WPFでグリッド状に写真を並べる

写真などを扱うアプリケーションを作成していると、エクスプローラーにあるような選択可能な写真プレビュー画面が作りたくなることがあります。

f:id:laicos:20180115235613p:plain

これをWPFバインディング(ReactiveProperty)を使って実現します。

選択可能なリスト

ListViewを使います。ただし、要素は画像をグリッド状に並べたいので以下のカスタマイズをします。 またSelectionMode="Extended"を指定しておくとCTRL+クリックで複数選択可能になるような挙動になります。他にもSingle,Multipleが指定できます。

PhotosにはViewModelでImageSourceに当たるものを指定します。WPFのImageSourceは結構便利で画像のパス、URL、BitmapSourceなどを指定するだけで勝手に表示してくれます。

class Photo {
    public string Title { get; set; }
    public string Url{ get; set; }
}
<ListView ItemsSource="{Binding Photos}" SelectionMode="Extended" ScrollViewer.HorizontalScrollBarVisibility="Disabled"></ListView>

画像をグリッド状に並べる

WrapPanelを使います。ListView.ItemsPanelに指定することでListViewの親要素にすることができます。 また、横方向のスクロールを無効化しておくと、横幅に応じて画像配置の列数を変えてくれます。

<ListView ItemsSource="{Binding Photos}" SelectionMode="Extended" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>

子要素にUIを当てる

これはListView,ItemTemplateに指定します。ここさえ工夫すれば画像以外であっても任意のUIに割り当てることができます。 Bindingにはプロパティ名を入れると参照可能です

<ListView ItemsSource="{Binding Photos}" SelectionMode="Extended" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Width="300" Height="200">
                <Image Source="{Binding Title}"></Image>
                <TextBlock Text="{Binding Url}"></TextBlock>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

これでPhotosの内容によって画像グリッドを作成することができます。