LoginSignup
13
20

More than 1 year has passed since last update.

[WPF] Styleでできることと書き方

Last updated at Posted at 2021-05-24

もくじ

■やりたいこと

画面の部品の見た目や挙動をStyleを使って変えたいなと思ったときに、いまだにどこにどう書くんだったか、と迷う。
しかもなぜか、以前に調べたことを毎回結構忘れていて時間を取られるので、一度テンプレート的なものを持っておきたい。

■Styleを書く場所

直接Styleを書く

通常状態/マウスオーバー状態
image.pngimage.png

MainWindow.xaml
<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の見た目になる。
image.png

MainWindow.xaml
<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名を指定したものだけ、その見た目になる。
image.png

MainWindow.xaml
<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を書く

以前の記事を参照。

■できること

自分自身のプロパティの値に応じて見た目を変える

これを「プロパティトリガー」という。
自分のプロパティの値に応じて、自分の見た目にかかわるプロパティの値を変える、ということ。

例.xaml
<Trigger Property="IsMouseOver" Value="True">
    <Setter Property="Fill" Value="GreenYellow"/>
</Trigger>

※上の「書く場所」に挙げたサンプルにある内容。

ViewModel等のプロパティの値に応じて見た目を変える

これを「データトリガー」という。
詳細は以前の記事を参照。

下記のような感じ。

例.xaml
<!-- ViewModelが持ってるプロパティColorChangeFlagにバインドしてる -->
<DataTrigger Binding="{Binding ColorChangeFlag}" Value="true">
     <Setter Property="Fill" Value="Blue"/>
</DataTrigger>

Styleの中でTemplateを変更する

できること、というよりは、こういう書き方もできる、という感じ。

各コントロールの標準のテンプレートを出すと、よく見る書かれ方。

下は、CheckBoxのデフォルトのStyleをまともに動かないくらい簡略化したものを、
リソースにControlTemplateを書いてkey指定してつかうものと、styleに直接書くものをやってみたコード。

やる機会はあまりないと思うが、これをやれば、プロパティの値によってTemplateを変えることができる、イコール見た目をガラッと変えることもできる。(むしろそんなことはしてはいけないかもしれない)

通常時/マウスオーバー時
image.pngimage.png

MainWindows.xaml
<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の値をじわじわ変化させるとか)でも実現できるはず。

13
20
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
13
20