リソースディクショナリ内のスタイルの拡張/オーバーライド
-
05-07-2019 - |
質問
WPFアプリケーションとは別のdllにBaseSkinと複数のUserSkinがあります。
アプリケーションを使用しているユーザーに応じて、ベーススキンとユーザースキンの1つがリソースディクショナリにマージされ、アプリケーションが使用するためにロードされます。
私が目指しているのは、BaseSkinファイルでスタイルを指定し、特定のUserSkinファイルでスタイルをオーバーライドして、必要なプロパティを変更できるようにすることです。
次のようにBasedOn属性を使用してこれを達成できることを知っています:
ベース:
<Style x:Key="ButtonBg" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
</Style>
ユーザー:
<Style x:Key="CustomButtonBg" TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonBg}">
<Setter Property="Background" Value="Blue"/>
</Style>
問題は、要素が実際には実装されていない可能性のあるCustomButtonBgのStyleを持つ必要があることです。両方のスタイルで同じキー(ButtonBg)を使用する方法はありますか?それらがマージされると、アプリケーションは最初にUserでButtonBgという名前のスタイルを探し、存在しない場合はbaseのスタイルを使用しますか?
BaseSkinファイルを指すようにBasedOn属性でアセンブリ名を指定できれば、同じキーを指定したときに名前付けエラーを回避できると考えていましたが、その方法は見つかりません。他のオプションは、何も変更されない場合でも各スタイルの実装を強制するか、スキンをプログラムでチェックしますが、これらは最後の手段です。
解決
リソースルックアップロジックを利用することができます。 WPFがキーでリソースを見つけようとするとき、最初に現在の要素の ResourceDictionary
を調べ、次にその親、次にその親などを調べます。
ユーザーに条件付きだと言ったので、元のベースが Applicationにある間に
レベル。 Window
レベルで ResourceDictionary
にマージされる可能性があります
編集:より良い情報があります。 MSDNのマージされた辞書から:
マージされた辞書の動作
マージされたディクショナリ内のリソースは、リソースルックアップスコープ内の場所を占有します。リソースルックアップスコープは、マージされるメインリソースディクショナリのスコープの直後です。リソースキーは個々のディクショナリ内で一意である必要がありますが、キーはマージされたディクショナリのセットに複数回存在できます。この場合、返されるリソースは、MergedDictionariesコレクションで順番に見つかった最後の辞書から取得されます。 MergedDictionariesコレクションがXAMLで定義されている場合、コレクション内のマージされた辞書の順序は、マークアップで提供される要素の順序です。キーがプライマリ辞書およびマージされた辞書でも定義されている場合、返されるリソースはプライマリ辞書から取得されます。これらのスコープ規則は、静的リソース参照と動的リソース参照の両方に等しく適用されます。
つまり、ベーススキンを別の ResourceDictionary
で定義し、別の ResourceDictionary
にマージできます。後者のユーザースキンを使用すると、最初に検出されます。それ以外の場合は、Baseを含むマージされたディクショナリにドリルダウンし続けます。ユーザー辞書のそれぞれがベース辞書をマージでき、ユーザー辞書を両方ではなくアプリにロードするだけです。
他のヒント
BaseにBaseButtonBgという名前を付けるだけで、ユーザーベースのResourceDictionaryをマージしない場合は、次のものを含む一般的なものをマージします。
<Style x:Key="ButtonBg" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButtonBg}"/>