如何在DataBound TreeView中的TreeViewItem上设置CommandBinding?

时间:2013-06-06 09:01:20

标签: wpf xaml commandbinding

为了简化我遇到的问题,请考虑这个假设情景。

在我控制的XAML中,我定义了一个TreeView和两个固定的根TreeViewItem节点,'AItemsNode'和'BItemsNode'。在它的ViewModel中,我公开了两个子集合:AItems和BItems。然后,我将每个根节点的ItemsSource属性绑定到ViewModel上的相应集合。这很有效,可以准确显示我想要的内容。

现在我要做的是将ApplicationCommands.Open的CommandBinding添加到两个根节点的 TreeViewItem节点。具体来说,我希望根'AItemsNode'下的子项将'Open'CommandBinding指向'OpenAItem_Executed',将第二个根节点的子节点指向'OpenBItem_Executed'。

我遇到的问题是我不知道如何在TreeViewItem对象上设置CommandBindings。我无法通过XAML解决这个问题,如果我要在代码隐藏中完成它,我必须与ItemContainerGenerator集成,检查生成的内容并添加绑定,基本上写了这么多代码我也可以将'Open'CommandBinding添加到TreeView本身并检查SelectedObject并从那里开始。不是最优的,因为我现在有一个Open_Executed处理程序,它根据数据类型委托所有地方,但它确实有效!

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

那么......如何通过样式(或XAML中的任何其他方式)为TreeViewItem应用特定的CommandBindings?

2 个答案:

答案 0 :(得分:0)

我认为你没有实施MVVM(通过使用RelayCommands / DelegateCommands代替RoutedCommands来直观地解决了这个问题)

但是,在您的情况下,您需要通过InitializedTreeViewItem处理Style TreeViewItem事件。在EventSetter中使用Style。并将代码添加CommandBindinge.OriginalSource值(即已初始化的TreeViewItem本身)传入TreeViewItem.Initialized事件处理程序。

让我知道这是否有意义。

修改

据我所知,你有x个不同TreeViewItems的x个keyborad快捷键。如果是这样的话,x的样式对我来说很有意义。

但是如果你想在树视图级别的单个处理程序中混乱,那么你可能需要处理该级别的附加事件...我不认为Initialised / {{1从indv treeviewitem到父树视图的事件气泡,但检查一下会很有趣,我很乐意证明它是错误的!

另外,这可能对折叠的树视图项无效。

因此,假设您为折叠树分支内的特定树视图项定义“Ctrl + o”快捷方式,或者它位于打开的分支中,但它位于滚动视图之外,基于路由事件的机制(因此命令)因为他们需要将项目虚拟化(在UI内存中)以便路由工作,所以工作得很好...

所以我的解决方案(正如我现在所理解的)在这种情况下变得有点不切实际。

<强>解决方案

什么时候一直可见?

的TreeView!

所以尽量利用它。将所有命令绑定(和快捷方式)添加到TreeView本身!

在处理程序中(可能在所有命令绑定中都是通用的)设计一种机制,通过在LoadedItemsSource进行搜索来识别单个项目,然后在相关的{{1}内搜索通过通用样式通过绑定TreeViewItemViewModels属性(INotifyable)到TreeViewItemViewModel的{​​{1}}属性来Open branch hierarchy机制。

答案 1 :(得分:0)

实施mvvm,我建议使用交互触发器。

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

的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)
{
}