none
怎样解决TreeView控件内的TreeViewItem 子节点响应事件前,父节点也跟着响应事件的问题? RRS feed

  • 问题

  • 我通过setter标签设置了IsMouseOver和PreviewMouseLeftButtonUp事件,设置了事件后,我发现只要子节点响应了事件,父节点也会跟着响应.子节点越深,响应次数越多.其他事件也是一样的, 怎么才能让父节点无法响应

    <Style x:Key="ItemStyle" TargetType="{x:Type TreeViewItem}"   >
                <Setter Property="Margin" Value="1"></Setter>
                
                <EventSetter Event="Expanded" Handler="OnExpanded"/>
                <EventSetter Event="Collapsed" Handler="OnCollapsed"/>
                <EventSetter Event="PreviewMouseLeftButtonUp" Handler="treePreviewMouseLeftButtonUp"></EventSetter>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="LawnGreen"></Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
    
        </Window.Resources>
        <Grid>
            <TreeView x:Name="treeView" HorizontalAlignment="Left" Height="172"  Margin="144,57,0,0" VerticalAlignment="Top" Width="215"
                        ItemContainerStyle="{StaticResource ItemStyle}"  >
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding TreeList}">
                        <WrapPanel>
                          
                            <TextBlock VerticalAlignment="Center" FontSize="14" Text="{Binding TreeName}" Margin="2,0,0,0"></TextBlock>
                        </WrapPanel>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
        </Grid>

    鼠标移动到名称为111的节点上,所有的父节点都会响应,点击111,会从上层响应到下层,三次


    2018年3月12日 8:02

答案

  • 你应该在treePreviewMouseLeftButtonUp方法里写上这句话:

    e.Handled = true;

    这样他就不会把消息往上层传了。

    • 已建议为答案 luornc 2018年3月14日 1:29
    • 取消建议作为答案 luornc 2018年3月14日 1:30
    • 已标记为答案 便携式家园 2018年3月15日 13:30
    2018年3月12日 10:11
  • Hi,

    >>鼠标移动到名称为111的节点上,所有的父节点都会响应,点击111,会从上层响应到下层,三次

    <Style TargetType="TreeViewItem">
        <Style.Triggers>
          <Trigger Property="local:MyTreeViewHelper.IsMouseDirectlyOverItem" Value="True">
            <Setter Property="Background" Value="Green" />
          </Trigger>
        </Style.Triggers>
      </Style>
    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);
    
                }
            }
        }
    }
    引用:https://stackoverflow.com/questions/1131161/how-can-i-make-wpf-trigger-for-ismouseover-on-treeviewitem-not-affect-all-parent

    PreviewMouseLeftButtonUp 是隧道事件,从Tree Visual根元素开始,向下遍历元素树,直到被处理或到达事件的源元素.

    使用下面的代码来中断路由。 

     e.Handled = true;

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2018年3月14日 11:48
    版主

全部回复

  • 你应该在treePreviewMouseLeftButtonUp方法里写上这句话:

    e.Handled = true;

    这样他就不会把消息往上层传了。

    • 已建议为答案 luornc 2018年3月14日 1:29
    • 取消建议作为答案 luornc 2018年3月14日 1:30
    • 已标记为答案 便携式家园 2018年3月15日 13:30
    2018年3月12日 10:11
  • Hi,

    >>鼠标移动到名称为111的节点上,所有的父节点都会响应,点击111,会从上层响应到下层,三次

    <Style TargetType="TreeViewItem">
        <Style.Triggers>
          <Trigger Property="local:MyTreeViewHelper.IsMouseDirectlyOverItem" Value="True">
            <Setter Property="Background" Value="Green" />
          </Trigger>
        </Style.Triggers>
      </Style>
    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);
    
                }
            }
        }
    }
    引用:https://stackoverflow.com/questions/1131161/how-can-i-make-wpf-trigger-for-ismouseover-on-treeviewitem-not-affect-all-parent

    PreviewMouseLeftButtonUp 是隧道事件,从Tree Visual根元素开始,向下遍历元素树,直到被处理或到达事件的源元素.

    使用下面的代码来中断路由。 

     e.Handled = true;

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    2018年3月14日 11:48
    版主