Wpf 如何在数据绑定树视图中的树视图项上设置CommandBinding? 为了简化我所讨论的问题,考虑这个假设的情况。

Wpf 如何在数据绑定树视图中的树视图项上设置CommandBinding? 为了简化我所讨论的问题,考虑这个假设的情况。,wpf,xaml,commandbinding,Wpf,Xaml,Commandbinding,在控件的XAML中,我定义了一个TreeView和两个固定根TreeView节点“AItemsNode”和“BItemsNode”。在其ViewModel中,我公开了两个子集合:AItems和BItems。然后,我将每个根节点的ItemsSource属性绑定到ViewModel上的相应集合。这很好用,显示的正是我想要的 现在我要做的是为ApplicationCommand添加一个CommandBinding。打开两个根节点的子TreeViewItem节点。具体地说,我希望根“AItemsNode

在控件的XAML中,我定义了一个TreeView和两个固定根TreeView节点“AItemsNode”和“BItemsNode”。在其ViewModel中,我公开了两个子集合:AItems和BItems。然后,我将每个根节点的ItemsSource属性绑定到ViewModel上的相应集合。这很好用,显示的正是我想要的

现在我要做的是为ApplicationCommand添加一个CommandBinding。打开两个根节点的子TreeViewItem节点。具体地说,我希望根“AItemsNode”下的子节点将其“Open”CommandBinding指向“OpenAItem_Executed”,第二个根节点的子节点将其指向“OpenBItem_Executed”

我遇到的问题是,我不知道如何在TreeViewItem对象本身上设置CommandBindings。我根本无法通过XAML来理解这一点,如果我要在代码隐藏中实现这一点,我必须与ItemContainerGenerator集成,检查生成的内容并添加绑定,本质上写了这么多代码,我还可以将“Open”命令绑定添加到树视图本身,并检查所选的对象,然后从那里开始。不是最优的,因为我现在有一个Open_执行的处理程序,它根据数据类型在所有地方进行委托,但它确实有效

尽管如此,我还是希望有人能告诉我如何将CommandBinding直接添加到生成的TreeViewItem中,以避免这种情况,并更清晰地隔离代码


所以。。。如何在XAML中通过样式或任何其他方式为TreeViewItem应用特定的命令绑定?

我认为您还没有实现MVVM,MVVM通过使用relayCommand/delegateCommand而不是RoutedCommand直观地解决了这个问题

但是,在您的情况下,您需要通过针对TreeViewItem的样式来处理TreeViewItem的初始化事件。在样式中使用EventSetter。并将添加CommandBinding的代码放入e.OriginalSource值,该值是正在初始化的TreeViewItem本身,传入TreeViewItem.initialized事件处理程序

让我知道这是否合理

编辑

我知道您有x个不同树状文字的x个数字键盘快捷方式。如果是这样的话,我认为x的样式数量是有意义的

但是,如果您想在树状视图级别的单个处理程序中杂乱无章地执行此操作,那么您可能必须在该级别处理附加的事件。。。我不认为初始化/加载的事件会从indv treeviewitem一直冒泡到父树视图,但检查它会很有趣,我很高兴证明是错误的

此外,这可能不适用于折叠的树视图项

因此,假设您为一个特定的树状视图项定义了Ctrl+o快捷方式,该项位于折叠的树状分支内,或者位于打开的分支内,但它位于滚动视图之外,则基于路由事件的机制和命令绑定将不起作用,因为它们需要在UI内存中对该项进行设备化,以便路由工作

因此,我现在理解的解决方案在这种情况下变得有点不切实际

解决方案

什么东西一直可见

树景

因此,利用这一点对你有利。将所有命令绑定和快捷方式添加到树视图本身


在所有命令绑定中通用的处理程序中,设计一种机制,使用TreeViewItemModels的ItemsSource来标识单个项,方法是在TreeViewModels中搜索,然后在相关TreeViewModel中搜索,并通过将IsOpen属性INotifyable绑定到IsExpanded来打开分支层次结构属性。我建议使用交互触发器来实现mvvm

希望这能帮助你朝着正确的方向前进

