Как сделать так, чтобы WPF Trigger для IsMouseOver на TreeViewItem НЕ влиял на всех родителей элемента управления moused-over? - PullRequest
6 голосов
/ 15 июля 2009

Я понимаю, почему это происходит. Ограничительная рамка родительского TreeViewItem включает в себя дочерние ограничивающие рамки, поэтому, когда я нахожусь над TreeViewItem, все его родители в дереве также накладываются Есть ли что-то кроме IsMouseOver, которое я должен использовать?

Ответы [ 3 ]

5 голосов
/ 15 июля 2009

http://blogs.msdn.com/mikehillberg/archive/2006/09/21/MyTreeViewHelperIsMouseDirectlyOverItem.aspx

эта ссылка решила проблему, я не пробовал идею оригинального источника.

  <Style TargetType="TreeViewItem">
    <Style.Triggers>
      <Trigger Property="local:MyTreeViewHelper.IsMouseDirectlyOverItem" Value="True">
        <Setter Property="Background" Value="Green" />
      </Trigger>
    </Style.Triggers>
  </Style>

где local: MyTreeViewHelper.IsMouseDirectlyOverItem является прикрепленным свойством

public static class MyTreeViewHelper
{
    //
    // The TreeViewItem that the mouse is currently directly over (or null).
    //
    private static TreeViewItem _currentItem = null;

    //
    // IsMouseDirectlyOverItem:  A DependencyProperty that will be true only on the 
    // TreeViewItem that the mouse is directly over.  I.e., this won't be set on that 
    // parent item.
    //
    // This is the only public member, and is read-only.
    //

    // The property key (since this is a read-only DP)
    private static readonly DependencyPropertyKey IsMouseDirectlyOverItemKey =
        DependencyProperty.RegisterAttachedReadOnly("IsMouseDirectlyOverItem",
                                            typeof(bool),
                                            typeof(MyTreeViewHelper),
                                            new FrameworkPropertyMetadata(null, new CoerceValueCallback(CalculateIsMouseDirectlyOverItem)));

    // The DP itself
    public static readonly DependencyProperty IsMouseDirectlyOverItemProperty =
        IsMouseDirectlyOverItemKey.DependencyProperty;

    // A strongly-typed getter for the property.
    public static bool GetIsMouseDirectlyOverItem(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsMouseDirectlyOverItemProperty);
    }

    // A coercion method for the property
    private static object CalculateIsMouseDirectlyOverItem(DependencyObject item, object value)
    {
        // This method is called when the IsMouseDirectlyOver property is being calculated
        // for a TreeViewItem.  

        if (item == _currentItem)
            return true;
        else
            return false;
    }

    //
    // UpdateOverItem:  A private RoutedEvent used to find the nearest encapsulating
    // TreeViewItem to the mouse's current position.
    //

    private static readonly RoutedEvent UpdateOverItemEvent = EventManager.RegisterRoutedEvent(
        "UpdateOverItem", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyTreeViewHelper));

    //
    // Class constructor
    //

    static MyTreeViewHelper()
    {
        // Get all Mouse enter/leave events for TreeViewItem.
        EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.MouseEnterEvent, new MouseEventHandler(OnMouseTransition), true);
        EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.MouseLeaveEvent, new MouseEventHandler(OnMouseTransition), true);

        // Listen for the UpdateOverItemEvent on all TreeViewItem's.
        EventManager.RegisterClassHandler(typeof(TreeViewItem), UpdateOverItemEvent, new RoutedEventHandler(OnUpdateOverItem));
    }


    //
    // OnUpdateOverItem:  This method is a listener for the UpdateOverItemEvent.  When it is received,
    // it means that the sender is the closest TreeViewItem to the mouse (closest in the sense of the tree,
    // not geographically).

    static void OnUpdateOverItem(object sender, RoutedEventArgs args)
    {
        // Mark this object as the tree view item over which the mouse
        // is currently positioned.
        _currentItem = sender as TreeViewItem;

        // Tell that item to re-calculate the IsMouseDirectlyOverItem property
        _currentItem.InvalidateProperty(IsMouseDirectlyOverItemProperty);

        // Prevent this event from notifying other tree view items higher in the tree.
        args.Handled = true;
    }

    //
    // OnMouseTransition:  This method is a listener for both the MouseEnter event and
    // the MouseLeave event on TreeViewItems.  It updates the _currentItem, and updates
    // the IsMouseDirectlyOverItem property on the previous TreeViewItem and the new
    // TreeViewItem.

    static void OnMouseTransition(object sender, MouseEventArgs args)
    {
        lock (IsMouseDirectlyOverItemProperty)
        {
            if (_currentItem != null)
            {
                // Tell the item that previously had the mouse that it no longer does.
                DependencyObject oldItem = _currentItem;
                _currentItem = null;
                oldItem.InvalidateProperty(IsMouseDirectlyOverItemProperty);
            }

            // Get the element that is currently under the mouse.
            IInputElement currentPosition = Mouse.DirectlyOver;

            // See if the mouse is still over something (any element, not just a tree view item).
            if (currentPosition != null)
            {
                // Yes, the mouse is over something.
                // Raise an event from that point.  If a TreeViewItem is anywhere above this point
                // in the tree, it will receive this event and update _currentItem.

                RoutedEventArgs newItemArgs = new RoutedEventArgs(UpdateOverItemEvent);
                currentPosition.RaiseEvent(newItemArgs);

            }
        }
    }
}
1 голос
/ 19 июля 2017

Хорошо, у меня была ваша проблема, и я потратил почти день на ее решение Все, что вам нужно сделать, это позаботиться об этом из кода. Например:

В XAML:

<TreeViewItem Header="{Binding diskName}" 
Background="Transparent" Mouse.MouseEnter="changeBackground">

А в файле cs:

private void changeBackground(object sender, MouseEventArgs e)
{
        TreeViewItem t = (TreeViewItem)sender; 
        t.Background = (SolidColorBrush)(new BrushConverter().ConvertFrom("#CCE8FF"));
        e.Handled = false;
}

Это должно сделать это. Удачи!

0 голосов
/ 15 июля 2009

Звучит как правильное событие. Единственное, что вы можете сделать, чтобы предотвратить события MouseOver, - это проверить события MouseOver для ваших TreeViewItems. Если ваш RoutedEventArgs.OriginalSource не равен родительскому, просто верните обработчики событий и управляйте ими вручную.

public void TreeViewItem_MouseOver(object sender, RoutedEventArgs e)
{
  if (sender != e.OriginalSource) return;
}
...