2011-12-22 35 views
6

想象一个wpf应用程序,我可以在其中动态更改主题。我通过在应用程序资源级别更换ResourceDictionaries来完成此操作。主题 - 资源词典为TextBox等定义了隐式样式。设置一个与主题风格不同的本地隐式风格/替代BasedOn DynamicResource

现在我在我的应用程序中的一部分,其中文本框应具有此特定样式“NonDefaultTextBoxStyle”,而不是应用程序范围内隐。

我很乐意这样做(使用DynamicResource因为主题可以在运行时更改):

<StackPanel> 
    <StackPanel.Resources> 
     <Style TargetType="TextBox" BasedOn="{DynamicResource NonDefaultTextBoxStyle}"/> 
    </StackPanel.Resources> 
    <TextBox .../> 
    <TextBox .../> 
    <TextBox .../> 
</StackPanel> 

,而不必这样做:

<StackPanel> 
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../> 
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../> 
    <TextBox Style="{DynamicResource NonDefaultTextBoxStyle}" .../> 
</StackPanel> 

我们简化了这一点,我有这样的想法,在StackPanel上设置一个可继承的附加属性,它将在每个后代文本框上设置指定的样式。

这是个好主意吗?有更简单的方法吗?我错过了什么吗?

这几乎可以归结为:什么是一个风格支持算法FMP替代=“{DynamicResource ...}

回答

4

我有相同的问题,但对于ItemsContainerStyle ...所以我做了? 。几乎你说的话,写的AttachedProperty这将允许支持算法FMP动态资源

DynamicResource for Style BasedOn

下面是修改您的情况的解决方案:

public class DynamicStyle 
{ 
    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(DynamicStyle), new UIPropertyMetadata(DynamicStyle.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(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged)); 

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

     var Element = (FrameworkElement)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.Style = 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 DynamicStyle class lives --> 
<Button ap:DynamicStyle.BaseStyle="{DynamicResource {x:Type Button}}"> 
    <ap:DynamicStyle.DerivedStyle> 
     <Style TargetType="Button"> 
      <Style.Triggers> 
       <MultiDataTrigger> 
        <MultiDataTrigger.Conditions> 
         <Condition Binding="{Binding Path=FirstButtonWarning}" Value="True"/> 
         <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="True"/> 
        </MultiDataTrigger.Conditions> 
        <MultiDataTrigger.Setters> 
         <Setter Property="Background" Value="{DynamicResource WarningBackground}"/> 
         <Setter Property="Foreground" Value="{DynamicResource WarningForeground}"/> 
        </MultiDataTrigger.Setters> 
       </MultiDataTrigger> 
      </Style.Triggers> 
     </Style> 
    </ap:DynamicStyle.DerivedStyle> 
    <TextBlock Text="Button that changes background and foreground when warning is active"/> 
</Button> 
+0

我只能建议你阅读的问题!你没有解决我的问题! – 2013-02-26 02:11:34

+0

@MarkusHütter我现在看到你的问题。嗯,继续我的答案,你应该能够将我的解决方案中的附加解决方案属性更改为“FrameworkPropertyMetadataOptions.Inherits”(使用此http://msdn.microsoft.com/en-us/library/ms557296.aspx而不是' UIPropertyMetadata'),然后检查元素类型“StylesChanged”功能。然后附加的属性只需要在StackPanel元素上写入一次。 – NtscCobalt 2013-02-26 05:26:54

+0

所以你的意思就像我已经提出的问题... – 2013-02-27 00:34:10

3

是否真的需要是一个DynamicResource?
所以也许this将帮助你

如果不是这里是静态资源

一个简单的例子App.xaml中

<Application.Resources> 
     <Style x:Key="myResource" TargetType="Button"> 
      <Setter Property="Background" Value="Black"/> 
      <Setter Property="Foreground" Value="White"/> 
     </Style>   
    </Application.Resources> 

MainWindow.xaml

<StackPanel> 
    <StackPanel.Resources> 
     <Style TargetType="Button" BasedOn="{StaticResource myResource}"/> 
    </StackPanel.Resources> 
    <Button Content="blubb" Height="23" Width="75" /> 
</StackPanel> 

如果双方没有帮助,也许是你,你可以提供你如何添加资源

编辑

OK,现在应该回答你的问题

应用。XAML

<Application.Resources> 

    <SolidColorBrush x:Key="background" Color="Red" /> 
    <SolidColorBrush x:Key="foreground" Color="Blue" /> 

    <Style x:Key="NonDefaultTextBoxStyle" > 
     <Setter Property="TextBox.Background" Value="{DynamicResource background}"/> 
     <Setter Property="TextBox.Foreground" Value="{DynamicResource foreground}"/> 
    </Style> 

</Application.Resources> 

MainWindow.xaml

<StackPanel> 
    <Button Content="Button" Height="23" Width="75" Click="Button_Click" /> 

    <StackPanel> 
     <StackPanel.Resources> 
      <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource NonDefaultTextBoxStyle}"> 
      </Style> 
     </StackPanel.Resources> 
     <TextBox Text="bliii" Height="23" Width="75" /> 
     <TextBox Text="blaaa" Height="23" Width="75" /> 
     <TextBox Text="blubb" Height="23" Width="75" /> 
    </StackPanel> 

</StackPanel> 

MainWindow.cs

private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      this.Resources["background"] = Brushes.Black; 
      this.Resources["foreground"] = Brushes.Yellow; 
     } 
+0

我想知道为什么这是我发布的唯一问题,人们不会读这个问题!这个话题和问题太难理解了吗?回答你:是的,由于我要求“动态更改主题”(第1句),它需要成为DynamicResource。如果你读过你会注意到的链接问题,答案就如你的答案不使用动态资源。很抱歉,这没有帮助! – 2013-04-25 15:26:49

+0

@MarkusHütter对不起,不够透彻。也许你应该大胆作为捕手 – WiiMaxx 2013-04-25 22:44:45

+0

@MarkusHütter我认为我的编辑现在会回答你的问题 – WiiMaxx 2013-04-26 07:02:06