【问题标题】:WPF TreeViewItem Context Menu Unhighlights ItemWPF TreeViewItem 上下文菜单取消突出显示项
【发布时间】: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 的问题。

【问题讨论】:

    标签: c# wpf treeview


    【解决方案1】:

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

    1. 创建附加属性 ContextMenuOpened
    2. 在 TreeViewItem 样式中,将 ContextMenuOpened 绑定到“ContextMenu.IsOpen”
    3. 添加一个触发器,当 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 文件创建了树视图控件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多