WPF TreeViewItem Context Menu Unhighlights Item
I have been having problems with this for some time now, and have come up with some less-than-desirable solutions. The problem is that when a TreeViewItem's context menu is opened, the TreeViewItem is greyed out. Is it possible for a TreeViewItem to stay highlighted while its ContextMenu is open?
The problem with the TreeViewItem greying out, is that it gives no relation to the context menu and the TreeViewItem, and it looks ugly.
Generally, the code I use for setting a context menu is this. Sometimes the context menu will be generated by the code with a PreviewRightMouseButtonDown EventSetter, but it doesn't mak开发者_StackOverflowe a difference:
<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>
So far the only solution I have found is to override the "grey" unfocused color with the focused color, but then the TreeView never seems unfocused, such as when another control is clicked on. I have had problems with ListViews as well.
WPF's default behavior is to change the TreeViewItem to gray when the ContextMenu opens, but like virtually everything else in WPF you can override this:
- Create an attached property ContextMenuOpened
- In the TreeViewItem Style, bind ContextMenuOpened to "ContextMenu.IsOpen"
- Add a trigger that changes the brush when ContextMenuOpened and IsSelected are both true
Here's the attached property:
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));
}
Here's the setter in the style:
<Setter Property="my:TreeViewCustomizer.ContextMenuOpened"
Value="{Binding ContextMenu.IsOpen, RelativeSource={RelativeSource Self}}" />
Here's the trigger:
<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>
How it works: Every time the ContextMenu opens its IsOpen property is set. The binding causes your attached property to be set on the TreeViewItem. This, combined with IsSelected, invokes the trigger which changes the foreground and background colors to make the item still appear selected.
精彩评论