4

アプリケーションに動的テーマ切り替えを追加するように要求されましたが、これを行う方法がわかりません。

現在の状況は次のとおりです。アプリケーションには、明示的な(暗黙的ではない)スタイルのマージされたリソースディクショナリがあります。StaticResourceアプリケーションのビューは、マークアップ拡張機能を介してこれらのスタイルを参照します。暗黙的なスタイルを使用しない理由は、一般的なタイプのコントロールを複数回検索するためです。たとえば、ある場所のボタンは別の場所のボタンとは異なって見えます。

したがって、私たちがやりたいのは、これらの名前付きスタイルを新しい名前付きスタイルのセットに置き換えるテーマを作成することです。

アプローチ1

最初の試みは、テーマごとにリソース辞書を作成することでした。一般的な辞書からスタイルの1つを削除し、それらを各テーマ辞書に配置して、次のように各コピーに異なる外観を与えました。

<!-- RedTheme.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    mc:Ignorable="d"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
  <Style x:Key="HeaderContentStyle" TargetType="ContentControl">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="ContentControl">
          <Grid Margin="0" Background="Red">
            <ContentPresenter Content="{TemplateBinding Content}"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>


<!-- BlueTheme.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    mc:Ignorable="d"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
  <Style x:Key="HeaderContentStyle" TargetType="ContentControl">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="ContentControl">
          <Grid Margin="0" Background="Blue">
            <ContentPresenter Content="{TemplateBinding Content}"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

次に、XAMLからリソースディクショナリの1つを動的にロードし、それをアプリケーションのマージされたディクショナリに挿入するコードを追加しました。

// In App.xaml.cs
var themeUri = new Uri(
    "OurApp;component/Themes/RedTheme.xaml", UriKind.Relative);
var resourceInfo = GetResourceStream(themeUri);
using (var stream = resourceInfo.Stream)
{
    using (var reader = new StreamReader(stream))
    {
        var xamlText = reader.ReadToEnd();
        var dict = XamlReader.Load(xamlText) as ResourceDictionary;
        Resources.MergedDictionaries.Add(dict);
    }
}

これはある程度機能しました。起動時に「テーマ」を読み込んだ場合、そのテーマのスタイルが表示されていました。しかし、うまくいかなかったのは、起動後に他のテーマに切り替えようとしたことでした。マージされたディクショナリに他のテーマテーマディクショナリを追加しても、UIは変更されませんでした。また、古いテーマ辞書をクリアして新しいテーマ辞書を追加することもしませんでした。これらのいずれも実行せずに、ルートビジュアルを削除して再度追加しました。

アプローチ2

その後、SilverlightToolkitパターンのテーマを使用してみました。これは、明示的なスタイルではなく暗黙的なスタイルを切り替えることを目的としているため、機能しなかったと思います。テーマから派生したクラスを作成し、そのリソースディクショナリURIを設定して、そのテーマをルートビジュアルに追加しました。ただし、メインのUIクラスを作成したときに、UIによって参照される明示的なスタイルが見つからなかったため、実行時例外が発生しました。 ContentControl

そこで、テーマリソースディクショナリの1つをアプリケーションのマージされたディクショナリにロードしてみました。これにより、メインUIクラスを作成し、Styleオブジェクト内に配置することができました。ただし、Styleリソースディクショナリ内の明示的なスタイルは、アプリケーションのマージされたディクショナリ内で定義されたスタイルをオーバーライドできませんでした。したがって、何も変化していないように見えました。

現在のアプローチ

そこで今、私は3番目のアプローチを検討しています。これには、次のようなものを使用した添付プロパティが含まれますTheming.Style="StyleName"。次に、アプリケーションの他の場所で、テーマ名とスタイル名のオーバーライドの間の関連付けが維持されます。テーマが変更されるたびに、テーマに適したスタイルが適用されます。

ジレンマ

すでにホイールが存在する場合は、ホイールを再発明したくありません。明示的なスタイルを含むテーマを切り替えることができるSilverlightに組み込まれているものはすでにありますか?私がやりたいことをさせてくれるサードパーティのライブラリはありますか?

4

1 に答える 1

4

私はもう会社にいないので、最終的に使用した特定のコードを投稿することはできませんが、添付のプロパティアプローチを使用しました。Style動的にスキニングする必要があるオブジェクトのプロパティへの割り当てをTheming.Style、同じ値に設定されたアタッチされたプロパティに置き換えました。次に、リソースディクショナリで、テーマ名のプレフィックスが付いたスタイルを作成しました。たとえば、かつて「StandardButton」スタイルがあった場合、「Blue|StandardButton」および「Clean|StandardButton」という名前の追加のスタイルを作成します。テーマエンジンは、テーマを切り替えるたびにそれらのテーマ固有のスタイルを検索し、それらをプロパティがアタッチされた要素に適用できるようになります。

うまくいけば、これは他の人にとって役立つアプローチですが、この問題をすでに解決しているライブラリがそこにあることが望ましいです。

于 2010-10-21T20:37:16.150 に答える