Select TreeView Node on right click before displaying ContextMenu

后端 未结 11 1962
鱼传尺愫
鱼传尺愫 2020-11-29 19:39

I would like to select a WPF TreeView Node on right click, right before the ContextMenu displayed.

For WinForms I could use code like this Find node clicked under co

相关标签:
11条回答
  • 2020-11-29 20:19

    Almost Right, but you need to watch out for non visuals in the tree, (like a Run, for instance).

    static DependencyObject VisualUpwardSearch<T>(DependencyObject source) 
    {
        while (source != null && source.GetType() != typeof(T))
        {
            if (source is Visual || source is Visual3D)
            {
                source = VisualTreeHelper.GetParent(source);
            }
            else
            {
                source = LogicalTreeHelper.GetParent(source);
            }
        }
        return source; 
    }
    
    0 讨论(0)
  • 2020-11-29 20:21

    If you want to stay within the MVVM pattern you could do the following:

    View:

    <TreeView x:Name="trvName" ItemsSource="{Binding RootElementListView}" Tag="{Binding ClickedTreeElement, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type models:YourTreeElementClass}" ItemsSource="{Binding Path=Subreports}">
                <TextBlock Text="{Binding YourTreeElementDisplayProperty}" PreviewMouseRightButtonDown="TreeView_PreviewMouseRightButtonDown"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
    

    Code Behind:

    private void TreeView_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (sender is TextBlock tb && tb.DataContext is YourTreeElementClass te)
        {
            trvName.Tag = te;
        }
    }
    

    ViewModel:

    private YourTreeElementClass _clickedTreeElement;
    
    public YourTreeElementClass ClickedTreeElement
    {
        get => _clickedTreeElement;
        set => SetProperty(ref _clickedTreeElement, value);
    }
    

    Now you could either react to the ClickedTreeElement property change or you could use a command which internally works with the ClickedTreeElement.

    Extended View:

    <UserControl ...
                 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
        <TreeView x:Name="trvName" ItemsSource="{Binding RootElementListView}" Tag="{Binding ClickedTreeElement, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseRightButtonUp">
                    <i:InvokeCommandAction Command="{Binding HandleRightClickCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate DataType="{x:Type models:YourTreeElementClass}" ItemsSource="{Binding Path=Subreports}">
                    <TextBlock Text="{Binding YourTreeElementDisplayProperty}" PreviewMouseRightButtonDown="TreeView_PreviewMouseRightButtonDown"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </UserControl>
    
    0 讨论(0)
  • 2020-11-29 20:25

    Depending on the way the tree was populated, the sender and the e.Source values may vary.

    One of the possible solutions is to use e.OriginalSource and find TreeViewItem using the VisualTreeHelper:

    private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        TreeViewItem treeViewItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);
    
        if (treeViewItem != null)
        {
            treeViewItem.Focus();
            e.Handled = true;
        }
    }
    
    static TreeViewItem VisualUpwardSearch(DependencyObject source)
    {
        while (source != null && !(source is TreeViewItem))
            source = VisualTreeHelper.GetParent(source);
    
        return source as TreeViewItem;
    }
    
    0 讨论(0)
  • 2020-11-29 20:26

    In XAML, add a PreviewMouseRightButtonDown handler in XAML:

        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <!-- We have to select the item which is right-clicked on -->
                <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="TreeViewItem_PreviewMouseRightButtonDown"/>
            </Style>
        </TreeView.ItemContainerStyle>
    

    Then handle the event like this:

        private void TreeViewItem_PreviewMouseRightButtonDown( object sender, MouseEventArgs e )
        {
            TreeViewItem item = sender as TreeViewItem;
            if ( item != null )
            {
                item.Focus( );
                e.Handled = true;
            }
        }
    
    0 讨论(0)
  • 2020-11-29 20:26

    You can select it with the on mouse down event. That will trigger the select before the context menu kicks in.

    0 讨论(0)
提交回复
热议问题