如何将菜单项命令连接到视图上的自定义命令和方法

本文关键字:命令 自定义 方法 视图 菜单项 连接 | 更新日期: 2023-09-27 18:11:32

我有一个简单的TextBlock上的视图,我添加了一个ContextMenu。我想为MenuItem连接Command来执行View上的一个方法。大半天后,我只找到了一个可行的解决方案,这让我相信我错过了什么。有那么多事情对我来说就是没有意义。

这是我唯一能让它工作的方法。

<TextBlock Text="Test">
    <TextBlock.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Test Me" Command="w:Command.TestMe" />
        </ContextMenu>
    </TextBlock.ContextMenu>
</TextBlock>
public static class Command
{
    public static readonly RoutedUICommand TestMe= new RoutedUICommand("Test Me", "TestMe", typeof(MainWindow));
}

在MainWindow类中:

    public MainWindow()
    { 
        CommandBindings.Add(new CommandBinding(Command.EditAlarm, new ExecutedRoutedEventHandler(EditAlarmDetails), new CanExecuteRoutedEventHandler(CanEditAlarm)));
        InitializeComponent();
        Focus();
    }
    public void CanTestMe(object sender, CanExecuteRoutedEventArgs e)
    {            
        e.CanExecute = true;
    }
    public void TestMeDetails(object sender, ExecutedRoutedEventArgs e)
    {
        TestView view = new TestView();
        view.ShowDialog();
    } 

为什么当我在XAML中声明命令绑定时,我终于让它工作了,但菜单项总是被禁用?

<Window.CommandBindings>
    <CommandBinding Command="w:Command.TestMe" Executed="TestMeDetails" CanExecute="CanTestMe" /> 
</Window.CommandBindings> 

为什么我不能只是声明一个RelayCommand和引用,就像我通常会从ViewModel?

public ICommand TestCommand
    {
        get
        {
            if (testCommand == null)
                testCommand = new RelayCommand(param => TestMeDetails(), param => CanTestMe());
            return changeStatusCommand;
        }
    } 
public bool CanTestMe()
{
    return true;
}
public void TestMeDetails() { }

为什么routeduiccommand类必须是一个在一个单独的静态类工作,但有一个类型的(MainWindow),而不是自己的静态实例类型的(命令)?肯定有什么我不明白的地方。当然,将一个简单的命令事件连接到一个按钮或元素不会这么复杂吧?

如何将菜单项命令连接到视图上的自定义命令和方法

理想情况下 ICommand 应该留在ViewModel中,但如果你想在windows后面的代码中创建它,你也可以实现(不创建RoutedCommand)

你可以像在ViewModel中那样绑定命令,但在此之前你需要考虑这些情况。

  1. ContextMenu不位于它所应用的控件的同一视觉树中。所以,要绑定父窗口,你必须使用 PlacementTarget
  2. 一旦你得到了放置目标,你就可以像在ViewModel中对任何命令一样在后面绑定代码。

下面的代码可以运行:

XAML

<TextBlock Text="Test"
            Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor, 
                                                     AncestorType=Window}}">
    <TextBlock.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Test Me"
                      Command="{Binding PlacementTarget.Tag.TestCommand, 
                               RelativeSource={RelativeSource Mode=FindAncestor, 
                                                  AncestorType=ContextMenu}}"/>
        </ContextMenu>
    </TextBlock.ContextMenu>
</TextBlock>

注意,我在标签中放置了窗口,并使用PlacementTarget从菜单项中访问。

代码后面

private ICommand testCommand;
public ICommand TestCommand
{
    get
    {
        if (testCommand == null)
            testCommand = new RelayCommand(param => TestMeDetails(),
                                           param => CanTestMe());
        return testCommand;
    }
}
public bool CanTestMe()
{
    return true;
}
public void TestMeDetails() { }