🗿

[WPF/C#] ListViewの見た目(背景色とか、行選択時の色とか)をまるっと変えたい

2021/07/31に公開

もくじ

https://qiita.com/tera1707/items/4fda73d86eded283ec4f

やりたいこと

セルの中身をいじったりヘッダの中身をいじったりはできたが、
背景の色とか行選択時の行の色などもいじりたい。

イメージとしては、

before
ListView標準状態だとこうなるやつを

after
こうしたい

やり方

リストの各行の背景の色をいじるときに、

リストの行.Background = "Red"

みたいな感じで簡単にできないかな?と思っていたが、そういうすぐできそうなやり方は見つけられなかった。

いろいろ試したところ、
MSのサンプルのGridViewのstyle(ControlTemplateを含む)をコピーしてきて、それをいろいろ編集すればできた。
(本当はこの記事で試したような「デザイナ上でGridViewColumnHeaderの部分を右クリック→スタイルの編集→コピーして編集」をして、標準のテンプレートを取り出してそいつをいじる、というのをやりたかったのだが、それ(デザイナー上のListViewを右クリック)をしてみても、ListViewのstyleが出るだけでListViewItemなどのstyleが出てくれないので、MSのページからとってくるというやり方をした)

今回取ってきたMSのサンプルのstyleは下記にある。

https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/listview-styles-and-templates?view=netframeworkdesktop-4.8

下で試したコードの中の「Dictionary1.xaml」にその内容をまるっとコピーして使用した。
Dictionary1.xamlの中に、背景色にあたる部分やヘッダの色にあたる部分、行の選択時の背景色にあたる部分があるので、そこを探して編集すればいろいろわりと自由に見た目を変えることができる。

試したコード

画面のxaml

冒頭でディクショナリを呼んで、見た目を変えてる。

あと以前の記事で試した、ヘッダをカスタムするのと、セルの中身をカスタムするのも一緒にやっている。

MainWindow.xaml
<Window x:Class="ListViewTet.MainWindow"
        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"
        xmlns:local="clr-namespace:ListViewTet"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Dictionary1.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <ListView ItemsSource="{Binding DataList}">
            <ListView.View>
                <GridView>
                    <!-- ヘッダ:直接指定 -->
                    <!-- セル :DisplayMemberBindingで指定 -->
                    <GridViewColumn Header="No"  DisplayMemberBinding="{Binding No}" Width="30"/>

                    <!-- ヘッダ:GridViewColumnHeaderで指定 -->
                    <!-- セル :DisplayMemberBindingで指定 -->
                    <GridViewColumn DisplayMemberBinding="{Binding Name}" Width="100">
                        <GridViewColumn.Header>
                            <StackPanel Orientation="Horizontal">
                                <Ellipse Stroke="Red" StrokeThickness="1" Width="10" Height="10" />
                                <TextBlock Text=" ヘッダの文言"/>
                            </StackPanel>
                        </GridViewColumn.Header>
                    </GridViewColumn>

                    <!-- ヘッダ:GridViewColumnHeaderで指定 -->
                    <!-- セル :CellTemplateで指定 -->
                    <!-- ヘッダ/セルの両方をカスタムするパターン -->
                    <GridViewColumn Width="100">
                        <GridViewColumn.Header>
                            <GridViewColumnHeader Content="Color"/>
                        </GridViewColumn.Header>
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Brush}" />
                                    <Rectangle Fill="{Binding Brush}" Width="10" Height="10"/>
                                </StackPanel>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

コードビハインド

試しに表示したいデータを詰め込んでるだけ。

MainWindow.xaml.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;

namespace ListViewTet
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName) => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        #endregion

        public ObservableCollection<MyData> DataList { get; set; } = new ObservableCollection<MyData>();

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            DataList.Add(new MyData() { No = 1, Brush = new SolidColorBrush(Colors.Red), Name = "Red" });
            DataList.Add(new MyData() { No = 2, Brush = new SolidColorBrush(Colors.Blue), Name = "Blue" });
            DataList.Add(new MyData() { No = 3, Brush = new SolidColorBrush(Colors.Green), Name = "Green" });
        }
    }

    public class MyData
    {
        public int No { get; set; }
        public SolidColorBrush Brush { get; set; }
        public string Name { get; set; }
    }
}

