当 TreeViewItem 包含带有 DropShadowEffect 的边框时,如何应用 TreeView 突出显示颜色?

How to apply TreeView highlight color when TreeViewItem contains border with DropShadowEffect?

情况:

我想要 DropShadowEffect 围绕我的 TreeViewItem,同时我希望 TreeViewItem 在被选中时改变颜色。

问题:

为了让 DropShadowEffect 不应用于 TreeViewItem 中的文本,我需要在包含 DropShadowEffect 的边框上设置 Background="White",这似乎选择时覆盖 TreeViewItem 的突出显示。

我可以像这个例子一样正确应用 DropShadowEffect

或者我可以在选择时正确突出显示,但在文本上放置阴影,如本例所示:

问题:

有没有办法保持 TreeView 的突出显示可能性,同时防止 DropShadowEffect 被应用到 TreeViewItem 中的文本?

到目前为止我尝试了什么:

  1. 我尝试将 TreeViewItemPanel.ZIndex 设置为您在下面看到的样式,例如 <Setter Property="Panel.ZIndex" Value="5"/>
  2. 我尝试使用两个边框,它们占据相同的 space,就像这个 tutorial 一样。

增加:

我无法将白色背景应用到 TreeViewItem,因为我的边框周围有圆边,TreeViewItem 的完美正方形背景不符合这一点。

我不想将 DropShadowEffect 应用于 Expander 按钮。

最小(非)工作示例:

树视图:

<Window x:Class="TreeViewDropShadowExampl.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TreeViewDropShadowExampl"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <TreeView ItemsSource="{Binding Root}" MinWidth="100" MinHeight="100">
        <TreeView.Resources>

            <HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Children}">
                <Grid>
                    <Border BorderBrush="Gray">
                        <TextBlock Text="{Binding ID}"/>
                        <Border.Effect>
                            <DropShadowEffect Color="Gray" BlurRadius="2"/>
                        </Border.Effect>
                    </Border>
                </Grid>             
            </HierarchicalDataTemplate>

            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="Margin" Value="2" />
            </Style>

        </TreeView.Resources>
    </TreeView>
</Window>

VM:

using System.Collections.ObjectModel;

namespace TreeViewDropShadowExampl
{
    class VM 
    {
        public VM()
        {
            var root = new Node("1");
            Root.Add(root);
            for (int i = 1; i < 4; i++)
            {
                Node newNode = new Node("1." + i.ToString());
                for (int j = 1; j < 4; j++)
                {
                    newNode.Children.Add(new Node("1." + i.ToString() + "." + j.ToString()));
                }
                root.Children.Add(newNode);
            }
        }

        public ObservableCollection<Node> Root { get; set; } = new ObservableCollection<Node>();
    }
}

节点:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace TreeViewDropShadowExampl
{
    public class Node : INotifyPropertyChanged
    {
        #region WPF integration properties
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion WPF integration properties

        public Node(string id)
        {
            ID = id;
        }

        private string _id;
        public string ID
        {
            get { return _id; }
            set
            {
                _id = value;
                // Call OnPropertyChanged whenever the property is updated
                OnPropertyChanged();
            }
        }
        public ObservableCollection<Node> Children { get; set; } = new ObservableCollection<Node>();
    }
}

不要将效果应用于数据模板中的 Border,而是将效果应用于整个项目:

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
      <Style.Triggers>
        <Trigger Property="IsSelected" Value="False">
          <Setter Property="Background" Value="White"/>
        </Trigger>
      </Style.Triggers>
      <Setter Property="Effect">
        <Setter.Value>
          <DropShadowEffect Color="Gray" BlurRadius="2"/>
        </Setter.Value>
      </Setter>
    </Style>
  </TreeView.ItemContainerStyle>
</TreeView>

不要忘记从数据模板的 Border 中删除效果。
或者甚至完全删除 Border,如果你只是为了阴影效果需要它。

更新:

您也可以对项目应用白色背景。只需将其置于触发器中即可确保它仅在未选择项目时发生。

更新二:

有了所有新要求,这里是您问题的完整解决方案。

首先,可以有一个圆角的选择矩形——你只需要改变选择边框的样式。

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
      <!-- This style changes the item's border appearance -->
      <Style.Resources>
        <Style TargetType="Border">
          <Setter Property="Effect">
            <Setter.Value>
              <DropShadowEffect Color="Gray" BlurRadius="2"/>
            </Setter.Value>
          </Setter>

          <!-- Set the same corner radius here as in your data template -->
          <Setter Property="CornerRadius" Value="8"/>
        </Style>
      </Style.Resources>
      <Setter Property="Margin" Value="2"/>
    </Style>
  </TreeView.ItemContainerStyle>
  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate>
      <Grid>
        <Border x:Name="RoundedBorder" CornerRadius="8">
          <!-- Your content here -->              
        </Border>            
      </Grid>             
      <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=TreeViewItem}}" Value="False">
          <!-- Only setting the item's background when it's not selected -->
          <Setter TargetName="RoundedBorder" Property="Background" Value="White"/>
        </DataTrigger>
      </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>    
  </TreeView.ItemTemplate>
</TreeView>