オルタナティブ・ブログ > IT's my business >

IT業界のコメントマニアが始めるブログ。いつまで続くのか?

(XAML#07)「スタイルと BasedOn による拡張」

»

スタイルとは、複数のコントロールで共通する外観を統一しやすくするための機能です。技術的には、外観に関わらずコントロールのプロパティをまとめて設定できるようにする機能です。

スタイルは、リソースとして定義することが多いのですが、これは単独のコントロールに割り当てるだけでは意味がないためで、5日目に紹介した「プロパティ要素構文」を使って次のように定義することができます。

<Button Content="One">
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Foreground" Value="Red" />
        </Style>
    </Button.Style>
</Button>

これは、次の記述と同じことです。

<Button Content="One" Foreground="Red" />

Style で TargetType を指定したコントロール型(クラス)のプロパティが、Style 中の Setter に指定するプロパティ(Property プロパティ)で利用できます(TargetTypeは、より単純に「TargetType="Button"」と書くこともできます)。

前述のとおり、通常はリソースとして定義します。以下の定義では、ウィンドウ(Window)内で定義されたすべての Button 型のコントロールの文字色(Foreground プロパティ)を "Red" に、スタイル(FontStyleプロパティ)を "Italic" に設定します。

<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="325" Width="525">
    <Window.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Foreground" Value="Red" />
            <Setter Property="FontStyle" Value="Italic" />
        </Style>
    </Window.Resources>
    <StackPanel>
        <!-- すべてのコントロールにだけスタイルが適用される -->
        <Button Content="One" />
        <Button Content="Two" />
        <Button Content="Three" />
    </StackPanel>
</Window>

特定のコントロールにだけ適用したい場合には、スタイルにキー(x:Key)を設定して、コントロールの Style プロパティで明示的に指定します。

<Window.Resources>
    <Style x:Key="MyStyle" TargetType="{x:Type Button}">
        <Setter Property="Foreground" Value="Red" />
        <Setter Property="FontStyle" Value="Italic" />
    </Style>
</Window.Resources>
<StackPanel>
    <!-- 最初のコントロールにだけスタイルが適用される -->
    <Button Content="One" Style="{StaticResource MyStyle}" />
    <Button Content="Two" />
    <Button Content="Three" />
</StackPanel>

ここでは Window のリソース(Resourcesプロパティ)として定義していますが、3日目に紹介した通り、リソースを定義する場所によって影響範囲を変えることができます。App.xaml の Application で定義すれば、アプリケーション全体にスタイルを適用できます。

さて、一般的なスタイルとして定義した後、さらに個別に異なるスタイルを定義したいことがあります。このような場合には基本的なスタイル定義を BasedOn 属性で参照した上で、設定を追加できます。

<Window.Resources>
    <Style x:Key="MyStyle" TargetType="{x:Type Button}">
        <Setter Property="Foreground" Value="Red" />
        <Setter Property="FontStyle" Value="Italic" />
    </Style>
    <!-- MyStyle をもとに新たな設定を追加する -->
    <Style x:Key="ExtraStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource MyStyle}">
        <Setter Property="Foreground" Value="Blue" />
        <Setter Property="FontWeight" Value="Bold" />
    </Style>
    </Window.Resources>
        <StackPanel Grid.Column="0">
            <!-- MyStyle の設定が適用される -->
            <Button Content="One" Style="{StaticResource MyStyle}" />
            <!-- ExtraStyle の設定が適用される -->
            <Button Content="Two" Style="{StaticResource ExtraStyle}" />
            <!-- ExtraStyle の設定が適用される(自身で設定した Foreground が最優先) -->
            <Button Content="Three" Style="{StaticResource ExtraStyle}" Foreground="Green" />
        </StackPanel>
        ...

あたかもスタイルを“継承”できるような機能です。初期の WPF には BasedOn はありませんでしたが、このように「既存のものを拡張して使う」方がスタイルの管理がしやすくなります。

また、キーを使わずに設定したスタイルを継承する場合には、「BasedOn="{StaticResource {x:TypeButton}}"」のように記述します。以下は、ウィンドウのリソースとして定義したスタイルを、2つの StackPanel で、それぞれ異なるスタイルに置き換えている例です。

<Window.Resources>
    <Style TargetType="{x:Type Button}">
        <Setter Property="Foreground" Value="Red" />
        <Setter Property="FontStyle" Value="Italic" />
    </Style>
</Window.Resources>
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <StackPanel Grid.Column="0">
        <StackPanel.Resources>
        <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
            <Setter Property="Foreground" Value="Blue" />
        </Style>
    </StackPanel.Resources>
    <Button Content="One" />
    <Button Content="Two" />
    <Button Content="Three" />
</StackPanel>
<StackPanel Grid.Column="1">
    <StackPanel.Resources>
        <Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
            <Setter Property="FontWeight" Value="Bold" />
        </Style>
    </StackPanel.Resources>
    <Button Content="First" />
    <Button Content="Second" />
    <Button Content="Third" />
    </StackPanel>
</Grid>

通常は、アプリケーション全体で適用されるスタイルを App.xaml に定義しておき、ウィンドウごとに個別のスタイルを設定する際に BasedOn を使うようにします。

このようにキーを設定せずに全体に適用するスタイルがあるときでも、特定のコントロールでスタイルを適用したくないならば、そのコントロールの属性として「Style="{x:Null}"」と指定しておきます。これで、そのコントロールのデフォルトの状態が使われるようになります。

Xaml7

Comment(0)