如何在 WPF 树视图中实现选择树节点的命令

HowTo implement commands for selection of treenodes in WPF treeview

再一次,我对 WPF 树视图有点迷路了。
我用一些数据填充了树视图,我想在单击节点并在该命令中获取其值时触发命令。

我的 treeview-xaml 看起来像这样:

        <TreeView DataContext="{Binding ProjectTree}" ItemsSource="{Binding ProjectNode}" DockPanel.Dock="Left" Margin="0 0 2 0" x:Name="ProjectTree" Grid.Column="0">
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
                <Setter Property="FontWeight" Value="Normal"/>
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>

        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <StackPanel Orientation="Horizontal">
                    <Image Margin="3" Source="{Binding ItemType, Converter={x:Static misc:TreeItemImageConverter.Instance }}" Width="20" />
                    <TextBlock VerticalAlignment="Center" Text="{Binding Name}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

如何在点击此处的 treeviewitem 时触发命令?

解决方案

经过一些实验,它对我有用:

xaml:

    <TreeView DataContext="{Binding ProjectTree}" ItemsSource="{Binding ProjectNode}" DockPanel.Dock="Left" 
              x:Name="ProjectTree" Margin="0 0 2 0" Grid.Column="0">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectedItemChanged">
                <i:InvokeCommandAction Command="{Binding TreeNodeSelected}" 
                                       CommandParameter="{Binding ElementName=ProjectTree, Path=SelectedItem}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
                <Setter Property="FontWeight" Value="Normal"/>
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="FontWeight" Value="Bold"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>

        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                <StackPanel Orientation="Horizontal">
                    <Image Margin="3" Source="{Binding ItemType, Converter={x:Static misc:TreeItemImageConverter.Instance }}" Width="20" />
                    <TextBlock VerticalAlignment="Center" Text="{Binding Name}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

在树视图的视图模型中:
C#

    public RelayCommand TreeNodeSelected { get; private set; }

    readonly ReadOnlyCollection<PlcAddressViewModel> _rootNodes;
    readonly PlcAddressViewModel _rootAddress;

    #region Constructor
    public ProjectTreeviewModel(PlcAddress rootAddress)
    {
        _rootAddress = new PlcAddressViewModel(rootAddress);

        _rootNodes = new ReadOnlyCollection<PlcAddressViewModel>(
            new PlcAddressViewModel[]
            {
                _rootAddress
            });

        TreeNodeSelected = new RelayCommand(ExecuteTreeNodeSelected, canExecuteMethod);
    }
    #endregion Constructor

    #region Commands
    private bool canExecuteMethod(object parameter)
    {
        return true;
    }
    private void ExecuteTreeNodeSelected(object parameter)
    {
        PlcAddressViewModel selectedNode = (PlcAddressViewModel)parameter;
                Console.WriteLine("Found this node: " + selectedNode.Name);

        return;
    }
    #endregion Commands

感谢@mm8 和@BionicCode

您可以使用交互触发器处理事件,例如 SelectedItemChanged

<TreeView DataContext="{Binding ProjectTree}"
            ItemsSource="{Binding ProjectNode}" 
            x:Name="ProjectTree"
            xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectedItemChanged" >
            <i:InvokeCommandAction Command="{Binding MouseEnterCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <TreeView.ItemContainerStyle>
        ...
    </TreeView.ItemContainerStyle>
    ...
</TreeView>

Handling events in an MVVM WPF application

How to add System.Windows.Interactivity to project?

但你为什么不直接将 SelectedItem 属性 绑定到源 属性 并在 setter 中处理你的逻辑一?这将是 MVVM 的方式。

编辑:由于 SelectedItem 属性 a TreeView 是只读的,您必须使用行为才能绑定到它。有一个如何执行此操作的示例 here.