WPF : ListView コントロール

 

 

 

1. Simple な ListView

極力 Blendを使って ListView を使ったシンプルなアプリを作ってみます。
こんな画面のプログラムを作ります。

作成するアプリ画面

 

(1) まずはWPFのプロジェクトを新規作成します。

WPFプロジェクトを新規作成

 

(2) ListViewコントロールを全面にして貼り付けます。

ListView コントロールを張り付け

 

(3) サンプルデータを作ります。ここでは Name と Address の2つの文字列データをサンプルデータとして作成します。

サンプルデータ作成

 

4) このサンプルデータを Grid の DataContext にバインドします。

ここでは”StaticResource”から”SampleDataSource”を選択します。

DataBinding 設定

 

(5) 次に ListView の ItemsSource へ 先に設定した SampleDataSource の Collection を設定します。

DataBinding 設定

 

(6) 続けて、ListView の GridViewColumn の設定を行います。

ここでは、”Name” と ”Address” の2つの列を作成してみます。

GridViewColumn 設定

GridViewColumn 設定

各 DisplayMemberBinding は ”データコンテキスト” の対応するアイテムを選択します。
DisplayMemberBinding 設定

以上で完成です。

 

(7) 動かしてみよう

[F5]でプログラムを動かしてみます。こんな感じです。

作成したプログラム画面

この時点の XAML は以下の通り。動いてしまえば簡単ですね。

[MainWindow.xaml]
<Window x:Class="ListViewSimple_2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid DataContext="{Binding Mode=OneWay, Source={StaticResource SampleDataSource}}">
        <ListView ItemsSource="{Binding Collection}">
            <ListView.View>
                <GridView>
                   <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                   <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Address}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

 

 

2. ヘッダの文字列を左寄せにする(HorizontalContentAlignment を設定する)

先ほど作ったプログラムの実行画面を見てみましょう。ヘッダ部分だけ中央に寄っています。
ヘッダの部分も左寄せにしてみたいですね。というわけで、ヘッダ部分も文字を左寄せにしてみます。
実は、少々面倒です。Blendでは設定できませんでした。XAMLの直接修正で実現します。

修正前のプログラム画面

[MainWindow.xaml]
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" x:Class="ListViewSimple.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Grid DataContext="{Binding Mode=oneway, Source={StaticResource SampleDataSource}}">
        <ListView ItemsSource="{Binding Collection}">
            <ListView.View>
                <GridView>
                    <!--
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                    -->
                    <GridViewColumn DisplayMemberBinding="{Binding Name}">
                        <GridViewColumn.Header>
                            <GridViewColumnHeader Content="Name" HorizontalContentAlignment="Left"/>
                        </GridViewColumn.Header>
                    </GridViewColumn>
                    <!--
                    <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Address}"/>
                    -->
                    <GridViewColumn DisplayMemberBinding="{Binding Address}">
                        <GridViewColumn.Header>
                            <GridViewColumnHeader Content="Address" HorizontalContentAlignment="Left"/>
                        </GridViewColumn.Header>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

修正したXAMLでコンパイルしたプログラムの実行結果は下記の通りです。
ちゃんと左寄せ(Left)になりました。同様に Right を設定すれば右寄せにもできます。

修正後のプログラム画面

 

 

3. イメージを表示する

1行目にイメージを表示するように変更します。

まず最初にすることは画像データをSampleDataに加えることです。
Images という名称で下記のようにサンプルに加えました。

サンプル作成

作成したプログラムは下記の通り。

作成したプログラム画面

作成したXAMLは下記の通り。
StackPanel は無くても良いのですが、後述の説明の都合で入れてあります。

[MainWindow.xaml]
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" x:Class="ListViewSimple.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Grid DataContext="{Binding Mode=oneway, Source={StaticResource SampleDataSource}}">
        <ListView ItemsSource="{Binding Collection}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Images">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel>
                                    <Image Source="{Binding Path=Images}" Width="64"></Image>
                                </StackPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                    <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Address}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

 

 

4.Image と TextBlock を一緒に表示する

1行目に表示していたイメージと、2行目に表示していた名前、の2つを1つのセルに融合して表示します。

作成するプログラム画面

[MainWindow.xaml]
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" x:Class="ListViewSimple.MainWindow"
        Title="MainWindow" Height="350" Width="525">
    <Grid DataContext="{Binding Mode=oneway, Source={StaticResource SampleDataSource}}">
        <ListView ItemsSource="{Binding Collection}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel>
                                    <Image Source="{Binding Path=Images}" Width="64"></Image>
                                    <TextBlock Text="{Binding Path=Name}"/>
                                </StackPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Address}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

 

 

5.タイル表示する

だんだん難しくなってきます。
ここでは、 ListView を使って下図のようなタイル表示を行う方法を記載します。

