【问题标题】:WPF TreeView Change ToggleButton's background colorWPF TreeView 更改切换按钮的背景颜色
【发布时间】:2021-02-10 18:51:12
【问题描述】:

我有这个当前正在工作的用户控件 xaml:

<UserControl ...>
 <TreeView Background="Yellow" ... >
    <TreeView.Resources >
        <HierarchicalDataTemplate ... >
            <Grid Name="Header" Background="Green" ... >
            </Grid>
        </HierarchicalDataTemplate>     

        <DataTemplate ... >
            <Grid Name="MultipleItems">
            </Grid>
        </DataTemplate>
    </TreeView.Resources>  
  </TreeView>
</UserControl>

我只需要更改 TreeView 切换按钮的背景颜色 类似于绿色的网格标题。切换按钮的默认背景颜色类似于 TreeView 的黄色。

当我尝试在 TreeView 标记之后和 TreeView.Resources 标记之前添加这些代码时,我遇到了错误:

<TreeViewItem>
   <TreeViewItem.Template>
      <ControlTemplate TargetType="TreeViewItem">
         <Grid>
            <ToggleButton>
               <ToggleButton.Style>
                  <Style TargetType="ToggleButton">
                     <Setter Property="Background" Value="Green"/>
                  </Style>
               </ToggleButton.Style>
            </ToggleButton>
         </Grid>
      </ControlTemplate>
   </TreeViewItem.Template>
</TreeViewItem>

错误是“Items collection must be empty before using ItemsSource.”。 如何成功更改切换按钮的背景颜色? 我上面的修复不是正确的方法吗?请让我知道是否有其他方法 这样做以及如何做到这一点。

附加信息: 即使添加这个简单的行也会发生错误。

<TreeViewItem></TreeViewItem>