Xaml:


我想你这里的东西倒过来了。只有一个命令。。标准应用程序.Open命令。我希望每个TreeViewItem都有相同的命令,但不同的命令绑定,因此,默认情况下,DataTemplate中的每个子项都有不同的命令绑定。另外,对于由键盘快捷键触发的命令,您的方式根本不起作用,因为它是具有焦点的TreeViewItem,因此是命令的源,并且您已将绑定设置为低于此值,因此它永远不会被命中。它中继/委派命令实际上不适用于我。你能解释一下你会怎么做吗?请记住,命令可以从其键盘快捷键触发,因此TreeViewItem是命令“开始”的位置。另外,根据您的第二个建议,似乎我必须定义“x”个样式,每个TreeViewNode类型一个我希望事件发生的样式,以及将命令绑定连接到的“x”个处理程序,在这一点上,仅仅在TreeView上定义绑定不是要简单得多吗
在命令处理程序中进行rt输出。。。还是我也错过了什么?也许如果你用代码更新你的答案会有帮助。我不确定我们在这里说的是同一种语言。没有“x”命令。让我把它简化一些。考虑具有三个静态定义的根节点的树视图,即在XAML中定义的:RootNodeA、RootNodeB和RootNodeC,它们的ItMsS源指向AtEnter、BITMS和CbIts。我想要标准的ApplicationCommands.Delete命令仅为RootNodeA的子级映射到“DeleteAItem_Executed”!!如果直接选择RootNodeA,则不会发生任何事情,因为DeleteAItem_CanExecute将返回false。我希望RootNodeB和RootNodeC也一样。希望这更有意义。如果我将Delete命令映射到TreeView本身,那么我必须编写If/case开关来检查所选对象,然后分支到各个CanExecute/Execute命令。如果我们添加了rootnode,那么我们必须再次修改后面的代码。但是,如果我们可以通过XAML模板将绑定直接映射到TreeViewItems,那么我们就可以简单地交换新资源来映射新内容,而无需重新编译任何内容。这使得UI更具可扩展性和数据驱动性。希望这现在更有意义。顺便说一下,我们提出的解决方案是添加一个名为CommandBindingsToAdd的新附加属性,并通过样式应用该属性。然后在附加属性的更改处理程序中,我们循环传递的值,并将它们添加到目标对象的CommandBindings属性中。它可以工作,但需要我们将其创建为附加行为。我们觉得这应该是您可以直接在XAML中设置的。唉,情况显然不是这样。正如我所说,希望这一切现在都有意义。
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

<TreeView >
    <TreeView.Resources>
        <DataTemplate x:Key="ItemATemplate">
            <TextBlock Text="{Binding MyNodeTitle}">
                                <i:Interaction.Triggers>
                                <i:EventTrigger EventName="PreviewMouseDown">
                                    <i:InvokeCommandAction Command="{Binding AChildCommand}" CommandParameter="{Binding}"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
            </TextBlock>
        </DataTemplate>
        <DataTemplate x:Key="ItemBTemplate">
            <TextBlock Text="{Binding MyNodeTitle}">
                                <i:Interaction.Triggers>
                                <i:EventTrigger EventName="PreviewMouseDown">
                                    <i:InvokeCommandAction Command="{Binding BChildCommand}" CommandParameter="{Binding}"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
            </TextBlock>
        </DataTemplate>
    </TreeView.Resources>
    <TreeView.Items>
        <TreeViewItem Header="AItemRootNode" ItemsSource="{Binding SomeAStuff}" ItemTemplate="{StaticResource ItemATemplate}"/>
        <TreeViewItem Header="BItemRootNode" ItemsSource="{Binding SomeBStuff}" ItemTemplate="{StaticResource ItemBTemplate}"/>
    </TreeView.Items>
</TreeView>
private ICommand _aChildCommand;
public ICommand AChildCommand
{
    get
    {
        if (_aChildCommand == null)
            _aChildCommand = new DelegateCommand(OnAChild);
        return _aChildCommand;
    }
}

private void OnAChild(object obj)
{
}