web-dev-qa-db-ja.com

アイテムを水平に配置したWPF ListView?

リストモードのWinForms ListViewと同様の方法で、ListViewのアイテムをレイアウトします。つまり、ListViewでもアイテムが縦方向だけでなく横方向にも配置されます。

アイテムが次のようにレイアウトされていても構いません。

1 4 7
2 5 8
3 6 9

またはこのように:

1 2 3
4 5 6
7 8 9

使用可能なスペースを最大限に活用するために、垂直および水平の両方で表示される限り。

私が見つけた最も近いものはこの質問でした:

WPF ListViewアイテムを水平スクロールバーのように水平に繰り返すにはどうすればよいですか?

アイテムを水平方向にのみレイアウトします。

55
Grokys

あなたが探しているものは WrapPannel のように聞こえます。これは次のようにスペースがなくなるまでアイテムを水平に配置し、次の行に移動します:

[〜#〜] msdn [〜#〜]
alt text http://i.msdn.Microsoft.com/Cc295081.b1c415fb-9a32-4a18-aa0b-308fca994ac9(en-us,Expression.10).png

また、 niformGrid を使用することもできます。これは、設定された数の行または列にアイテムをレイアウトします。

ListView、ListBox、またはItemsControlの任意のフォームでこれらの他のパネルを使用してアイテムを範囲に取得する方法は、 ItemsPanel プロパティを変更することです。 ItemsPanelを設定すると、ItemsControlsで使用されるデフォルトのStackPanelから変更できます。 WrapPanelでは、幅を ここに表示 として設定する必要もあります。

<ListView>
   <ListView.ItemsPanel>
      <ItemsPanelTemplate>
         <WrapPanel Width="{Binding (FrameworkElement.ActualWidth), 
            RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
            ItemWidth="{Binding (ListView.View).ItemWidth, 
            RelativeSource={RelativeSource AncestorType=ListView}}"
            MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
            ItemHeight="{Binding (ListView.View).ItemHeight, 
            RelativeSource={RelativeSource AncestorType=ListView}}" />
      </ItemsPanelTemplate>
   </ListView.ItemsPanel>
...
</ListView>
100
rmoore

私は最近、WPFでこれを達成する方法を研究し、良い解決策を見つけました。私が望んでいたのは、Windowsエクスプローラーでリストモード、つまり上から下、次に左から右に複製することでした。

基本的に、あなたがしたいことは、ListBox.ItemsPanelプロパティをオーバーライドして、WrapPanelの向きをVerticalに設定して使用します。

<ListBox>
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>      
      <WrapPanel Orientation="Vertical"/>
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</ListBox>

ただし、この[〜#〜] [〜#〜]は、ラップパネルが仮想化されていないため、大きなデータセットを読み込むときに遅くなります。これは重要。したがって、VirtualizedPanelを拡張してIScrollInfoを実装することにより、独自のVirtualizedWrapPanelを記述する必要があるため、このタスクはもう少しなります。

public class VirtualizedWrapPanel : VirtualizedPanel, IScrollInfo
{
   // ...
}

これは、別のタスクに移る前に研究で得たものです。詳細や例が必要な場合は、コメントしてください。

[〜#〜] update [〜#〜]。 Ben Constableには素晴らしい IScrollInfoの実装方法に関するシリーズ があります。

全部で4つの記事があります。本当に良い読み物。

それ以来、仮想化されたラップパネルを実装しましたが、上記の一連の記事の助けを借りても簡単な作業ではありません。

21
Dennis

私の場合、最良のオプションは以下を使用することでした:

        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Vertical"
                    MaxHeight="{Binding (FrameworkElement.ActualHeight), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
                               ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}"
                               MinHeight="{Binding ItemHeight, RelativeSource={RelativeSource Self}}"
                               ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>

これにより、Windowsエクスプローラのリストオプションにかなり似たものが得られました。

8
Arsen Zahray

@Dennisの答えに加えて、WrapPanelが仮想化を失うことについて、これを正しく実装するNiceクラスを見つけました。 Ben Constableによる提案記事( Part 1Part 2パート3パート4 )は素晴らしい紹介です。ラップパネルのタスクを完全に完了します。

実装は次のとおりです: https://virtualwrappanel.codeplex.com/ 合計3.300のビデオと写真でテストし、リスト自体をロードしましたもちろん少し長いですが、最終的にはリストを正しく仮想化し、スクロールの遅れはまったくありません。

  • このコードにはいくつかの問題があります。上のページの問題タブをご覧ください。

プロジェクトにソースコードを追加した後、ソースコードの例:

   <!--in your <Window> or <UserControl> tag -->
  <UserControl
        xmlns:hw="clr-namespace:Project.Namespace.ToClassFile" >
   <!--...-->

    <ListView x:Name="lvImages" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Margin="10" Height="auto" 
             ItemsSource="{Binding ListImages}"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <hw:VirtualizingWrapPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Vertical" Margin="5" MaxHeight="150">
                    <TextBlock Text="{Binding title}" FontWeight="Bold"/>
                    <Image Source="{Binding path, IsAsync=True}" Height="100"/>
                    <TextBlock Text="{Binding createDate, StringFormat=dd-MM-yyyy}"/>

                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

MVVMスタイルのバックエンドなので、これはViewModel内にあります。

    public ObservableCollection<Media> ListImages
    {
        get
        {
            return listImages;
        }
        set { listImages = value; OnPropertyChanged(); }
    }


     //Just load the images however you do it, then assign it to above list.
//Below is the class defined that I have used.
public class Media
{
    private static int nextMediaId = 1;
    public int mediaId { get; }
    public string title { get; set; }
    public string path { get; set; }
    public DateTime createDate { get; set; }
    public bool isSelected { get; set; }

    public Media()
    {
        mediaId = nextMediaId;
        nextMediaId++;
    }
}
2
CularBytes

左から右、次に上から下に使用

      <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" 
                     MaxWidth="{Binding ActualWidth, Mode=OneWay, 
                       RelativeSource={RelativeSource FindAncestor, 
                       AncestorType={x:Type er:MainWindow}}}"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
2
kns98