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

发布于 2024-10-20 11:32:29 字数 1291 浏览 1 评论 0原文

我目前面临一个问题。我正在使用在 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 的情况下使其工作。

谢谢和问候,

I currently am facing 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,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

猫七 2024-10-27 11:32:29

style的BaseOn属性不能用DynamicResource设置,用StaticResource设置,应用于控件时会被密封。

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

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>

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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文