.NETで作る!

.NETに関するあれこれ(C#、VB.NET)

WPF 配色を外部ファイル化する

「app.configに設定した色をコントロールの背景色に使う」とかそういうイメージ。

f:id:mk3008net:20150215012035p:plain

イデア

  • app.configにて色を16進数で指定。
  • app.configにある色情報をアクセッサクラス(Pallet.vb)を作成。
  • リソースファイル(xaml)にて、Palletクラスをインスタンス。色を取り出し単色ブラシにする。 このリソースファイルをTheme.xamlとして、他のリソースから参照する。

app.configにて色を16進数で指定

特筆すべきことはありません。こんな感じで指定するだけ。

<setting name="PageBackgroundColor" serializeAs="String">
    <value>#F5F5F5</value>
</setting>

パレットクラスを作る

app.configで設定した色情報はあくまでもString型なので、これをColor構造体に変換し扱いやすいものに変える。

Public Class Pallet

    Public Sub New()
        Me.PageBackgroundColor = My.Settings.PageBackgroundColor.ToColor
    End Sub

    ''' <summary>
    ''' ページ背景色
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property PageBackgroundColor As System.Windows.Media.Color
End Class

型変換は拡張メソッドで定義して、「String.ToColor」と記述できるようにしてやりましょう。なお色名指定には対応しておりません。

Public Module StringExtension

    Private Const RGB_PATTERN As String = "^#(?<r>[0-9A-Fa-f]{2})(?<g>[0-9A-Fa-f]{2})(?<b>[0-9A-Fa-f]{2})$"
    Private Const ARGB_PATTERN As String = "^#(?<a>[0-9A-Fa-f]{2})(?<r>[0-9A-Fa-f]{2})(?<g>[0-9A-Fa-f]{2})(?<b>[0-9A-Fa-f]{2})$"

    <Extension()>
    Public Function ToColor(source As String) As Color
        Try
            Dim a As Integer = 255
            Dim r As Integer = 255
            Dim g As Integer = 255
            Dim b As Integer = 255

            If Regex.IsMatch(source, RGB_PATTERN) Then
                Dim m As Match = Regex.Match(source, RGB_PATTERN)
                r = HexToInt(m.Groups("r").Value)
                g = HexToInt(m.Groups("g").Value)
                b = HexToInt(m.Groups("b").Value)

            ElseIf Regex.IsMatch(source, ARGB_PATTERN) Then
                Dim m As Match = Regex.Match(source, ARGB_PATTERN)
                a = HexToInt(m.Groups("a").Value)
                r = HexToInt(m.Groups("r").Value)
                g = HexToInt(m.Groups("g").Value)
                b = HexToInt(m.Groups("b").Value)

            End If

            Return Color.FromArgb(a, r, g, b)

        Catch ex As Exception
            Return Color.FromRgb(255, 255, 255)
        End Try
    End Function

    Private Function HexToInt(s As String) As Integer
        Return Convert.ToInt32(s, 16)
    End Function

End Module

テーマリソースディクショナリを作る

特筆すべきことなし。名前空間の「theme」は適宜ご自分の環境に変えてお使いください。(Themeクラスの正式名が「Prism.UI.Extension.Theme」の場合、以下のようになる)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:theme="clr-namespace:Prism.UI.Extension.Theme">

    <theme:Pallet x:Key="pallet" />

    <SolidColorBrush x:Key="PageBackgroundBrush" Color="{Binding PageBackgroundColor, Source={StaticResource pallet}}" />
</ResourceDictionary>

あとは使うだけ

Sourceの記述は適宜ご自分の環境に変えてお使いください。(テーマリソースディクショナリが「Prism.UI.Extension」ライブラリのパス「/Theme/Resources/Theme.xaml」にある場合、以下のようになる)

<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:,,,/Prism.UI.Extension;component/Theme/Resources/Theme.xaml" />
    </ResourceDictionary.MergedDictionaries></ResourceDictionary>

おまけ

設定色は少ない方が管理が楽なので、こんなことをするといいかも。

  • 文字色は背景色の明度を判定して動的に判定させることで省略する。
  • フォーカス時のハイライトカラーは透明度のレイヤーをかぶせて表現することで省略する。
. .