もくじ
■やりたいこと
画面の部品の見た目や挙動をStyleを使って変えたいなと思ったときに、いまだにどこにどう書くんだったか、と迷う。
しかもなぜか、以前に調べたことを毎回結構忘れていて時間を取られるので、一度テンプレート的なものを持っておきたい。
■Styleを書く場所
直接Styleを書く
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Grid>
<Rectangle x:Name="chk" Margin="50" Stroke="Black" >
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="GreenYellow"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Fill" Value="RosyBrown"/>
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Grid>
</Window>
<Window.Resources>
にStyleを書く(Keyなし)
Resourcesの中にキー名なしでTargetTypeを指定してstyleを書くと、画面に配置されている指定したTypeのものが全部そのstyleの見た目になる。
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<Style TargetType="Rectangle">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="GreenYellow"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Fill" Value="RosyBrown"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<Rectangle Margin="5" Height="50" Width="50" Stroke="Black" />
<Rectangle Margin="5" Height="50" Width="50" Stroke="Black" />
</StackPanel>
</Grid>
</Window>
<Window.Resources>
にStyleを書く(Keyあり)
Resourcesの中にキー名あり(<Style x:Key="xxxx"
のところ)でStyleを書くと、画面上にあるkey名を指定したものだけ、その見た目になる。
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<Style x:Key="RectStyle" TargetType="Rectangle">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="GreenYellow"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Fill" Value="RosyBrown"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<Rectangle Style="{DynamicResource RectStyle}" Margin="5" Height="50" Width="50" Stroke="Black" />
<Rectangle Margin="5" Height="50" Width="50" Stroke="Black" />
</StackPanel>
</Grid>
</Window>
※注意
同じTargetTypeのStyleでkey名のあるもの、ないもの両方あるときも、Styleに"{DynamicResource key名}"を指定したものだけその見た目になる
ResourceDictionary.xamlにStyleを書く
以前の記事を参照。
■できること
自分自身のプロパティの値に応じて見た目を変える
これを**「プロパティトリガー」**という。
自分のプロパティの値に応じて、自分の見た目にかかわるプロパティの値を変える、ということ。
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="GreenYellow"/>
</Trigger>
※上の「書く場所」に挙げたサンプルにある内容。
ViewModel等のプロパティの値に応じて見た目を変える
これを**「データトリガー」**という。
詳細は以前の記事を参照。
下記のような感じ。
<!-- ViewModelが持ってるプロパティColorChangeFlagにバインドしてる -->
<DataTrigger Binding="{Binding ColorChangeFlag}" Value="true">
<Setter Property="Fill" Value="Blue"/>
</DataTrigger>
Styleの中でTemplateを変更する
できること、というよりは、こういう書き方もできる、という感じ。
各コントロールの標準のテンプレートを出すと、よく見る書かれ方。
下は、CheckBoxのデフォルトのStyleをまともに動かないくらい簡略化したものを、
リソースにControlTemplateを書いてkey指定してつかうものと、styleに直接書くものをやってみたコード。
やる機会はあまりないと思うが、これをやれば、プロパティの値によってTemplateを変えることができる、イコール見た目をガラッと変えることもできる。(むしろそんなことはしてはいけないかもしれない)
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="200">
<Window.Resources>
<!-- テンプレートをリソースとして書く -->
<ControlTemplate x:Key="type1" TargetType="{x:Type CheckBox}">
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="checkBoxBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid">
<TextBlock Text="1"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
<!-- チェックボックスのスタイル本体 -->
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<!-- ★styleの中でTemplateを指定(Resourceに書いたやつをDynamicResourceで指定) -->
<Setter Property="Template" Value="{DynamicResource type1}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<!-- ★styleの中でTemplateを指定(ここに直接書く)(デフォのStyleでよくこの書き方で書かれてるので、こっちが基本っぽい) -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid x:Name="templateRoot" Background="Transparent" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="checkBoxBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<Grid x:Name="markGrid">
<TextBlock Text="2"/>
</Grid>
</Border>
<ContentPresenter x:Name="contentPresenter" Grid.Column="1" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<!-- 画面本体 -->
<Grid>
<CheckBox Content="チェックボックス" Style="{DynamicResource CheckBoxStyle1}"/>
</Grid>
</Window>
アニメーションを記述する
以前の記事を参照。
以前の記事では、CheckBoxの見た目を変化させてスイッチがぐいーんと動くようなことをやっているので、ControlTemplateとの合わせ技で実現させているが、見た目がダイナミックに変わらなくてよいようなアニメーションをするだけなら(例えば、背景色がじわじわ変わるだけとか)、Templateを使わなくても、プロパティの値を変化させるだけ(例えばBackgroundの値をじわじわ変化させるとか)でも実現できるはず。