ディクショナリ

MSのサンプルをそのまま使っている。
こいつをいろいろいじれば、見た目カスタムできる。

https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/listview-styles-and-templates?view=netframeworkdesktop-4.8

Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:ListViewTet">
    <!-- MSのサンプルのstyleをそのまま持ってきた部分 -->
    <!-- https://docs.microsoft.com/ja-jp/dotnet/desktop/wpf/controls/listview-styles-and-templates?view=netframeworkdesktop-4.8 -->
        
    <!--Control colors.-->
    <Color x:Key="WindowColor">#FFE8EDF9</Color>
    <Color x:Key="ContentAreaColorLight">#FFC5CBF9</Color>
    <Color x:Key="ContentAreaColorDark">#FF7381F9</Color>

    <Color x:Key="DisabledControlLightColor">#FFE8EDF9</Color>
    <Color x:Key="DisabledControlDarkColor">#FFC5CBF9</Color>
    <Color x:Key="DisabledForegroundColor">#FF888888</Color>

    <Color x:Key="SelectedBackgroundColor">#FFC5CBF9</Color>
    <Color x:Key="SelectedUnfocusedColor">#FFDDDDDD</Color>

    <Color x:Key="ControlLightColor">White</Color>
    <Color x:Key="ControlMediumColor">#FF7381F9</Color>
    <Color x:Key="ControlDarkColor">#FF211AA9</Color>

    <Color x:Key="ControlMouseOverColor">#FF3843C4</Color>
    <Color x:Key="ControlPressedColor">#FF211AA9</Color>


    <Color x:Key="GlyphColor">#FF444444</Color>
    <Color x:Key="GlyphMouseOver">sc#1, 0.004391443, 0.002428215, 0.242281124</Color>

    <!--Border colors-->
    <Color x:Key="BorderLightColor">#FFCCCCCC</Color>
    <Color x:Key="BorderMediumColor">#FF888888</Color>
    <Color x:Key="BorderDarkColor">#FF444444</Color>

    <Color x:Key="PressedBorderLightColor">#FF888888</Color>
    <Color x:Key="PressedBorderDarkColor">#FF444444</Color>

    <Color x:Key="DisabledBorderLightColor">#FFAAAAAA</Color>
    <Color x:Key="DisabledBorderDarkColor">#FF888888</Color>

    <Color x:Key="DefaultBorderBrushDarkColor">Black</Color>

    <!--Control-specific resources.-->
    <Color x:Key="HeaderTopColor">#FFC5CBF9</Color>
    <Color x:Key="DatagridCurrentCellBorderColor">Black</Color>
    <Color x:Key="SliderTrackDarkColor">#FFC5CBF9</Color>

    <Color x:Key="NavButtonFrameColor">#FF3843C4</Color>

    <LinearGradientBrush x:Key="MenuPopupBrush"
                     EndPoint="0.5,1"
                     StartPoint="0.5,0">
        <GradientStop Color="{DynamicResource ControlLightColor}"
                Offset="0" />
        <GradientStop Color="{DynamicResource ControlMediumColor}"
                Offset="0.5" />
        <GradientStop Color="{DynamicResource ControlLightColor}"
                Offset="1" />
    </LinearGradientBrush>

    <LinearGradientBrush x:Key="ProgressBarIndicatorAnimatedFill"
                     StartPoint="0,0"
                     EndPoint="1,0">
        <LinearGradientBrush.GradientStops>
            <GradientStopCollection>
                <GradientStop Color="#000000FF"
                    Offset="0" />
                <GradientStop Color="#600000FF"
                    Offset="0.4" />
                <GradientStop Color="#600000FF"
                    Offset="0.6" />
                <GradientStop Color="#000000FF"
                    Offset="1" />
            </GradientStopCollection>
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>

    <Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}"
       TargetType="ScrollViewer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ScrollViewer">
                    <Grid Background="{TemplateBinding Background}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                            <ColumnDefinition Width="Auto" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>

                        <DockPanel Margin="{TemplateBinding Padding}">
                            <ScrollViewer DockPanel.Dock="Top"
                          HorizontalScrollBarVisibility="Hidden"
                          VerticalScrollBarVisibility="Hidden"
                          Focusable="false">
                                <GridViewHeaderRowPresenter Margin="2,0,2,0"
                                          Columns="{Binding Path=TemplatedParent.View.Columns,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          ColumnHeaderContainerStyle="{Binding
                Path=TemplatedParent.View.ColumnHeaderContainerStyle,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          ColumnHeaderTemplate="{Binding
                Path=TemplatedParent.View.ColumnHeaderTemplate,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          ColumnHeaderTemplateSelector="{Binding 
                Path=TemplatedParent.View.ColumnHeaderTemplateSelector,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          AllowsColumnReorder="{Binding
                Path=TemplatedParent.View.AllowsColumnReorder,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          ColumnHeaderContextMenu="{Binding
                Path=TemplatedParent.View.ColumnHeaderContextMenu,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          ColumnHeaderToolTip="{Binding
                Path=TemplatedParent.View.ColumnHeaderToolTip,
                RelativeSource={RelativeSource TemplatedParent}}"
                                          SnapsToDevicePixels="{TemplateBinding
                SnapsToDevicePixels}" />
                            </ScrollViewer>

                            <ScrollContentPresenter Name="PART_ScrollContentPresenter"
                                    KeyboardNavigation.DirectionalNavigation="Local"
                                    CanContentScroll="True"
                                    CanHorizontallyScroll="False"
                                    CanVerticallyScroll="False" />
                        </DockPanel>

                        <ScrollBar Name="PART_HorizontalScrollBar"
                     Orientation="Horizontal"
                     Grid.Row="1"
                     Maximum="{TemplateBinding ScrollableWidth}"
                     ViewportSize="{TemplateBinding ViewportWidth}"
                     Value="{TemplateBinding HorizontalOffset}"
                     Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />

                        <ScrollBar Name="PART_VerticalScrollBar"
                     Grid.Column="1"
                     Maximum="{TemplateBinding ScrollableHeight}"
                     ViewportSize="{TemplateBinding ViewportHeight}"
                     Value="{TemplateBinding VerticalOffset}"
                     Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />

                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="GridViewColumnHeaderGripper"
       TargetType="Thumb">
        <Setter Property="Width"
          Value="18" />
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,0"
                           EndPoint="0,1">
                    <LinearGradientBrush.GradientStops>
                        <GradientStopCollection>
                            <GradientStop Color="{DynamicResource BorderLightColor}"
                          Offset="0.0" />
                            <GradientStop Color="{DynamicResource BorderDarkColor}"
                          Offset="1.0" />
                        </GradientStopCollection>
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Border Padding="{TemplateBinding Padding}"
                Background="Transparent">
                        <Rectangle HorizontalAlignment="Center"
                     Width="1"
                     Fill="{TemplateBinding Background}" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderBrush">
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1"
                           StartPoint="0.5,0">
                    <GradientStop Color="Black"
                      Offset="0" />
                    <GradientStop Color="White"
                      Offset="1" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="{x:Type GridViewColumnHeader}"
       TargetType="GridViewColumnHeader">
        <Setter Property="HorizontalContentAlignment"
          Value="Center" />
        <Setter Property="VerticalContentAlignment"
          Value="Center" />
        <Setter Property="Foreground"
          Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="GridViewColumnHeader">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).
                    (GradientBrush.GradientStops)[1].(GradientStop.Color)"
                                                Storyboard.TargetName="HeaderBorder">
                                            <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed" />
                                <VisualState x:Name="Disabled" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="HeaderBorder"
                  BorderThickness="0,1,0,1"
                  Padding="2,0,2,0">
                            <Border.BorderBrush>
                                <LinearGradientBrush StartPoint="0,0"
                                   EndPoint="0,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStopCollection>
                                            <GradientStop Color="{DynamicResource BorderLightColor}"
                                  Offset="0.0" />
                                            <GradientStop Color="{DynamicResource BorderDarkColor}"
                                  Offset="1.0" />
                                        </GradientStopCollection>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>

                            </Border.BorderBrush>
                            <Border.Background>

                                <LinearGradientBrush StartPoint="0,0"
                                   EndPoint="0,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStopCollection>
                                            <GradientStop Color="{DynamicResource ControlLightColor}"
                                  Offset="0.0" />
                                            <GradientStop Color="{DynamicResource ControlMediumColor}"
                                  Offset="1.0" />
                                        </GradientStopCollection>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>

                            </Border.Background>
                            <ContentPresenter x:Name="HeaderContent"
                              Margin="0,0,0,1"
                              RecognizesAccessKey="True"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Border>
                        <Thumb x:Name="PART_HeaderGripper"
                 HorizontalAlignment="Right"
                 Margin="0,0,-9,0"
                 Style="{StaticResource GridViewColumnHeaderGripper}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="Role"
             Value="Floating">
                <Setter Property="Opacity"
              Value="0.7" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="GridViewColumnHeader">
                            <Canvas Name="PART_FloatingHeaderCanvas">
                                <Rectangle Fill="#60000000"
                         Width="{TemplateBinding ActualWidth}"
                         Height="{TemplateBinding ActualHeight}" />
                            </Canvas>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="Role"
             Value="Padding">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="GridViewColumnHeader">
                            <Border Name="HeaderBorder"
                    BorderThickness="0,1,0,1">
                                <Border.Background>
                                    <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
                                </Border.Background>
                                <Border.BorderBrush>
                                    <LinearGradientBrush StartPoint="0,0"
                                     EndPoint="0,1">
                                        <LinearGradientBrush.GradientStops>
                                            <GradientStopCollection>
                                                <GradientStop Color="{DynamicResource BorderLightColor}"
                                    Offset="0.0" />
                                                <GradientStop Color="{DynamicResource BorderDarkColor}"
                                    Offset="1.0" />
                                            </GradientStopCollection>
                                        </LinearGradientBrush.GradientStops>
                                    </LinearGradientBrush>
                                </Border.BorderBrush>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

    <Style x:Key="{x:Type ListView}"
       TargetType="ListView">
        <Setter Property="SnapsToDevicePixels"
          Value="true" />
        <Setter Property="OverridesDefaultStyle"
          Value="true" />
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
          Value="Auto" />
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
          Value="Auto" />
        <Setter Property="ScrollViewer.CanContentScroll"
          Value="true" />
        <Setter Property="VerticalContentAlignment"
          Value="Center" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListView">
                    <Border Name="Border"
                BorderThickness="1">
                        <Border.Background>
                            <SolidColorBrush Color="{StaticResource ControlLightColor}" />
                        </Border.Background>
                        <Border.BorderBrush>
                            <SolidColorBrush Color="{StaticResource BorderMediumColor}" />
                        </Border.BorderBrush>
                        <ScrollViewer Style="{DynamicResource
                        {x:Static GridView.GridViewScrollViewerStyleKey}}">
                            <ItemsPresenter />
                        </ScrollViewer>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsGrouping"
                   Value="true">
                            <Setter Property="ScrollViewer.CanContentScroll"
                    Value="false" />
                        </Trigger>
                        <Trigger Property="IsEnabled"
                   Value="false">
                            <Setter TargetName="Border"
                    Property="Background">
                                <Setter.Value>
                                    <SolidColorBrush Color="{DynamicResource DisabledBorderLightColor}" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="{x:Type ListViewItem}"
       TargetType="ListViewItem">
        <Setter Property="SnapsToDevicePixels"
          Value="true" />
        <Setter Property="OverridesDefaultStyle"
          Value="true" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Border x:Name="Border"
                Padding="2"
                SnapsToDevicePixels="true"
                Background="Transparent">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver" />
                                <VisualState x:Name="Disabled" />
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="SelectionStates">
                                <VisualState x:Name="Unselected" />
                                <VisualState x:Name="Selected">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                                            <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource SelectedBackgroundColor}" />
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="SelectedUnfocused">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                                            <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource SelectedUnfocusedColor}" />
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <GridViewRowPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Discussion