绑定到一个不在代码中的路由的命令 [英] Binding to a RoutedUICommand that's not in the codebehind

查看:214
本文介绍了绑定到一个不在代码中的路由的命令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个静态类,它包含一个我想在绑定中使用的RoutedUICommand。

I have a static class which contains a RoutedUICommand that I would like to use in binding.

public static class CommandLibrary
{
    public static ProjectViewModel Project { get; set; }

    public static RoutedUICommand AddPage { get; private set; }

    static CommandLibrary()
    {
        AddPage = new RoutedUICommand("AddPage", "AddPage", typeof(CommandLibrary));

    }

    public static void AddPage_Executed(object sender, ExecutedRoutedEventArgs args)
    {
        Project.AddPage();
    }

    public static void AddPage_CanExecute(object sender, CanExecuteRoutedEventArgs args)
    {
        // We need a project before we can add pages.
        if (Project != null)
        {
            args.CanExecute = true;
        }
        else
        {
            // Did not find project, turning Add Page off.
            args.CanExecute = false;
        }
    }
}

当我尝试创建一个CommandBinding对于这个AddPage命令,VS引发了一个发脾气,抱怨说它在Window1中找不到AddPage_CanExecute ...这是没有道理的,考虑到我看到的所有例子都表明这个XAML应该是正确的,考虑到我的代码:

When I attempt to create a CommandBinding for this AddPage command, VS throws a tantrum, complaining that it can't find AddPage_CanExecute in Window1... Which makes no sense considering that all the examples I've seen indicate this XAML should be fine considering the code I have in place:

<Window x:Class="MyProject.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MyProject">
    <Menu>
        <Menu.CommandBindings>
            <CommandBinding Command="local:CommandLibrary.AddPage" 
                            Executed="AddPage_Executed" CanExecute="AddPage_CanExecute" />
        </Menu.CommandBindings>
        <MenuItem Header="_Page">
            <MenuItem Header="_New" Command="local:CommandLibrary.AddPage" />
        </MenuItem>
    </Menu>
</Window>

我也尝试过不包括Menu.CommandBindings部分,只需使用(根据这个提出这个但不具体的问题) :

I've also tried not including the Menu.CommandBindings section and simply using this (as per this question which suggests this but is not specific):

<MenuItem Header="_New" Command="{x:Static local:CommandLibrary.AddPage}" />

打破了错误流程,但它生成的菜单项始终被禁用! CanExecute从来没有似乎被调用。我假设在这种情况下,绑定是失败的,尽管更安静。

That staunched the flow of errors but the menu item it generates is always disabled! CanExecute never seems to get called. I'm assuming the binding is failing in this case, as well, though more quietly.

为什么VS讨厌我的命令,拒绝看正确找到执行和CanExecute方法的地方?我已经看到了许多例子(在马普麦克唐纳的Pro WPF 和在线的几个自定义命令教程),我已经做到了这一点

Why does VS hate my command and refuse to look in the right place to find the Executed and CanExecute methods? I've seen a number of examples (in Pro WPF by Matthew McDonald and on several custom command tutorials online) that have done this as I am doing it.

推荐答案

A CommandBinding 就像任何其他元素你的视觉树。任何指定的事件将由视觉树的根(在这种情况下为您的 Window )处理。这意味着如果您将 AddPage_Executed AddPage_CanExecute 移动到您的窗口的代码后面,它将工作。这允许您在许多UI组件中使用相同的命令,但具有不同的处理程序。

A CommandBinding is just like any other element in your visual tree. Any events specified on it will be handled by the root of your visual tree (your Window in this case). That means if you move the AddPage_Executed and AddPage_CanExecute to your Window's code behind, it will work. This allows you to use the same command in many UI components but have different handlers.

但是,我看到,您的命令对您的视图模型执行一些逻辑。为了节省您一些时间和沮丧,请了解路由命令在这里是错误的解决方案。相反,将您的命令封装在您的视图模型中,如下所示:

I see, however, that your command executes some logic against your view model. To save you some time and frustration, understand that routed commands are the wrong solution here. Instead, encapsulate your command in your view model something like this:

public class ProjectViewModel
{
    private readonly ICollection<PageViewModel> _pages;
    private readonly ICommand _addPageCommand;

    public ProjectViewModel()
    {
        _pages = new ObservableCollection<PageViewModel>();
        _addPageCommand = new DelegateCommand(AddPage);
    }

    public ICommand AddPageCommand
    {
        get { return _addPageCommand; }
    }

    private void AddPage(object state)
    {
        _pages.Add(new PageViewModel());
    }
}

A DelegateCommand ICommand ,它调用代理来执行和查询命令。这意味着命令逻辑全部包含在命令中,您不需要一个 CommandBinding 来提供处理程序(您不需要一个 CommandBinding )/ / code>。所以你的视图只是绑定到您的虚拟机如下:

A DelegateCommand is an implementation of ICommand that invokes delegates to execute and query the command. That means the command logic is all wrapped up in the command and you don't need a CommandBinding to provide handlers (you don't need a CommandBinding at all). So your view just binds to your VM as follows:

<MenuItem Header="_New" Command="{Binding AddPageCommand}"/>

我建议您阅读这一系列的帖子,为您提供更多的上下文:

I suggest you read through this series of posts to give you more context:

  • View Models: POCOs versus DependencyObjects
  • ViewModel
  • DelegateCommand
  • ActiveAwareCommand

这篇关于绑定到一个不在代码中的路由的命令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