开发者

Merge control style with global style set by another project dynamically

开发者 https://www.devze.com 2023-02-15 13:34 出处:网络
I currently am fac开发者_JAVA百科ing a problem. I am using WPF.Themes which i found on codeplex, it allows me to change my application\'s theme.

I currently am fac开发者_JAVA百科ing a problem. I am using WPF.Themes which i found on codeplex, it allows me to change my application's theme.

So I imported the project and got it all working fine, but for some control, say my treeViewItem, I had style already set to it which it overrides the global styles.

I have the following code after research but still won't work.

<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>

The based on works if I manully add the resrouce file in the merge dictionary of app.xaml of my Main Project.

But WPF.Themes project allow me to change theme dynamically by doing this.

  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);
  }

Having the above code, does not merge the global styles and my event setters. If I manually reference the theme in app.xaml then "BasedOn" would kick in and work, but "BasedOn" don't seem to work if I set the mergedDictionaries dynamically.

Is there a way I can get this to work without adding the theme to app.xaml.

Thanks and Regards,


The BaseOn property of style cannot be set with DynamicResource, with StaticResource, it will be sealed when applied to control.

You should merge the style when global style changed, try these codes:

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
}

Add attached property AutoMergeStyle to 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>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号