如何在TreeViewItem上为IsMouseOver创建WPF触发器不会影响moused-over控件的所有父项?

时间:2009-07-15 12:39:40

标签: wpf treeview triggers

我明白为什么会这样。父TreeViewItem的边界框包含其子边框,因此当我在TreeViewItem上进行鼠标悬停时,树中的所有父节点也会被覆盖。除了我应该使用的IsMouseOver之外还有什么东西吗?

4 个答案:

答案 0 :(得分:5)

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>

where 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 :(得分:1)

好的 - 我遇到了你的问题,我浪费了将近一天的时间来解决它... 您需要做的就是从后面的代码中解决这个问题。 例如:

在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;
}

应该这样做。祝你好运!

答案 2 :(得分:0)

link为我提供了一个很好的解决方案。

有效地,您可以覆盖ControlTemplate并将SourceName设置器的IsMouseOver指定为TreeViewItem的标头部分。因此,是的,从技术上讲,您将鼠标悬停在子TreeViewItems和父<table #table mat-table [dataSource]="dataSource"> <ng-container matColumnDef="empty1"> <th mat-header-cell *matHeaderCellDef style="text-align: center"> </th> </ng-container> <ng-container matColumnDef="empty2"> <th mat-header-cell *matHeaderCellDef style="text-align: center"> </th> </ng-container> <ng-container matColumnDef="identifier"> <th mat-header-cell *matHeaderCellDef colspan="3" style="text-align: center"> Column Label </th> </ng-container> </table> 上,但是触发器仅针对光标位于标题上方的项目触发。

答案 3 :(得分:-1)

这听起来像是正确的事件。您可以做的一件事就是阻止MouseOver事件检查TreeViewItems的MouseOver事件。如果您的RoutedEventArgs.OriginalSource不等于父级,只需手动返回并管理您的事件处理程序。

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