「Pro WPF 4.5 in C#」の本で、Chapter 22 にて"Creating a Custum View"として紹介されている内容です。
ほとんど本に記載のままですが、若干独自の処理を加えています。

作成するプログラム画面

(1) まず、次の2つのソースファイル(TileView.cs、Generic.xaml)をプロジェクトへ追加します。

[TileView.cs]
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace  ListViewStyle
{
    public class TileView : ViewBase
    {
        private DataTemplate itemTemplate;
        public DataTemplate ItemTemplate
        {
            get { return itemTemplate; }
            set { itemTemplate = value; }
        }

        private Brush selectedBackground = Brushes.Transparent;
        public Brush SelectedBackground
        {
            get { return selectedBackground; }
            set { selectedBackground = value; }
        }

        private Brush selectedBorderBrush = Brushes.Black;
        public Brush SelectedBorderBrush
        {
            get { return selectedBorderBrush; }
            set { selectedBorderBrush = value; }
        }

        private int selectedBorderThickness = 1;
        public int SelectedBorderThickness
        {
            get { return selectedBorderThickness; }
            set { selectedBorderThickness = value; }
        }

        private int selectedCornerRadius = 3;
        public int SelectedCornerRadius
        {
            get { return selectedCornerRadius; }
            set { selectedCornerRadius = value; }
        }

        protected override object DefaultStyleKey
        {
            get { return new ComponentResourceKey(GetType(), "TileView"); }
        }

        protected override object ItemContainerDefaultStyleKey
        {
            get { return new ComponentResourceKey(GetType(), "TileViewItem"); }
        }       
    }
}

 

[Themes / Generic.xaml]
[重要1] ”Generic.xaml” のファイルは必ず”Themes”フォルダの下に保存してください。詳細は不明。
[重要2] ”Generic.xaml” の "ビルドアクション" を "Page" にすること。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ListViewStyle">
    
  <Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:TileView},
         ResourceId=TileView}"
         TargetType="{x:Type ListView}" BasedOn="{StaticResource {x:Type ListBox}}">
    <Setter Property="BorderBrush" Value="Black"></Setter>
    <Setter Property="BorderThickness" Value="0.5"></Setter>
    <Setter Property="Grid.IsSharedSizeScope" Value="True"></Setter>

    <Setter Property="ItemsPanel">
      <Setter.Value>
        <ItemsPanelTemplate>
          <WrapPanel Width="{Binding (FrameworkElement.ActualWidth),
            RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
          ></WrapPanel>
        </ItemsPanelTemplate>
      </Setter.Value>
    </Setter>
  </Style>

  <Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type local:TileView},
         ResourceId=TileViewItem}"
         TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
    <Setter Property="Padding" Value="3"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
    <Setter Property="ContentTemplate" Value="{Binding Path=View.ItemTemplate,
            RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}"></Setter>

    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type ListBoxItem}">
<!-- 値を直接指定する場合はこんな感じで
          <Border Name="Border" BorderThickness="1" CornerRadius="3" >
-->
          <Border Name="Border"
            BorderThickness="{Binding Path=View.SelectedBorderThickness,
            RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}"
            CornerRadius="{Binding Path=View.SelectedCornerRadius,
            RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}">
              <ContentPresenter />
          </Border>
          <ControlTemplate.Triggers>            
            <Trigger Property="IsSelected" Value="True">
                <Setter TargetName="Border" Property="BorderBrush"
                    Value="{Binding Path=View.SelectedBorderBrush,
                    RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}"></Setter>
                <Setter TargetName="Border" Property="Background"
                    Value="{Binding Path=View.SelectedBackground,
                    RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}}"></Setter>
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

 

ビルドアクションを Page にする
図: "Generic.xaml" のビルドアクション

 

(2) 次に MainWindow.xaml を以下のように修正します。