【问题讨论】:

    标签: wpf xaml treeview controltemplate togglebutton


    【解决方案1】:

    您的某些代码用省略号隐藏,但我猜您正在尝试将&lt;TreeViewItem/&gt; 添加到TreeView.Items,而已经指定了TreeView.ItemSource 属性。使用 ItemsControl 时,您必须使用 Items 属性或 ItemsSource 属性。

    请查看this SO answer了解更多详情。

    【讨论】:

      【解决方案2】:

      为了更改控件的外观或视觉状态,您必须更改其样式或控件模板。这些比你想象的要复杂得多。您提供的控件模板缺少大部分状态和所需部分(模板中的控件)才能正常工作。您可以查看所需的部分和状态in the documentation。

      您可以extract the default ones using Blend or Visual Studio 并根据您的需要调整它们,而不是从头开始为控件创建控件模板和样式。在大多数情况下,您将复制大量代码,并且满足您的要求所需的更改很小,但没有其他方法,因为您不能像使用样式那样将控件模板基于其他控件模板。

      错误是“在使用 ItemsSource 之前,Items 集合必须为空。”

      您收到此错误是因为您在 TreeView 中设置了 TreeViewItem。它将将此项目添加为内容,但由于您可能已经在其他地方设置了ItemsSource,它会引发错误,因为您不能同时执行这两个操作。相反,您可以通过 ItemContainerStyle 属性设置自定义样式,例如像这样内联:

      <TreeView ItemsSource="{Binding MyTreeViewNodes}">
         <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
               <Setter Property="Template">
                  <Setter.Value>
                     <ControlTemplate TargetType="TreeViewItem">
                        <!-- ...your control template -->
                     </ControlTemplate>
                  </Setter.Value>
               </Setter>
            </Style>
         </TreeView.ItemContainerStyle>
         <!-- ...other tree view definitions. -->
      </TreeView>
      

      当然,您也可以使用StaticResource 或DynamicResource 引用命名样式。我希望你能明白,但无论哪种方式,你的控制模板都不完整,无法正常工作。

      我已经提取了默认样式,包括TreeViewItem 的控件模板并对其进行了调整。您必须将所有这些样式复制到范围内的资源字典或应用程序资源中。

      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Background" Color="Green"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF818181"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="#FFFFFFFF"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Background" Color="Green"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Stroke" Color="#FF27C7F7"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Fill" Color="#FFCCEEFB"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Background" Color="Green"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Stroke" Color="#FF262626"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Fill" Color="#FF595959"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Background" Color="Green"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Stroke" Color="#FF1CC4F7"/>
      <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Fill" Color="#FF82DFFB"/>
      <PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
      
      <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
         <Setter Property="Focusable" Value="False"/>
         <Setter Property="Width" Value="16"/>
         <Setter Property="Height" Value="16"/>
         <Setter Property="Template">
            <Setter.Value>
               <ControlTemplate TargetType="{x:Type ToggleButton}">
                  <Border x:Name="ExpandBorder" Background="{StaticResource TreeViewItem.TreeArrow.Static.Background}" Height="16" Padding="5,5,5,5" Width="16">
                     <Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
                        <Path.RenderTransform>
                           <RotateTransform Angle="135" CenterY="3" CenterX="3"/>
                        </Path.RenderTransform>
                     </Path>
                  </Border>
                  <ControlTemplate.Triggers>
                     <Trigger Property="IsChecked" Value="True">
                        <Setter Property="RenderTransform" TargetName="ExpandPath">
                           <Setter.Value>
                              <RotateTransform Angle="180" CenterY="3" CenterX="3"/>
                           </Setter.Value>
                        </Setter>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
                        <Setter Property="Background" TargetName="ExpandBorder" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Background}"/>
                     </Trigger>
                     <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
                        <Setter Property="Background" TargetName="ExpandBorder" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Background}"/>
                     </Trigger>
                     <MultiTrigger>
                        <MultiTrigger.Conditions>
                           <Condition Property="IsMouseOver" Value="True"/>
                           <Condition Property="IsChecked" Value="True"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
                        <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
                        <Setter Property="Background" TargetName="ExpandBorder" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Background}"/>
                     </MultiTrigger>
                  </ControlTemplate.Triggers>
               </ControlTemplate>
            </Setter.Value>
         </Setter>
      </Style>
      
      <Style x:Key="TreeViewItemFocusVisual">
         <Setter Property="Control.Template">
            <Setter.Value>
               <ControlTemplate>
                  <Rectangle/>
               </ControlTemplate>
            </Setter.Value>
         </Setter>
      </Style>
      
      <Style x:Key="TreeViewItemContainerStyle" TargetType="{x:Type TreeViewItem}">
         <Setter Property="Background" Value="Transparent"/>
         <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
         <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
         <Setter Property="Padding" Value="1,0,0,0"/>
         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
         <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
         <Setter Property="Template">
            <Setter.Value>
               <ControlTemplate TargetType="{x:Type TreeViewItem}">
                  <Grid>
                     <Grid.ColumnDefinitions>
                        <ColumnDefinition MinWidth="19" Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                     </Grid.ColumnDefinitions>
                     <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition/>
                     </Grid.RowDefinitions>
                     <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
                     <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                     </Border>
                     <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
                  </Grid>
                  <ControlTemplate.Triggers>
                     <Trigger Property="IsExpanded" Value="false">
                        <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                     </Trigger>
                     <Trigger Property="HasItems" Value="false">
                        <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
                     </Trigger>
                     <Trigger Property="IsSelected" Value="true">
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                     </Trigger>
                     <MultiTrigger>
                        <MultiTrigger.Conditions>
                           <Condition Property="IsSelected" Value="true"/>
                           <Condition Property="IsSelectionActive" Value="false"/>
                        </MultiTrigger.Conditions>
                        <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                     </MultiTrigger>
                     <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                     </Trigger>
                  </ControlTemplate.Triggers>
               </ControlTemplate>
            </Setter.Value>
         </Setter>
         <Style.Triggers>
            <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
               <Setter Property="ItemsPanel">
                  <Setter.Value>
                     <ItemsPanelTemplate>
                        <VirtualizingStackPanel/>
                     </ItemsPanelTemplate>
                  </Setter.Value>
               </Setter>
            </Trigger>
         </Style.Triggers>
      </Style>
      

      如您所见,这非常复杂。项目本身中有TreeViewItem 的样式、焦点样式以及ToggleButton 的样式。我只修改了名为ExpandBorder 的Border,并根据触发器中的项目状态为其分配了初始背景和背景。

      如果你想适应不同状态的颜色,你只需要改变这些画笔:

      • TreeViewItem.TreeArrow.Static.Background
      • TreeViewItem.TreeArrow.MouseOver.Background
      • TreeViewItem.TreeArrow.Static.Checked.Background
      • TreeViewItem.TreeArrow.MouseOver.Checked.Background

      要应用新的TreeViewItem 样式,请将其引用为ItemContainerStyle。

      <TreeView ItemsSource="{Binding MyTreeViewNodes}" ItemContainerStyle="{StaticResource TreeViewItemContainerStyle}">
      

      如果您省略相应样式的键,您也可以将该样式应用于范围内的所有TreeViewItems,这使其成为隐式样式。

      <Style TargetType="{x:Type TreeViewItem}">
      

      【讨论】:

        猜你喜欢
        • 2011-03-05
        • 2017-08-19
        • 2013-06-07
        • 2012-09-05
        • 2021-04-27
        • 2011-12-01
        • 1970-01-01
        • 2015-06-04
        • 1970-01-01
        相关资源
        最近更新 更多