mogmo .NET

C#/XAML/VB6たまにC++についてメモ程度に書いていく。あくまで自分用。責任は取れません。

コントロールテンプレートを使ってみる

リソースディクショナリに何度も使うWindowのスタイルを定義する。

スタイルを書いていくリソースディクショナリの作成

コントロールテンプレートをリソースディクショナリに書いていくことにしたので,ファイルを作成。
f:id:mogmo811:20180927111518p:plain

こういうコントロールテンプレートが今後増えていくと見越して,テンプレートファイルを踏襲するためのテンプレートファイル"Templates.xaml"を作成した。
f:id:mogmo811:20180927111706p:plain

中身はこんな感じ。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/Template/DisplaySettingsWindowTemplate.xaml"/>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

クライアント側でどう使うか

スタイルの読み込み

App.xamlにスタイル読み込み処理を記述。
アプリ起動時に読み込んでしまうようにした。

<Application x:Class="***.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:StandardWindow"
             StartupUri="MainWindow.xaml">
    <!--アプリケーションで使うスタイルを読み込んでます-->
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/***;component/Theme/LightColor.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/***;component/Styles/Windows.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/***;component/Styles/Controls.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/Template/Templates.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

スタイルの適用方法

コントロールのStyleプロパティに適用してあげるだけで完成。
以下はウィンドウの場合の例。

<Window x:Class="StandardWindow.***"
        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:StandardWindow.***"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance {x:Type viewmodel:***ViewModel}, IsDesignTimeCreatable=True}"
        Style="{Binding Source={StaticResource ***Style}}"
        Title="***" Height="450" Width="800">

どのコントロールに適用するのかを指定する

TargetTypeプロパティで、どの型にスタイルを適用するのかを指定する。
今回はWindowが対象だ。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:StandardWindow.Template">

    <BooleanToVisibilityConverter x:Key="boolToVisibilityConverter" />

    <Style x:Key="DisplaySettingsWindow" TargetType="{x:Type Window}">
    </Style>

</ResourceDictionary>

Metroライクな画面を作る

従来のウィンドウ枠じゃダサい...ということでWindowChromeクラスの出番。
Visual Studioのような,フラットなウィンドウ枠にできる。
ResizeBorderThicknessにはシステム設定値を使用した。

        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome
                    CaptionHeight="30"
                    ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}"/>
            </Setter.Value>
        </Setter>

コントロールの外観を定義する

コントロールのTemplateプロパティを設定して UI でのコントロールの外観を定義する。
コントロールとして動作するために必ず必要な構成要素があるので,以下のサイトでテンプレートを確認すること。
コントロールのスタイルとテンプレート | Microsoft Docs

        <!--外観設定-->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Border>
                        <Grid>
                            ...
                        </Grid>                        
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

最大化等の処理をする

ControlTemplateのTriggerクラスで行う。
WindowStateの状態はNomal, Maximized, Minimizedの3種類あり,この状態の変化をトリガとしてMarginを変更する。

        <!--外観設定-->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Border>
                        ...
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="WindowState" Value="Maximized">
                            <Setter TargetName="WindowFrame" Property="Margin" Value="8"/>
                        </Trigger>
                        <Trigger Property="WindowState" Value="Normal">
                            <Setter TargetName="WindowFrame"  Property="Margin" Value="0" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>