WPF TreeViewItem 上下文菜单取消突出显示项

Posted

技术标签:

【中文标题】WPF TreeViewItem 上下文菜单取消突出显示项【英文标题】:WPF TreeViewItem Context Menu Unhighlights Item 【发布时间】:2011-03-03 02:21:37 【问题描述】:

一段时间以来,我一直遇到这个问题,并提出了一些不太理想的解决方案。问题是当 TreeViewItem 的上下文菜单打开时,TreeViewItem 是灰色的。 TreeViewItem 是否可以在其 ContextMenu 打开时保持突出显示?

TreeViewItem 变灰的问题是它与上下文菜单和 TreeViewItem 没有关系,而且看起来很丑。

通常,我用于设置上下文菜单的代码是这样的。有时上下文菜单会由带有 PreviewRightMouseButtonDown EventSetter 的代码生成,但这并没有什么区别:

    <TreeView>
        <TreeView.Resources>
            <Style TargetType="x:Type TreeViewItem">
                <Setter Property="ContextMenu">
                    <Setter.Value>
                        <ContextMenu>
                            <MenuItem Header="Menu Item 1" />
                            <MenuItem Header="Menu Item 2" />
                        </ContextMenu>
                    </Setter.Value>
                </Setter>
            </Style>
        </TreeView.Resources>
        <TreeViewItem Header="Item 1">
            <TreeViewItem Header="Sub-Item 1"/>
        </TreeViewItem>
        <TreeViewItem Header="Item 2"></TreeViewItem>
    </TreeView>

到目前为止,我发现的唯一解决方案是用聚焦颜色覆盖“灰色”未聚焦颜色,但 TreeView 似乎永远不会聚焦,例如单击另一个控件时。我也遇到过 ListViews 的问题。

【问题讨论】:

【参考方案1】:

WPF 的默认行为是在 ContextMenu 打开时将 TreeViewItem 更改为灰色,但与 WPF 中的几乎所有其他内容一样,您可以覆盖它:

    创建附加属性 ContextMenuOpened 在 TreeViewItem 样式中,将 ContextMenuOpened 绑定到“ContextMenu.IsOpen” 添加一个触发器,当 ContextMenuOpened 和 IsSelected 都为 true 时更改画笔

这是附加的属性:

public class TreeViewCustomizer : DependencyObject

  public static bool GetContextMenuOpened(DependencyObject obj)  return (bool)obj.GetValue(ContextMenuOpenedProperty); 
  public static void SetContextMenuOpened(DependencyObject obj, bool value)  obj.SetValue(ContextMenuOpenedProperty, value); 
  public static readonly DependencyProperty ContextMenuOpenedProperty = DependencyProperty.RegisterAttached("ContextMenuOpened", typeof(bool), typeof(TreeViewCustomizer));

这是样式中的二传手:

<Setter Property="my:TreeViewCustomizer.ContextMenuOpened"
        Value="Binding ContextMenu.IsOpen, RelativeSource=RelativeSource Self" />

这里是触发器:

<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition Property="IsSelected" Value="true"/>
    <Condition Property="my:TreeViewCustomizer.ContextMenuOpened" Value="true"/>
  </MultiTrigger.Conditions>
  <Setter TargetName="Bd"
          Property="Background"
          Value="DynamicResource x:Static SystemColors.HighlightBrushKey"/>
  <Setter Property="Foreground"
          Value="DynamicResource x:Static SystemColors.HighlightTextBrushKey"/>
</MultiTrigger>

它是如何工作的:每次 ContextMenu 打开时,它的 IsOpen 属性都会被设置。绑定会导致在 TreeViewItem 上设置您的附加属性。这与 IsSelected 相结合,调用更改前景色和背景色的触发器,以使项目仍显示为选中状态。

【讨论】:

太棒了。我自己永远不会想到这一点。不过有一件事:背景设置不正确,但前景设置正确。我感觉它与无法编译的 TargetName="Bd" 有关。 我的回答假设您的自定义 TreeViewItem ControlTemplate 是默认 TreeViewItem ControlTemplate 的编辑副本。 “Bd”是边框的默认 TreeViewItem ControlTemplate 中使用的名称。如果为 TreeViewItem 构建了一个完全自定义的 ControlTemplate 而不是复制系统并编辑它,您的模板中可能根本没有边框,或者它可能被命名为不同的东西。在这种情况下,您可能需要不同的 TargetName 来设置项目的背景颜色。 我刚刚意识到我可能假设太多:也许您根本没有为 TreeViewItem 创建自定义 ControlTemplate。在那种情况下,除了替换资源之外,我看不到任何影响模板内边框颜色的方法,正如您所指出的,它具有某种全局范围。因此,我认为您将需要使用自定义 ControlTemplate。在 Blend 中,只需右键单击控件并从上下文菜单中选择 Edit Template -> Edit A Copy,然后将我的 MultiTrigger 添加到模板中触发器列表的底部。 好吧,希望它不会变成那样,但它必须这样做(不幸的是,我没有 Blend,但我之前找到了默认模板)。再次感谢。 嘿,我怎样才能通过 C# 而不是通过 XAML 来实现这一点,因为我已经通过 .cs 文件创建了树视图控件。

以上是关于WPF TreeViewItem 上下文菜单取消突出显示项的主要内容,如果未能解决你的问题,请参考以下文章

wpf treeview中动态创建的treeViewItem如何用右键触发菜单?

如何在 wpf 中的 treeviewitem 中访问 treeviewitem?

禁用WPF TreeView(或TreeViewItem)选择?

C# WPF TreeViewItem MouseDoubleClick 事件在 TreeViewItem 与 TreeViewItem.Header

WPF 如果选中它,则只保留一个 TreeViewItem 展开,折叠其他的,除非它是 Selected TreeViewItem 的祖先

在wpf中将treeviewitem显示为网格行