LoginSignup
39
58

More than 5 years have passed since last update.

[WPF] DataGridのデザイン変更

Posted at

はじめに

せっかくWPFでアプリを作るなら、旧来のWin32を引きずったデザインではなく、モダンな見た目で作りたいなと思うわけです。
たとえそれが、しがない業務アプリだとしても・・・

neue ccさんのブログを参考に、Material Design In XAML Toolkitを入れてみると、確かにテンション上がります。
見た目が変わるだけで、素晴らしいアプリに見えてくる!
(全体のイメージは本家スクリーンショットを参照

ただ、DataGridだけは、カッコ良すぎるというか、業務アプリとしては使いづらいかなと思うわけで。
そんなDataGridのデザイン(Style)を、アレコレ悩んで 弄ったときの記録です。

環境

.NET Framework 4.6.1
MaterialDesignThemes 2.3.0.823
MahApps.Metro 1.5.0

素のフォーム

サンプルとして、TextBox, ComboBox, Button と DataGrid を並べたフォームを用意しました。
neue ccさん的に言う、実にギョーミーな画面。
グリッドのデータは、なんちゃって個人情報から拝借しました。

image

Material Design In XAML Toolkit導入

こいつに、Material Design In XAML Toolkit と、MahApps.Metro を適用します。
どちらもNuGetで入れました。

App.xaml にStyle定義を行い、Window は MahApps.Metro.Controls.MetroWindow を継承します。

App.xaml
<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:materialDesign="clr-namespace:MaterialDesignThemes.Wpf;assembly=MaterialDesignThemes.Wpf"
             xmlns:local="clr-namespace:WpfApplication1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>

            <ResourceDictionary.MergedDictionaries>

                <!-- MahApps -->
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />

                <!-- Material Design -->
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Indigo.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Red.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Button.xaml" />

            </ResourceDictionary.MergedDictionaries>

            <!-- MahApps Brushes -->
            <SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource Primary700}"/>
            <SolidColorBrush x:Key="AccentColorBrush" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="AccentColorBrush2" Color="{DynamicResource Primary400}"/>
            <SolidColorBrush x:Key="AccentColorBrush3" Color="{DynamicResource Primary300}"/>
            <SolidColorBrush x:Key="AccentColorBrush4" Color="{DynamicResource Primary200}"/>
            <SolidColorBrush x:Key="WindowTitleColorBrush" Color="{DynamicResource Primary700}"/>
            <SolidColorBrush x:Key="AccentSelectedColorBrush" Color="{DynamicResource Primary500Foreground}"/>
            <LinearGradientBrush x:Key="ProgressBrush" EndPoint="0.001,0.5" StartPoint="1.002,0.5">
                <GradientStop Color="{DynamicResource Primary700}" Offset="0"/>
                <GradientStop Color="{DynamicResource Primary300}" Offset="1"/>
            </LinearGradientBrush>
            <SolidColorBrush x:Key="CheckmarkFill" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="RightArrowFill" Color="{DynamicResource Primary500}"/>
            <SolidColorBrush x:Key="IdealForegroundColorBrush" Color="{DynamicResource Primary500Foreground}"/>
            <SolidColorBrush x:Key="IdealForegroundDisabledBrush" Color="{DynamicResource Primary500}" Opacity="0.4"/>

        </ResourceDictionary>
    </Application.Resources>
</Application>
MainWindow.xaml
<metro:MetroWindow x:Class="WpfApplication1.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"
                   mc:Ignorable="d"
                   xmlns:materialDesign="clr-namespace:MaterialDesignThemes.Wpf;assembly=MaterialDesignThemes.Wpf"
                   xmlns:metro="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
                   TextElement.Foreground="{DynamicResource MaterialDesignBody}"
                   TextElement.FontWeight="Regular"
                   TextElement.FontSize="13"
                   TextOptions.TextFormattingMode="Ideal" 
                   TextOptions.TextRenderingMode="Auto"        
                   Background="{DynamicResource MaterialDesignPaper}"
                   FontFamily="{StaticResource MaterialDesignFont}"                      
                   GlowBrush="{DynamicResource AccentColorBrush}"
                   ResizeMode="CanResizeWithGrip"
                   TitleCaps="False"
                   Title="MainWindow"
                   Height="500" Width="600"
                   Loaded="Window_Loaded">
MainWindow.xaml.cs
using System;
using System.Windows;
using MahApps.Metro.Controls;

namespace WpfApplication1
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

    }
}

こうして出来た画面がこちら

image

ガラリと雰囲気が変わりますな。
TextBoxやButtonなどはコレで良い感じだけど、DataGridは業務アプリとしては見づらい気がします。
ここだけをギョーミーにしたい。

なので、DataGridのStyleをデフォルトのもので継承し直す定義を、App.xamlに書いてみます。

App.xaml
    <Application.Resources>
        <ResourceDictionary>

           (略)

            <!--
                =======================================================
                [Style]DataGrid用スタイル再定義 ここから
                =======================================================
            -->
            <!-- DataGridColumnHeader(列ヘッダ) Style設定 -->
            <Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"/>

            <!-- DataGridCell(セル) Style設定 -->
            <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}"/>

            <!-- DataGrid Style設定 -->
            <Style TargetType="DataGrid" BasedOn="{StaticResource {x:Type DataGrid}}">
                <Setter Property="AutoGenerateColumns" Value="False"/>
                <Setter Property="CanUserAddRows" Value="False"/>
                <Setter Property="CanUserDeleteRows" Value="False"/>
            </Style>

            <!-- その他はデフォルト継承 -->
            <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}"/>
            <Style TargetType="DataGridRowHeader" BasedOn="{StaticResource {x:Type DataGridRowHeader}}" />
            <!--
                =======================================================
                [Style]DataGrid用スタイル再定義 ここまで
                =======================================================
            -->

        </ResourceDictionary>
    </Application.Resources>

