XAML の Style を CSS っぽく作る
◆ css のようなもの → XAML の Style
前にちょっと触れた WPF で作るときの XAML で CSS っぽくする方法
気になったので少し調べてみました
と言っても これで何作るわけでもないのでかる~くです
その中の各プロパティは Setter タグを使います
こういうのです
これを CSS 風に書けば
となります
Style の属性 TargetType がタグ名(コントロール名)で Setter の Property にプロパティ名を書いて その設定する値を Value に書きます
Foreground は CSS でいう color です
Style タグは Resources か Style の添付プロパティの下にしか書けないみたい
Window.Resources に書くと Window 以下全体のように 書いた場所以下が対象になるようです
Button.Style のような書き方の場合は その Button コントロールひとつを指定して設定できるようです
HTML の style 属性ということかな
Style にしなくても普通の属性でも設定できるのにこういうことも可能なようです
上の XAML の場合は ボタンコントロールは Window の内側ですし 自分の Style 属性もあるので 2 つの Background が設定されています
ですが 自分の Style 属性が優先されるので Lime 色になります
style 属性が優先なのは HTML/CSS でも一緒ですね
という Style があるときに
というボタンを 2 つ用意すると下のほうだけにスタイルが適用されて色がつきます
Style の定義では x:Key 属性にクラス名を書いておきます
コントロールの方では Style 属性に {StaticResource ○○} というフォーマットでクラス名を指定します
HTML/CSS だと
StaticResource に対して DynamicResource もあります
違いは 最初の定義時のものを使うか 動的に変更されるものを使うかということみたいです
Style タグの属性に BasedOn という属性を追加します
下の Style は上の Style を継承しています
なので Button の Style に inherited を指定すれば 背景が Yellow で文字色が Chocolate でフォントサイズが 20 のボタンになります
BasedOn の書き方はクラスと同じで StaticResource を使います
TargetType が Button のを指定しているのですが {StaticResource base} でもいいんじゃないかと思います(未確認)
(後から確認したくなったときにサッと起動して確認できないのが C# というか多くの言語の不便なところですよね JavaScript なら書きながら試したいことができたら F12 キーを押して即試せるのに……)
つまり CSS のようにファイルを分けてロードするということができます
ロードされる側はこんな定義の仕方をします
[style.xaml]
このファイルをロードするときは
こんな感じでロードします
Window じゃないといけないことはないので StackPanel にしてみました
ロードしたところに 読み込むファイルで定義したものをそのまま入れるような感じです
複数のファイルをロードする場合は マージが必要になるようでこんなに書かないといけません
ただ 面倒なだけじゃなくて ぱっと見たときにごちゃごちゃしていて目的のものを探すのも大変です
ということで CSS 風に書いたものを XAML 変換するものを作ってみました
といっても 全部の機能に対応してるわけじゃないです
これだけあれば簡単なものなら困らないんじゃない?くらいなものです
また 完全な XAML を出力するのじゃなくて Style タグのグループとして出力するようになってます
C# に組み込んで実行時に CSS 風なものから変換だと複雑ですし 遅くなりますし そもそもコンパイル時に XAML は IL に変換されてた気がするので 実行時に XAML 生成しても使えなさそうに思えます
どこの Resources に配置するかや 別ファイルにするかなども Style タグだけ作った方が自由にできるのでこっちのほうがいいと思ってます
あと パーサは凄くシンプルに 「{」まで持ってくる 「}」まで持ってくる のような作りなので構文エラーがあるとおかしなことになる可能性は高めです
xcss2xaml.html
タグ名とクラス名を書けます
extends の後にクラスのセレクタを書けばそのクラスを継承できます
↑のコードで出力される XAML はこちら
どうせなら border とか color とか CSS のプロパティ名と書き方で XAML 変換するようにしてもよかったのですが XAML というか C# のクラス名で慣れてる人もいるでしょうし どこかで BorderBrush とか Foreground とか書くことはでてきそうなので そのときに CSS のプロパティ名で書いてると不便なこともあるかなーと思ってそのまま出力することにしました
Style をネストして
(めんどくさくなった)
:hover のようなこともトリガーで可能ですが非対応です
(めんd(ry))
気になったので少し調べてみました
と言っても これで何作るわけでもないのでかる~くです
Style
基本
Style というタグを使って CSS でいう {} のまとまりを表現しますその中の各プロパティは Setter タグを使います
<Style TargetType="Button">
<Setter Property="Background" Value="Azure"/>
<Setter Property="Foreground" Value="Tomato"/>
</Style>
<Setter Property="Background" Value="Azure"/>
<Setter Property="Foreground" Value="Tomato"/>
</Style>
こういうのです
これを CSS 風に書けば
Button {
Background: Azure;
Foreground: Tomato;
}
Background: Azure;
Foreground: Tomato;
}
となります
Style の属性 TargetType がタグ名(コントロール名)で Setter の Property にプロパティ名を書いて その設定する値を Value に書きます
Foreground は CSS でいう color です
Style タグは Resources か Style の添付プロパティの下にしか書けないみたい
<Window>
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Purple" />
</Style>
</Window.Resources>
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Lime" />
</Style>
</Button.Style>
ぼたんてきすと
</Button>
</Window>
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Purple" />
</Style>
</Window.Resources>
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="Lime" />
</Style>
</Button.Style>
ぼたんてきすと
</Button>
</Window>
Window.Resources に書くと Window 以下全体のように 書いた場所以下が対象になるようです
Button.Style のような書き方の場合は その Button コントロールひとつを指定して設定できるようです
HTML の style 属性ということかな
Style にしなくても普通の属性でも設定できるのにこういうことも可能なようです
上の XAML の場合は ボタンコントロールは Window の内側ですし 自分の Style 属性もあるので 2 つの Background が設定されています
ですが 自分の Style 属性が優先されるので Lime 色になります
style 属性が優先なのは HTML/CSS でも一緒ですね
クラス
同じ種類のコントロール全部だけじゃなくて CSS でいうクラスのようなこともできます<Style x:Key="classname" TargetType="Button">
<Setter Property="Background" Value="Crimson"/>
</Style>
<Setter Property="Background" Value="Crimson"/>
</Style>
という Style があるときに
<Button>普通の</Button>
<Button Style="{StaticResource classname}">色付き</Button>
<Button Style="{StaticResource classname}">色付き</Button>
というボタンを 2 つ用意すると下のほうだけにスタイルが適用されて色がつきます
Style の定義では x:Key 属性にクラス名を書いておきます
コントロールの方では Style 属性に {StaticResource ○○} というフォーマットでクラス名を指定します
HTML/CSS だと
<style>
button.classname{
background: crimson;
}
</style>
<button>普通の</button>
<button class="classname">色付き</button>
となりますbutton.classname{
background: crimson;
}
</style>
<button>普通の</button>
<button class="classname">色付き</button>
StaticResource に対して DynamicResource もあります
違いは 最初の定義時のものを使うか 動的に変更されるものを使うかということみたいです
継承
CSS 自体にはない機能ですが XAML の Style では継承もできますStyle タグの属性に BasedOn という属性を追加します
<Style x:Key="base" TargetType="Button">
<Setter Property="Background" Value="Gold"/>
<Setter Property="Foreground" Value="Chocolate"/>
</Style>
<Style x:Key="inherited" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="FontSize" Value="20"/>
</Style>
<Setter Property="Background" Value="Gold"/>
<Setter Property="Foreground" Value="Chocolate"/>
</Style>
<Style x:Key="inherited" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="FontSize" Value="20"/>
</Style>
下の Style は上の Style を継承しています
なので Button の Style に inherited を指定すれば 背景が Yellow で文字色が Chocolate でフォントサイズが 20 のボタンになります
BasedOn の書き方はクラスと同じで StaticResource を使います
TargetType が Button のを指定しているのですが {StaticResource base} でもいいんじゃないかと思います(未確認)
(後から確認したくなったときにサッと起動して確認できないのが C# というか多くの言語の不便なところですよね JavaScript なら書きながら試したいことができたら F12 キーを押して即試せるのに……)
インクルード
Winow.Resources に Style を書いていたと思いますが Resources は別ファイルにすることができますつまり CSS のようにファイルを分けてロードするということができます
ロードされる側はこんな定義の仕方をします
[style.xaml]
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button">
<Setter Property="Background" Value="#f0f0f0"/>
</Style>
</ResourceDictionary>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Button">
<Setter Property="Background" Value="#f0f0f0"/>
</Style>
</ResourceDictionary>
このファイルをロードするときは
<StackPanel>
<StackPanel.Resources>
<ResourceDictionary Source="style.xaml"/>
</StackPanel.Resources>
</StackPanel>
<StackPanel.Resources>
<ResourceDictionary Source="style.xaml"/>
</StackPanel.Resources>
</StackPanel>
こんな感じでロードします
Window じゃないといけないことはないので StackPanel にしてみました
ロードしたところに 読み込むファイルで定義したものをそのまま入れるような感じです
複数のファイルをロードする場合は マージが必要になるようでこんなに書かないといけません
<StackPanel>
<StackPanel.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="style1.xaml"/>
<ResourceDictionary Source="style2.xaml"/>
<ResourceDictionary Source="style3.xaml"/>
<ResourceDictionary Source="style4.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</StackPanel.Resources>
</StackPanel>
<StackPanel.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="style1.xaml"/>
<ResourceDictionary Source="style2.xaml"/>
<ResourceDictionary Source="style3.xaml"/>
<ResourceDictionary Source="style4.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</StackPanel.Resources>
</StackPanel>
CSS ぽいものから XAML にする
CSS と比べると全部 XML なのですごく書くのが面倒ですよねただ 面倒なだけじゃなくて ぱっと見たときにごちゃごちゃしていて目的のものを探すのも大変です
ということで CSS 風に書いたものを XAML 変換するものを作ってみました
といっても 全部の機能に対応してるわけじゃないです
これだけあれば簡単なものなら困らないんじゃない?くらいなものです
また 完全な XAML を出力するのじゃなくて Style タグのグループとして出力するようになってます
C# に組み込んで実行時に CSS 風なものから変換だと複雑ですし 遅くなりますし そもそもコンパイル時に XAML は IL に変換されてた気がするので 実行時に XAML 生成しても使えなさそうに思えます
どこの Resources に配置するかや 別ファイルにするかなども Style タグだけ作った方が自由にできるのでこっちのほうがいいと思ってます
あと パーサは凄くシンプルに 「{」まで持ってくる 「}」まで持ってくる のような作りなので構文エラーがあるとおかしなことになる可能性は高めです
xcss2xaml.html
使い方
こんな構文Button.base {
border-thickness: 0;
background: white;
}
Button extends .base {
Foreground: #77a;
}
Button.name extends .base {
BorderThickness: 3;
}
border-thickness: 0;
background: white;
}
Button extends .base {
Foreground: #77a;
}
Button.name extends .base {
BorderThickness: 3;
}
タグ名とクラス名を書けます
extends の後にクラスのセレクタを書けばそのクラスを継承できます
↑のコードで出力される XAML はこちら
<Style TargetType="Button" x:Key="base">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="white" />
</Style>
<Style TargetType="Button" BasedOn="{StaticResource base}">
<Setter Property="Foreground" Value="#77a" />
</Style>
<Style TargetType="Button" x:Key="name" BasedOn="{StaticResource base}">
<Setter Property="BorderThickness" Value="3" />
</Style>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="white" />
</Style>
<Style TargetType="Button" BasedOn="{StaticResource base}">
<Setter Property="Foreground" Value="#77a" />
</Style>
<Style TargetType="Button" x:Key="name" BasedOn="{StaticResource base}">
<Setter Property="BorderThickness" Value="3" />
</Style>
どうせなら border とか color とか CSS のプロパティ名と書き方で XAML 変換するようにしてもよかったのですが XAML というか C# のクラス名で慣れてる人もいるでしょうし どこかで BorderBrush とか Foreground とか書くことはでてきそうなので そのときに CSS のプロパティ名で書いてると不便なこともあるかなーと思ってそのまま出力することにしました
未対応
Style をネストして
section div h1 {}
みたいな構造にすることもできるようですが 非対応です(めんどくさくなった)
:hover のようなこともトリガーで可能ですが非対応です
(めんd(ry))