【问题标题】:ItemContainerStyle cleared by loading custom style通过加载自定义样式清除 ItemContainerStyle
【发布时间】:2021-10-14 09:00:00
【问题描述】:

所以,我在使用自定义 treeviewitem:s 创建自定义树视图时遇到了这个问题,其中 ItemContainerStyle 通过从自定义样式加载样式被清除。

它是这样工作的。我有基于 TreeViewItem 的自定义 MyTreeViewItem。

  <TreeViewItem x:Class="UI.MyTreeViewItem"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
    
        <TreeViewItem.Resources>
    
            <Style x:Key="MyTreeViewItemStyle" TargetType="TreeViewItem">
                <Setter Property="Background" Value="#AEFFC1" />
            </Style>
    
        </TreeViewItem.Resources>
    
    </TreeViewItem>

如您所见,我在这里只设置了一个简单的颜色,以确保它自己的样式有效。除非我在后面的代码中这样做,否则这将永远不会加载。

编辑:我知道不需要将诸如着色之类的内容放在这里,因为这里本来是打算放一个模板的。自从注意到真正起作用以来,我只是把它剥离到骨头上,以确保我放了一些超级简单的东西,我知道它应该可以工作,以防万一它是因为它本身的模板。

    public partial class MyTreeViewItem : TreeViewItem
    {
        public MyTreeViewItem()
        {
            InitializeComponent();
            this.Loaded += MyTreeViewItem_Loaded;          
        }

        private void MyTreeViewItem_Loaded(object sender, RoutedEventArgs e)
        {
           this.Style = Resources["MyTreeViewItemStyle"] as Style;
        }
   }

这很有效。已经多次将它与其他控件一起使用,以便为需要加载的控件自定义样式,而不必费心一遍又一遍地“重新设置样式”。

我怎么会遇到这个问题。这就是 ItemContainerStyle 用于这种自定义样式控制器的时候。

<local:BaseTreeView x:Class="My.Navigator.NavigatorTreeView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:ui="clr-namespace:UI;assembly=BaseCode" 
             d:DesignHeight="450" d:DesignWidth="800">

<ui:MyTreeView ItemsSource="{Binding Path=Nodes}">   
...

        <ui:MyTreeView.ItemContainerStyle>
            <Style TargetType="{x:Type ui:MyTreeViewItem}">
                <Setter Property="FontWeight" Value="Normal" />
                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />

                <EventSetter Event="Selected" Handler="TreeView_SelectedItemChanged" />
                <EventSetter Event="Expanded" Handler="TreeView_NodeExpanded" />
                <EventSetter Event="Collapsed" Handler="TreeView_NodeCollapsed" />

                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ui:MyTreeView.ItemContainerStyle>
    </ui:MyTreeView>
</local:BaseTreeView>

您在上面看到的这个ui:MyTreeView.ItemContainerStyle 在样式加载后将被this.Style = Resources["MyTreeViewItemStyle"] as Style; 完全忽略在MyTreeViewItem_Loaded 中。 这意味着这些 Setter、EventSetter 和 Trigger 根本不会触发,因为它们仍然需要能够作为附加规则添加。

如何解决这个问题,以便可以加载自定义控件中的预定义样式,并且通过使用此控件,您仍然可以连接独特的规则,例如上面没有预定义的否决它们?

【问题讨论】:

    标签: c# wpf wpf-style itemcontainerstyle


    【解决方案1】:

    目前还不清楚你为什么要做你正在做的事情。我只能说,在使用来自TreeView.ItemContainerStyle 的值初始化控件之后,通过显式分配它来覆盖Style 值。

    通常,在 UserControl 上,您会在元素上本地设置属性:

    <TreeViewItem x:Class="UI.MyTreeViewItem" 
                  ...
                  d:DesignHeight="450" d:DesignWidth="800"
                  Background="#AEFFC1">
    </TreeViewItem>
    

    或在代码隐藏中:

    private void MyTreeViewItem_Loaded(object sender, RoutedEventArgs e)  
    {
      this.Background = 
        new SolidColorBrush(ColorConverter.ConvertFromString("#AEFFC1"));
     }
    

    在编写自定义 Control 时,您将在 Generic.xaml 中提供默认 Style。这是最好的解决方案,因为它允许为控件设置样式(允许自定义样式覆盖默认 Style 提供的默认值)。外部样式被隐式合并。您应该更喜欢自定义控件而不是 UserControl。

    您当前的代码不允许样式化,因为您强制覆盖自定义 Style 提供的值:

    // Overwrite previous property value.
    this.Style = someValue;
    

    这是编程 101,一年级:赋值总是覆盖变量的旧值(引用)。

    假设您知道自己在做什么并且不想使用上述解决方案之一,则必须使用 Style.BasedOn 属性手动合并两种样式:

    private void MyTreeViewItem_Loaded(object sender, RoutedEventArgs e)
    {
      var defaultStyle = Resources["MyTreeViewItemStyle"] as Style;
      defaultStyle.BasedOn = this.ItemContainerStyle;
      this.Style = defaultStyle;
    }
    

    见:Control authoring overview: Models for Control Authoring

    【讨论】:

    • 啊,它缺少合并。谢谢!是的,我完全意识到可以通过其他方式设置像背景这样的样式。我刚刚删除了以前打算为自定义控件加载的完整模板。然而,由于没有什么真正起作用,我不知道是因为它自己的模板还是其他地方,我只是消除并尽可能简单地尝试自己的概念。无论如何,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2012-02-17
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 2016-09-15
    相关资源
    最近更新 更多