こうすると、DataGrid だけが元の Win32 なスタイルに戻ります。

image

ただねぇ、このヘッダのデザインはいただけません。
せっかく他の部品がフラット・マテリアルな感じなのに、DataGrid ヘッダだけ、一昔前の3Dなグラデーションです。
すごく野暮ったく見えます。

なわけで、DataGrid個々のパーツのStyleにも手を入れていきます。
ソートマークの付与や、マウスオーバーの色変化、列幅変更のUIなど、機能はそのまま使えるようにして。

カスタムStyle適用

XAMLのStyle定義だけで試行錯誤した結果が、こちらになりました。

image

App.xaml
    <!--
        =======================================================
        [Style]DataGrid用スタイル再定義 ここから
        =======================================================
    -->
    <!-- 罫線の色 -->
    <Brush x:Key="DG_Brush_Border">#ffaaaaaa</Brush>
    <!-- 選択行の背景色 -->
    <Color x:Key="DG_Color_SelectedBackground">#337ab7</Color>
    <!-- マウスオーバー背景色 -->
    <Color x:Key="DG_Color_MouseOver">#dadada</Color>

    <!-- Thumb(列ヘッダ幅変更マウスカーソル) Style設定 -->
    <Style x:Key="columnHeaderGripperStyle" TargetType="{x:Type Thumb}">
        <Setter Property="Width" Value="8"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="Cursor" Value="SizeWE"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Thumb}">
                    <Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- DataGridColumnHeader(列ヘッダ) Style設定 -->
    <Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
        <Setter Property="SeparatorBrush" Value="LightGray" />
        <Setter Property="FontWeight" Value="Normal" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                    <Grid>
                        <!-- マウスオーバで色が変わる設定 -->
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="columnHeaderBorder"
                                                                      Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                            <EasingColorKeyFrame KeyTime="0" Value="#fafafa" />
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <!-- ヘッダ の外観 -->
                        <Border x:Name="columnHeaderBorder"
                                BorderThickness="0 0 1 1"
                                Padding="3 0 3 0"
                                BorderBrush="{StaticResource DG_Brush_Border}"
                                Background="#ffdddddd">

                            <Grid>
                                <!-- ソートマーク -->
                                <Path x:Name="sortArrow"
                                      HorizontalAlignment="Center"
                                      VerticalAlignment="Top"
                                      Width="8" Height="6" Margin="0 2 0 0"
                                      Stretch="Fill" Fill="DarkGray"
                                      RenderTransformOrigin="0.5 0.4"
                                      Visibility="Collapsed"
                                      Data="M0,0 L1,0 0.5,1 z" />
                                <!-- ヘッダ文字列 -->
                                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                            </Grid>
                        </Border>

                        <!-- サイズ変更グリップ -->
                        <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource columnHeaderGripperStyle}"/>
                        <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource columnHeaderGripperStyle}"/>
                    </Grid>

                    <!-- ソート trigger -->
                    <ControlTemplate.Triggers>
                        <Trigger Property="SortDirection" Value="Ascending">
                            <Setter TargetName="sortArrow" Property="Visibility" Value="Visible" />
                            <Setter TargetName="sortArrow" Property="RenderTransform">
                                <Setter.Value>
                                    <RotateTransform Angle="180" />
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="SortDirection" Value="Descending">
                            <Setter TargetName="sortArrow" Property="Visibility" Value="Visible" />
                        </Trigger>
                    </ControlTemplate.Triggers>

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

    <!-- DataGridCell(セル) Style設定 -->
    <Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
        <Setter Property="Height" Value="24"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Grid Background="{TemplateBinding Background}">
                        <ContentPresenter VerticalAlignment="Center" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- DataGrid Style設定 -->
    <Style TargetType="DataGrid" BasedOn="{StaticResource {x:Type DataGrid}}">
        <Setter Property="AutoGenerateColumns" Value="False"/>
        <Setter Property="CanUserAddRows" Value="False"/>
        <Setter Property="CanUserDeleteRows" Value="False"/>
        <Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"/>
        <Setter Property="BorderBrush" Value="{StaticResource DG_Brush_Border}"/>
        <Setter Property="BorderThickness" Value="1 1 1 1"/>
        <Setter Property="ColumnHeaderHeight" Value="35"/>
        <Setter Property="HeadersVisibility" Value="Column"/>
        <Setter Property="HorizontalGridLinesBrush" Value="{StaticResource DG_Brush_Border}"/>
        <Setter Property="VerticalGridLinesBrush" Value="{StaticResource DG_Brush_Border}"/>
        <Setter Property="VirtualizingPanel.IsVirtualizing" Value="True"/>
        <Setter Property="VirtualizingPanel.VirtualizationMode" Value="Standard"/>
        <Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
    </Style>

    <!-- その他はデフォルト継承 -->
    <Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}"/>
    <Style TargetType="DataGridRowHeader" BasedOn="{StaticResource {x:Type DataGridRowHeader}}" />
    <!--
        =======================================================
        [Style]DataGrid用スタイル再定義 ここまで
        =======================================================
    -->

なんかもう長すぎて、解らないところもあります。
多分余計な記述もあることでしょう。
ヘッダをフラットにして、罫線を細くするだけで、こんなに苦労するとは、思わなかったです。

まだ少し気に入らない部分もありますが、いちおうこれで完成と相成りました。

参考ページ

Material Design In XAML Toolkitでお手軽にWPFアプリを美しく
MaterialDesignInXamlToolkit - Getting Started

39
58
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
58