2010年3月13日土曜日

第24回 スキンに対応する

見た目を簡単に変更できるように、
Styleなどの見た目に関する部分を
外部ファイルに移していきます。

dllなどにしても置き換えるだけで変更できますが、
これだと開発者しか作れないので、
テキストのxamlファイルを動的に読み込むようにします。
テキストなので手軽に編集できますが、
起動時に読み込む分、動作は若干遅くなると思います。

ちなみにWPFのテーマ、スキンを扱う方法に関しては
エッセンシャルWPFという本に結構詳しく書いてあります。

まずスキンは起動ディレクトリのSkinフォルダに入っているxamlすべてということに決めます。
App.xaml.csで、すべての.xamlファイルを読み込み、
ResourceDictionaryに統合します。
AppクラスのResourcesに入れたStyleなどは
アプリケーションのすべての場所に適用されます。
(個々の場所で上書きされた場合を除く)



   //スキンの読込
   var baseUri = Directory.GetParent(
    System.Reflection.Assembly.GetExecutingAssembly().Location).FullName;
   ResourceDictionary rd = null;
   foreach (var file in Directory.GetFiles(baseUri + @"\Skins", @"*.xaml")) {
    var theme = XamlReader.Load(XmlReader.Create(file)) as ResourceDictionary;
    if (rd == null) {
     rd = new ResourceDictionary();
     foreach (DictionaryEntry entry in this.Resources) {//既存のリソースを読込
      rd[entry.Key] = entry.Value;
     }
    }
    rd.MergedDictionaries.Add(theme);
   }
   if (rd != null) {
    this.Resources = rd;
   }



あとは、以下のような内容が入ったxamlファイルを用意します。


<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   
    <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
      <Setter Property="FontFamily" Value="Meiryo UI"/>
    </Style>
   
    <Style x:Key="{x:Type TextBlock}" TargetType="{x:Type TextBlock}">
      <Setter Property="FontFamily" Value="Meiryo UI"/>
    </Style>
</ResourceDictionary>

この例では、アプリケーション中のTextBlockとButtonのすべてのフォントが
Meiryo UIになるように変更しています。

特定の場所にだけ適用したい場合はスキンファイルで


<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style x:Key="TimelineItemNameStyle" TargetType="{x:Type Hyperlink}">
      <Setter Property="FontWeight" Value="Bold"/>
      <Setter Property="TextDecorations" Value="None"/>
    </Style>
   
    <Style x:Key="TimelineItemTextStyle" TargetType="{x:Type ContentPresenter}">
    <Setter Property="Margin" Value="3"/>
    </Style>
</ResourceDictionary>

のようにKeyを設定して、
使う場所(View)でStyleを指定します。


      <ContentPresenter Style="{DynamicResource TimelineItemTextStyle}"
       Content="{Binding Path=TextComponents, Converter={StaticResource TextCompConverter}}"/>


今回のソースコード
http://wtwitter.codeplex.com/SourceControl/changeset/view/42975

Skin関係のファイルはbinフォルダを降りたところにあるので注意してください。

2 件のコメント:

  1. このエントリはあまりにも間違いがひどかったので、
    投稿後ソースコードを書き直しました。

    返信削除
  2. SubmitViewのボタンを変にいじっているのですが、
    テストでいじっていたのをそのまま忘れちゃってただけなので
    無視してください。。

    返信削除