将控件样式与另一个项目动态设置的全局样式合并

时间:2011-03-07 17:42:06

标签: wpf xaml binding styles

我目前正面临一个问题。我正在使用我在codeplex上找到的WPF.Themes,它允许我改变我的应用程序的主题。

所以我导入了这个项目并且一切正常,但是对于某些控件,比如我的treeViewItem,我已经设置了它的样式,它覆盖了全局样式。

我在研究后得到以下代码,但仍然无效。

<TreeView Name="_tvTreeView" Grid.Row="1" >
       <TreeView.ItemContainerStyle>
           <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
               <EventSetter Event="MouseDoubleClick" Handler="tvTreeView_PreviewMouseDoubleClick"/>
               <EventSetter Event="MouseDown" Handler="tvTreeView_MouseDown"/>
           </Style>
       </TreeView.ItemContainerStyle>
</TreeView>

如果我在我的主项目的app.xaml的合并字典中手动添加resrouce文件,那么基于工作原理。

但WPF.Themes项目允许我动态更改主题。

  public static void ApplyTheme(this ContentControl control, string theme)
  {
      ResourceDictionary dictionary = ThemeManager.GetThemeResourceDictionary(theme);

      control.Resources.MergedDictionaries.Clear();
      if (dictionary != null)
          control.Resources.MergedDictionaries.Add(dictionary);
  }

拥有上述代码,不会合并全局样式和我的事件设置器。 如果我在app.xaml中手动引用主题,那么“BasedOn”将启动并运行,但如果我动态设置mergedDictionaries,“BasedOn”似乎不起作用。

如果没有将主题添加到app.xaml,我有没有办法让它工作。

谢谢和问候,

1 个答案:

答案 0 :(得分:1)

使用DynamicResource无法使用DynamicResource设置样式的BaseOn属性,在应用于控件时它将被密封。

您应该在全局样式更改时合并样式,请尝试以下代码:

public class Behavior
{
    #region AutoMergeStyle

    public static readonly DependencyProperty AutoMergeStyleProperty =
        DependencyProperty.RegisterAttached("AutoMergeStyle", typeof(bool), typeof(Behavior),
            new FrameworkPropertyMetadata((bool)false,
                new PropertyChangedCallback(OnAutoMergeStyleChanged)));

    public static bool GetAutoMergeStyle(DependencyObject d)
    {
        return (bool)d.GetValue(AutoMergeStyleProperty);
    }

    public static void SetAutoMergeStyle(DependencyObject d, bool value)
    {
        d.SetValue(AutoMergeStyleProperty, value);
    }

    private static void OnAutoMergeStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue == e.NewValue)
        {
            return;
        }

        Control control = d as Control;
        if (control == null)
        {
            throw new NotSupportedException("AutoMergeStyle can only used in Control");
        }

        if ((bool)e.NewValue)
        {
            Type type = d.GetType();
            control.SetResourceReference(Behavior.BaseOnStyleProperty, type);
        }
        else
        {
            control.ClearValue(Behavior.BaseOnStyleProperty);
        }
    }

    #endregion

    #region BaseOnStyle

    public static readonly DependencyProperty BaseOnStyleProperty =
        DependencyProperty.RegisterAttached("BaseOnStyle", typeof(Style), typeof(Behavior),
            new FrameworkPropertyMetadata((Style)null,
                new PropertyChangedCallback(OnBaseOnStyleChanged)));

    public static Style GetBaseOnStyle(DependencyObject d)
    {
        return (Style)d.GetValue(BaseOnStyleProperty);
    }

    public static void SetBaseOnStyle(DependencyObject d, Style value)
    {
        d.SetValue(BaseOnStyleProperty, value);
    }

    private static void OnBaseOnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue == e.NewValue)
        {
            return;
        }

        Control control = d as Control;
        if (control == null)
        {
            throw new NotSupportedException("BaseOnStyle can only used in Control");
        }

        Style baseOnStyle = e.NewValue as Style;
        Style originalStyle = GetOriginalStyle(control);
        if (originalStyle == null)
        {
            originalStyle = control.Style;
            SetOriginalStyle(control, originalStyle);
        }
        Style newStyle = originalStyle;

        if (originalStyle.IsSealed)
        {
            newStyle = new Style();
            newStyle.TargetType = originalStyle.TargetType;

            //1. Copy resources, setters, triggers
            newStyle.Resources = originalStyle.Resources;
            foreach (var st in originalStyle.Setters)
            {
                newStyle.Setters.Add(st);
            }
            foreach (var tg in originalStyle.Triggers)
            {
                newStyle.Triggers.Add(tg);
            }

            //2. Set BaseOn Style
            newStyle.BasedOn = baseOnStyle;
        }
        else
        {
            originalStyle.BasedOn = baseOnStyle;
        }

        control.Style = newStyle;
    }

    #endregion

    #region OriginalStyle

    public static readonly DependencyProperty OriginalStyleProperty =
        DependencyProperty.RegisterAttached("OriginalStyle", typeof(Style), typeof(Behavior),
            new FrameworkPropertyMetadata((Style)null));

    public static Style GetOriginalStyle(DependencyObject d)
    {
        return (Style)d.GetValue(OriginalStyleProperty);
    }

    public static void SetOriginalStyle(DependencyObject d, Style value)
    {
        d.SetValue(OriginalStyleProperty, value);
    }

    #endregion
}

将附加属性AutoMergeStyle添加到xaml:

<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
               <EventSetter Event="MouseDoubleClick" Handler="tvTreeView_PreviewMouseDoubleClick"/>
               <EventSetter Event="MouseDown" Handler="tvTreeView_MouseDown"/>
               <Setter Property="Behavior.AutoMergeStyle" Property="True"/>
</Style>