我创建了一个简单的剥离ListView样式,在IsMouseOver
属性为true时突出显示一个元素。这是通过在ItemContainerStyle中触发来完成的。这很好用,xaml是这样的:
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<!--UserControl with actual content goes here-->
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<!--here is a border with the ContentPresenter inside-->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Lime"/>
</Trigger>
</Style.Triggers>
</Style>
<ListView.ItemContainerStyle>
</ListView>
但是我还希望通过右键单击显示实际元素的contextmenu时,悬停时停留的颜色会停留。基本上问题就像this one,除了我不能在那里使用(否则很好)答案:想法是添加一个触发器来检查上下文菜单何时打开:
<DataTrigger Binding="{Binding ContextMenu.IsOpen}" Value="True">
<Setter Property="Background" Value="Lime"/>
</DataTrigger>
问题是:我输入什么绑定表达式,以便在DataTemplate中设置实际内容ContextMenu.IsOpen
?我尝试了所有类似的东西,比如引用ContentPresenter.ContextMenu.IsOpen等,但都没有用。
除了使用ContextMenu.IsOpen之外,我已经在IsSelected上尝试了大量的触发器组合,在MouseLeave等上尝试了事件触发器,但也无济于事。所以第二个问题是:如果contextmenu技巧不起作用,还有另一种方法来实现这种效果吗?基本上我想要一个不支持选择任何类型的列表视图,但确实向用户显示鼠标所在的元素,无论菜单是否部分隐藏它。
答案 0 :(得分:0)
当xaml中某些东西看起来很难时,这是完全可以解决的,使用附加属性并具有可重复性的额外奖励。基本原则是将行为附加到FrameworkElement,并挂钩它的MouseEneter/Leave
事件。除此之外,还要寻找具有上下文菜单并挂钩ContextMenuOpening/Closing
事件的任何孩子。我没有博客或存储库,所以这里是代码,我想这对其他人也很有用。
public static class HasMouseOver
{
private static readonly DependencyProperty HasMouseOverBehaviorProperty = DependencyProperty.RegisterAttached(
"HasMouseOverBehavior", typeof( HasMouseOverBehavior ),
typeof( FrameworkElement ), null );
private static void AttachBehavior( FrameworkElement target )
{
var behavior = target.GetValue( HasMouseOverBehaviorProperty ) as HasMouseOverBehavior;
if( behavior == null )
{
behavior = new HasMouseOverBehavior( target, HasMouseProperty );
target.SetValue( HasMouseOverBehaviorProperty, behavior );
}
}
private static void DetachBehavior( FrameworkElement target )
{
target.ClearValue( HasMouseOverBehaviorProperty );
}
public static readonly DependencyProperty RegisterProperty = DependencyProperty.RegisterAttached(
"Register", typeof( bool ),
typeof( HasMouseOver ), new PropertyMetadata( false, RegisterPropertyChanged ) );
public static void SetRegister( FrameworkElement element, bool value )
{
element.SetValue( RegisterProperty, value );
}
public static bool GetRegister( FrameworkElement element )
{
return (bool) element.GetValue( RegisterProperty );
}
private static void RegisterPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
var target = d as FrameworkElement;
if( target == null )
return;
if( (bool) e.NewValue )
AttachBehavior( target );
else
DetachBehavior( target );
}
public static readonly DependencyProperty HasMouseProperty = DependencyProperty.RegisterAttached(
"HasMouse", typeof( bool ),
typeof( HasMouseOver ), null );
public static void SetHasMouse( FrameworkElement element, bool value )
{
element.SetValue( HasMouseProperty, value );
}
public static bool GetHasMouse( FrameworkElement element )
{
return (bool) element.GetValue( HasMouseProperty );
}
}
public class HasMouseOverBehavior
{
private readonly DependencyProperty dep;
private readonly FrameworkElement target;
private bool isReallyLeaving;
public HasMouseOverBehavior( FrameworkElement target, DependencyProperty dep )
{
this.target = target;
this.dep = dep;
target.Loaded += Loaded;
target.Unloaded += Unloaded;
target.MouseEnter += MouseEnter;
target.MouseLeave += MouseLeave;
}
private void Loaded( object sender, RoutedEventArgs e )
{
var childrenWithMenu = target.FindChildren<FrameworkElement>( u => u.ContextMenu != null );
foreach( var child in childrenWithMenu )
{
child.ContextMenuOpening += ContextMenuOpening;
child.ContextMenuClosing += ContextMenuClosing;
}
}
private void Unloaded( object sender, RoutedEventArgs e )
{
var childrenWithMenu = target.FindChildren<FrameworkElement>( u => u.ContextMenu != null );
foreach( var child in childrenWithMenu )
{
child.ContextMenuOpening -= ContextMenuOpening;
child.ContextMenuClosing -= ContextMenuClosing;
}
}
private void ContextMenuOpening( object sender, ContextMenuEventArgs e )
{
isReallyLeaving = false;
}
private void ContextMenuClosing( object sender, ContextMenuEventArgs e )
{
if( !isReallyLeaving ) //else, mouse is still over element eg upon Esc.
DoesNotHaveMouse();
}
private void MouseEnter( object sender, System.Windows.Input.MouseEventArgs e )
{
isReallyLeaving = true;
HasMouse();
}
private void MouseLeave( object sender, System.Windows.Input.MouseEventArgs e )
{
if( isReallyLeaving )
{
isReallyLeaving = false;
DoesNotHaveMouse();
}
}
private void HasMouse()
{
target.SetValue( dep, true );
}
private void DoesNotHaveMouse()
{
target.SetValue( dep, false );
}
}
在xaml:
<style>
<Setter Property="behav:HasMouseOver.Register" Value="True"/>
<Style.Triggers>
<Trigger Property="behav:HasMouseOver.HasMouse" Value="True">
...
</Trigger>
</Style.Triggers>
</style>