[MainWindow.xaml]
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" x:Class="ListViewSimple.MainWindow"
        xmlns:local="clr-namespace:ListViewStyle"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <local:TileView x:Key="ImageView" SelectedBackground="LightSteelBlue" SelectedBorderBrush="BlueViolet" SelectedBorderThickness="5" SelectedCornerRadius="10">
            <local:TileView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Width="128" VerticalAlignment="Top">
                        <Image Source="{Binding Path=Images}"></Image>
                        <TextBlock TextWrapping="Wrap" HorizontalAlignment="Center"  Text="{Binding Path=Name}" ></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </local:TileView.ItemTemplate>
        </local:TileView>

        <local:TileView x:Key="ImageDetailView" SelectedBackground="LightSteelBlue">
            <local:TileView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="Auto" SharedSizeGroup="Col2"></ColumnDefinition>
                        </Grid.ColumnDefinitions>
            
                        <Image Margin="5" Grid.Column="0"  Width="100" Source="{Binding Path=Images}"></Image>
                        <StackPanel Grid.Column="1" VerticalAlignment="Center">
                            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}"></TextBlock>
                            <TextBlock Text="{Binding Path=Address}"></TextBlock>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </local:TileView.ItemTemplate>
        </local:TileView>

        <GridView x:Key="GridView">
            <GridView.Columns>
                <GridViewColumn Header="Name">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <Image Source="{Binding Path=Images}" Width="64"></Image>
                                <TextBlock Text="{Binding Path=Name}"/>
                            </StackPanel>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>                      
                </GridViewColumn>
                <GridViewColumn Header="Address" DisplayMemberBinding="{Binding Address}"/>
            </GridView.Columns>
        </GridView>
    </Window.Resources>

    <Grid DataContext="{Binding Mode=oneway, Source={StaticResource SampleDataSource}}">
        <ListView View="{StaticResource ImageView}" ItemsSource="{Binding Collection}" BorderBrush="Black" BorderThickness="0.5" Foreground="Black"/>
    </Grid>
</Window>

 

このまま実行すると、下図のようになります。

作成したプログラム画面

 

「View="{StaticResource ImageView}"」 を「View="{StaticResource ImageDetailView}"」へ変えると、下図の通り。

ImageDetailView 表示

「View="{StaticResource ImageView}"」 を「View="{StaticResource GridView}"」へ変えると、下図の通り。

GridView 表示

これらをベースにして微修正していけば、多くのバリエーションに対応できそうです。

アイテム選択時のセルの色や枠の太さ、角、色、などのカスタマイズは、上記ソース中の水色部分を参考に修正を行ってください。

 

 

6.GridView のスタイルをカスタマイズ

”GridView” のスタイルをカスタマイズしたい場合は、下記のような感じでスタイル指定にて。

[MainWindow.xaml]
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="ListViewSimple_2.MainWindow"
        xmlns:local="clr-namespace:ListViewSimple_2"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <local:TileView x:Key="ImageView" SelectedBorderBrush="BlueViolet" SelectedBorderThickness="5" SelectedCornerRadius="10">
            <local:TileView.SelectedBackground>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF1B6576" Offset="1"/>
                    <GradientStop Color="White"/>
                    <GradientStop Color="#FF9FD2DE" Offset="0.237"/>
                </LinearGradientBrush>
            </local:TileView.SelectedBackground>
            
            <local:TileView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Width="128" VerticalAlignment="Top">
                        <Image Source="{Binding Path=Images}"></Image>
                        <TextBlock TextWrapping="Wrap" HorizontalAlignment="Center"  Text="{Binding Path=Name}" ></TextBlock>
                    </StackPanel>
                </DataTemplate>
            </local:TileView.ItemTemplate>
        </local:TileView>

        <local:TileView x:Key="ImageDetailView" SelectedBackground="LightSteelBlue">
            <local:TileView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="Auto" SharedSizeGroup="Col2"></ColumnDefinition>
                        </Grid.ColumnDefinitions>
            
                        <Image Margin="5" Grid.Column="0"  Width="100" Source="{Binding Path=Images}"></Image>
                        <StackPanel Grid.Column="1" VerticalAlignment="Center">
                            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}"></TextBlock>
                            <TextBlock Text="{Binding Path=Address}"></TextBlock>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </local:TileView.ItemTemplate>
        </local:TileView>

        <GridView x:Key="GridView">
            <GridView.Columns>
                <GridViewColumn Header="Name">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <Image Source="{Binding Path=Images}" Width="64"></Image>
                                <TextBlock Text="{Binding Path=Name}" TextWrapping="Wrap"/>
                            </StackPanel>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>                      
                </GridViewColumn>
                <GridViewColumn Header="Address">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Path=Address}" TextWrapping="Wrap"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView.Columns>
        </GridView>

        <Style x:Key="MyStyle" TargetType="ListViewItem">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="Bisque"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        
    </Window.Resources>

    <Grid DataContext="{Binding Mode=oneway, Source={StaticResource SampleDataSource}}">
        <ListView ItemContainerStyle="{StaticResource MyStyle}" ItemsSource="{Binding Collection}" View="{StaticResource GridView}" BorderBrush="Black" BorderThickness="0.5" Foreground="Black" Background="White"/>
    </Grid>
</Window>

 

選択時のセルの色を変えられました。

選択セルの背景色を変更

 

 

ライセンス

本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。

The MIT License (MIT)

  Copyright 2014 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 


参考

 


 

変更履歴

2023-05-31 - ページデザイン更新
2018-09-08 - "Generic.xaml" のビルドアクションに関する記述を追記
2014-09-08 - 新規作成

 

Programming Items トップページ

プライバシーポリシー