2012-01-06 9 views
0

Я создал простой, лишенный стиль ListView, который выделяет элемент, когда свойство IsMouseOver является истинным. Это делается путем запуска в ItemContainerStyle. Это прекрасно работает и XAML, как это:Эффект Hover в ItemContainerStyle, который находится при открытии контекстного меню

<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> 

Вопрос заключается в том: что выражение привязки делать Я вхожу, чтобы выяснить, что ContextMenu.IsOpen на фактическом содержимом, установленном в DataTemplate? Я пробовал всевозможные вещи, например, ссылаясь на ContentPresenter.ContextMenu.IsOpen и т. Д., Но никто не работал.

Помимо использования ContextMenu.IsOpen, я уже пробовал множество комбинаций триггеров на IsSelected, триггеры событий на MouseLeave и т. Д., Но также безрезультатно. Итак, второй вопрос: если трюк contextmenu не работает, есть ли другой способ получить этот эффект? В принципе, мне нужен вид списка, который не поддерживает выбор какого-либо вида, но показывает пользователя, в котором элемент мыши находится, независимо от того, какое меню частично скрывает или нет.

ответ

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> 
Смежные вопросы