2012-02-28 6 views
12

実行時にオンとオフを切り替えることができる屋外用のカスタム「高コントラスト」テーマを持つアプリケーションを構築します。これは、以下のようなスタイルを含むリソースディクショナリをマージし、非合併により正常に動作します...Style BasedOnのDynamicResource

<Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}"> 
    <Setter Property="OverridesDefaultStyle" Value="true"/> 
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/> 
    <Setter Property="Template" Value="{StaticResource Theme_MenuItemTemplate}"/> 
</Style> 

メニュー項目の使用量がスタイルを指定していないとき、これは素晴らしい作品。これは現実的ではありませんが、Stylesを持たないItemsSourceで生成された子をバインドする方法がないため、多くの状況ではそうです。 StackOverflowの上の他のすべての投稿はあなただけのこの操作を行う必要があると言う

<ContextMenu.ItemContainerStyle> 
    <Style TargetType="MenuItem"> 
     <Setter Property="Header" Value="{Binding Path=Name}"/> 
     <Setter Property="IsCheckable" Value="True"/> 
     <Setter Property="IsChecked" Value="{Binding Path=Checked}"/> 
     <EventSetter Event="Checked" Handler="HistoryItem_Checked"/> 
    </Style> 
</ContextMenu.ItemContainerStyle> 

...

<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}"> 
    <!-- Your overrides --> 
</Style> 

しかし、私のBASEDONは、実行時に変更される可能性があるため、これは私の状況では動作しません。たとえば、 (もちろん、BasedOnプロパティでDynamicResource拡張を使用することはできません)。私のアプリケーションでこれを行うと、コントロールが読み込まれずに他のすべてのコントロールが正しく切り替わる間にコントロールがロードされたときに、スタイルに慣れてしまうオーバーライドコントロールが表示されます。

だから私の質問...

がBASEDONのために働いてDynamicResourceの拡張子を取得する方法はありますか、別の方法があるが/私はこの作業を取得するために実装することができますハック?

答えて

7

は最後にAttachedDependencyPropertyを使用してStyle.BasedOnためDynamicResouceのためのソリューションを考え出しました。ここで

がここItemsControl.ItemContainerStyleの修正(簡単FrameworkElement.Styleを変更するように変更することができる)

public class DynamicContainerStyle 
{ 
    public static Style GetBaseStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(BaseStyleProperty); 
    } 

    public static void SetBaseStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(BaseStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for BaseStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty BaseStyleProperty = 
     DependencyProperty.RegisterAttached("BaseStyle", typeof(Style), typeof(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged)); 

    public static Style GetDerivedStyle(DependencyObject obj) 
    { 
     return (Style)obj.GetValue(DerivedStyleProperty); 
    } 

    public static void SetDerivedStyle(DependencyObject obj, Style value) 
    { 
     obj.SetValue(DerivedStyleProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for DerivedStyle. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty DerivedStyleProperty = 
     DependencyProperty.RegisterAttached("DerivedStyle", typeof(Style), typeof(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged)); 

    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     if (!typeof(System.Windows.Controls.ItemsControl).IsAssignableFrom(target.GetType())) 
      throw new InvalidCastException("Target must be ItemsControl"); 

     var Element = (System.Windows.Controls.ItemsControl)target; 

     var Styles = new List<Style>(); 

     var BaseStyle = GetBaseStyle(target); 

     if (BaseStyle != null) 
      Styles.Add(BaseStyle); 

     var DerivedStyle = GetDerivedStyle(target); 

     if (DerivedStyle != null) 
      Styles.Add(DerivedStyle); 

     Element.ItemContainerStyle = MergeStyles(Styles); 
    } 

    private static Style MergeStyles(ICollection<Style> Styles) 
    { 
     var NewStyle = new Style(); 

     foreach (var Style in Styles) 
     { 
      foreach (var Setter in Style.Setters) 
       NewStyle.Setters.Add(Setter); 

      foreach (var Trigger in Style.Triggers) 
       NewStyle.Triggers.Add(Trigger); 
     } 

     return NewStyle; 
    } 
} 

とは一例である...ここで

<!-- xmlns:ap points to the namespace where DynamicContainerStyle class lives --> 
<MenuItem Header="Recent" 
    ItemsSource="{Binding Path=RecentFiles}" 
    IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=HasItems}" 
    ap:DynamicContainerStyle.BaseStyle="{DynamicResource {x:Type MenuItem}}"> 
    <ap:DynamicContainerStyle.DerivedStyle> 
     <Style TargetType="MenuItem"> 
      <EventSetter Event="Click" Handler="RecentFile_Clicked"/> 
     </Style> 
    </ap:DynamicContainerStyle.DerivedStyle> 
    <MenuItem.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding}"/> 
     </DataTemplate> 
    </MenuItem.ItemTemplate> 
</MenuItem> 

FrameworkElement.Styleを設定し、修正したバージョンです代わりに私の別の投稿への私の答え: Setting a local implicit style different from theme-style/alternative to BasedOn DynamicResource

+0

ベーススタイルを簡単にコピーすることができます。私はこれを新しい答えに加えました。 – aliceraunsbaek

1

スタイルは、UIElement.Resourcesタグ内にある必要があります。これを動的にクリアして再投入することができます。

私はこのような複雑なようではないが類似何かを:

MobileApp.Get().Resources.MergedDictionaries.Clear(); 

Uri uri = new Uri("/Resources/DayModeButton.xaml", UriKind.Relative); 
ResourceDictionary resDict = Application.LoadComponent(uri) as ResourceDictionary; 

resDict["SelectedColor"] = selectedColor; //change an attribute of resdict 

MobileApp.Get().Resources.MergedDictionaries.Add(resDict); 
+0

これは、リソースディクショナリをマージしたり解凍したりするのとほぼ同じです。私はあなたがUIElement.Resorucesタグによって何を意味するか分かりません。 – NtscCobalt

+0

私は、のスタイルを明示的に設定するのではなく、UIElement.Resourcesにスタイルを配置することをテストしましたが、同じ効果があり、読みやすくするためにを使用しています。 – NtscCobalt

3

私は少しのimp NtscCobaltsのローバメントの答え:

新しいスタイルを作成するときは、単純に基本スタイルを設定することができます。このように、基本スタイルの基本スタイルは自動的に階層に配置されます。