1

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

在我的控件的 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 集成,检查正在生成的内容并添加绑定,基本上我编写了这么多代码不妨将“打开”CommandBinding 添加到 TreeView 本身并检查 SelectedObject 并从那里开始。不是最优的,因为我现在有一个 Open_Executed 处理程序,它根据数据类型在所有地方委托,但它确实有效!

不过,我希望有人可以向我展示如何将 CommandBinding 直接添加到生成的 TreeViewItem 以避免这种情况并更干净地隔离代码。

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

4

2 回答 2

0

我认为您尚未实现MVVM(通过使用RelayCommands/DelegateCommands而不是可以直观地为您解决此问题RoutedCommands

但是,在您的情况下,您需要处理via targetted to的Initialized事件。中使用。并将您的代码添加到传入事件处理程序的值(这是正在初始化的本身) 。TreeViewItemStyleTreeViewItemEventSetterStyleCommandBindinge.OriginalSourceTreeViewItemTreeViewItem.Initialized

让我知道这是否有意义。

编辑

我了解您有 x 个用于 x 个 distinct 的键盘快捷键TreeViewItems。如果是这样,x 种样式对我来说是有意义的。

但是,如果您想在树视图级别的单个处理程序中执行此操作,那么您可能必须处理该级别的附加事件......我不认为Initialised/Loaded事件从 indv treeviewitem 一直到父级树视图,但检查一下会很有趣,我很高兴证明是错误的!

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

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

因此,在这种情况下,我的解决方案(据我所知)变得有点不切实际。

解决方案

什么是一直可见的?

树视图!

所以利用它来发挥你的优势。将所有命令绑定(和快捷方式)添加到 TreeView 本身!

并且在处理程序中(这可能在所有命令绑定中都很常见)设计一种机制来使用 a 来识别单个项目,方法是在它们ItemsSourceTreeViewItemViewModels搜索,然后在相关TreeViewItemViewModel的机制中Open通过branch hierarchy绑定IsOpen属性(INotifyable)到via的IsExpanded属性TreeViewItem一种通用风格。

于 2013-06-06T10:14:13.937 回答
0

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

希望这可以帮助您朝着正确的方向前进。

xml:

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)
{
}
于 2013-06-06T11:11:37.190 回答