繁体   English   中英

如果没有项目,则禁用WPF TreeView上下文菜单

[英]WPF TreeView context menu is disabled if no items exist

我试图在TreeView中显示一个ContextMenu。 无论是否选择一项,某些条目都必须可用,但是直到我用至少一项填充TreeView为止,所有命令都被禁用:

<TreeView Name="myTreeView" Width="200px">
    <TreeView.ContextMenu>
        <ContextMenu>
            <MenuItem Command="New" IsEnabled="True" />
        </ContextMenu>
    </TreeView.ContextMenu>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate>
            <TextBlock Text="{Binding Path=Title}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

但是,菜单项仍被禁用:

禁用的上下文菜单

在菜单栏的“ 文件”菜单中启用了相同的命令,并且没有CanExecute属性。

即使不存在任何项目,如何启用上下文菜单项?

问题在于ContextMenu的DataContext(即绑定New命令的位置)是树视图节点,而不是树视图本身。 如果您有与节点相关的命令,那就好极了-编辑,移动,更改设置。

对于少数几个像添加和删除这样的泛节点而言,效果不是很好。

当它在节点的DataContext中查找(并且没有节点退出)时,它找不到该命令(无论如何该命令都没有意义,因为管理TreeView的对象应该创建新项目,而不是项目本身)。

解决方案是绑定到不在项目的DataContext中但在TreeView中的New命令。 使用ContextMenu处理数据绑定存在令人沮丧的事情,因为它与窗口中的其他部分不在同一个可视树中,因此常常令人沮丧。

一个解决方案是像这样引用上下文菜单的PlacementTarget:

    <TreeView Name="myTreeView" Width="200px">
    <TreeView.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Edit (This command exists in the Node's ViewModel)" Command="{Binding Edit}"/>
            <MenuItem Header="New (This command exists in the Window's ViewModel)" Command="{Binding PlacementTarget.DataContext.New, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"/>
        </ContextMenu>
    </TreeView.ContextMenu>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate>
            <TextBlock Text="{Binding Path=Title}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

进一步的问题

将命令添加为静态资源的示例(如果在用户控件视图中,则将窗口更改为用户控件):

<Window.Resources>
    <local:MyCommand x:Key="MyCommand"/>
</Window.Resources>

然后引用:

<MenuItem Header="MyCommand" Command="{StaticResource MyCommand}"/>

与第一个示例一样,在ViewModel(即DataContext)中绑定命令。 用与绑定Title相同的方式,可以绑定到任何属性,例如ICommand。

因此,对于一个视图:

<MenuItem Header="New" Command="{Binding New}"/>

视图模型具有名为New的属性NewCommand:

public NewCommand New { get; private set; }

人们之所以经常使用它,是因为他们拥有接受委托的通用ICommand,因此他们可以配置与该ViewModel相关的所有操作。 例如:

public class MyCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
    public Action<object> Action { get; set; }

    public MyCommand(Action<object> action)
    {
        Action = Action;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        Action(parameter);
    }
}

然后,在ViewModel中,我们不必重用ICommand类的全部负载,而可以重用它并让它做其他事情:

public MyCommand New { get; private set; }
public MyCommand Delete { get; private set; }
public MyCommand ClearAll { get; private set; }

public MyViewModelConstructor()
{
    New = new MyCommand((parameter) =>
    {
        //Add new object
    });
    Delete = new MyCommand((parameter) =>
    {
        //Delete object
    });
    ClearAll = new MyCommand((parameter) =>
    {
        //Clear all objects
    });
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM