【问题标题】:Binding to a RoutedUICommand that's not in the codebehind绑定到不在代码隐藏中的 RoutedUICommand
【发布时间】:2010-11-19 20:26:56
【问题描述】:

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

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;
        }
    }
}

当我尝试为此 AddPage 命令创建 CommandBinding 时,VS 发脾气,抱怨它在 Window1 中找不到 AddPage_CanExecute...考虑到我看到的所有示例都表明该 XAML 应该考虑到我的代码没问题:

<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 部分,而是简单地使用它(根据 this question 建议但不具体):

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

这阻止了错误流,但它生成的菜单项总是被禁用! CanExecute 似乎永远不会被调用。我假设在这种情况下绑定也失败了,尽管更安静。

为什么 VS 讨厌我的命令并拒绝在正确的位置查找 Executed 和 CanExecute 方法?我已经看到了很多示例(在 Pro WPF 中 由 Matthew McDonald 和几个在线自定义命令教程提供),我正在这样做。

【问题讨论】:

    标签: c# wpf data-binding xaml command


    【解决方案1】:

    CommandBinding 就像可视化树中的任何其他元素一样。在其上指定的任何事件都将由您的可视化树的根(在本例中为您的Window)处理。这意味着如果您将AddPage_Executed 和AddPage_CanExecute 移动到您的Window 代码后面,它将起作用。这允许您在许多 UI 组件中使用相同的命令,但具有不同的处理程序。

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

    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());
        }
    }
    

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

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

    我建议您通读这一系列文章以了解更多背景信息:

    【讨论】:

    • 很好的答案。得到了我需要的东西。我已经阅读了一些 MVVM 教程并看到过这种命令的使用,但不记得如何去做,所以我求助于我在书中和通过搜索找到的解决方案。感谢您的帮助。
    • 美丽。我正在努力解决这个问题……学习 wpf+mvvm 并不像我希望的那样简单。 RoutedUICommands 对于我的意图来说太复杂了,我知道应该有一个更简单的方法。 @Kent,感谢您的示例和博客。
    猜你喜欢
    • 2016-09-12
    • 2012-07-15
    • 1970-01-01
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 2019-06-07
    • 2010-12-14
    • 1970-01-01
    相关资源
    最近更新 更多