【问题标题】:In WPF, how can a Command's CanExecute method gain visibility of other UI elements?在 WPF 中,Command 的 CanExecute 方法如何获得其他 UI 元素的可见性?
【发布时间】:2012-04-26 17:45:38
【问题描述】:

我使用 WPF 已经有一段时间了,但我是 Commands 新手,但我想开始正确使用它们一次。在一个代码示例之后,我建立了一个单独的静态 Commands 类来保存我的所有命令,它看起来像这样。

public static class Commands
{
    public static RoutedUICommand OpenDocument { get; set; }

    static Commands()
    {
        OpenDocument = new RoutedUICommand("Open Document", "OpenDocument", typeof(Commands));
    }

    public static void BindCommands(Window window)
    {
        window.CommandBindings.Add(new CommandBinding(OpenDocument, OpenDocument_Executed, OpenDocument_CanExecute));
    }

    private static void OpenDocument_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        // Should be set to true if an item is selected in the datagrid.
    }

    private static void OpenDocument_Executed(object sender, ExecutedRoutedEventArgs e)
    {

    }
}

我的问题是,虽然命令将绑定到 MainWindow.xaml 中的 Button 控件,但 OpenDocument_CanExecute 方法需要查看 MainWindow.xaml 中的 DataGrid 以查看是否选择了项目。

我怎样才能让方法可以看到 DataGrid?

解决方案

受到 Ken 回复的启发(再次感谢!),我将以下内容放在适当的位置,效果很好。

MainWindow.xaml.cs

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();

        Loaded += delegate
        {
            DataContext = ViewModel.Current;
            Commands.BindCommands(this);
        };
    }
}

ViewModel.cs

public class ViewModel
{
    private static ViewModel _current;
    public static ViewModel Current
    {
        get { return _current ?? (_current = new ViewModel()); }
        set { _current = value; }
    }

    public object SelectedItem { get; set; }
}

Commands.cs

public static class Commands
{
    public static RoutedUICommand OpenDocument { get; set; }

    static Commands()
    {
        OpenDocument = new RoutedUICommand("Open Document", "OpenDocument", typeof(Commands));
    }

    public static void BindCommands(Window window)
    {
        window.CommandBindings.Add(new CommandBinding(OpenDocument, OpenDocument_Executed, OpenDocument_CanExecute));
    }

    private static void OpenDocument_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = ViewModel.Current.SelectedItem != null;
    }

    private static void OpenDocument_Executed(object sender, ExecutedRoutedEventArgs e)
    {

    }
}

【问题讨论】:

    标签: c# wpf command


    【解决方案1】:

    ICommand 实现在 MVVM 模式中效果最佳:

    class ViewModel : INotifyPropertyChanged {
        class OpenDocumentCommand : ICommand {
            public bool CanExecute(object parameter) {
                return ViewModel.ItemIsSelected;
            }
            public OpenDocumentCommand(ViewModel viewModel) {
                viewModel.PropertyChanged += (s, e) => {
                    if ("ItemIsSelected" == e.PropertyName) {
                        RaiseCanExecuteChanged();
                    }
                };
            }
        }
    
        private bool _ItemIsSelected;
    
        public bool ItemIsSelected {
            get { return _ItemIsSelected; }
            set {
                if (value == _ItemIsSelected) return;
                _ItemIsSelected = value;
                RaisePropertyChanged("ItemIsSelected");
            }
        }
    
        public ICommand OpenDocument { 
            get { return new OpenDocumentCommand(this); } 
        }
    }
    

    显然,我遗漏了一大堆东西。但这种模式过去对我来说效果很好。

    【讨论】:

    • 哦,我明白了。所以本质上我只需要将我的 UI 绑定到模型对象,然后在绑定时将该模型传递给我的命令类?
    • 优秀。我做了一些稍微不同的事情(我将在稍后发布)但基本相同。感谢您的帮助!
    【解决方案2】:

    如果您将命令与 UI 实现紧密耦合,为什么还要实现它?只需响应 datagrid.SelectionChanged 并编写应该发生的代码。

    否则,将其放在 ViewModel 中。让 ViewModel 监控它的状态并评估 CanExe 何时为真。

    编辑

    另一方面,您可以将参数传递给命令,以及 Exe() 和 CanExe() 方法

    //where T is the type you want to operate on
    public static RoutedUICommand<T> OpenDocument { get; set; }
    

    【讨论】:

      【解决方案3】:

      如果您正在执行 MVVM 解决方案,这将是实现发布/订阅聚合器以允许控件相互“对话”的最佳时机。它背后的要点是数据网格将发布一个事件“打开文档”。后续控件可以订阅该事件并对“打开文档”的调用做出反应。发布/订阅模式防止数据网格和控件紧密耦合。对事件聚合器进行一些搜索,我想你会在路上。

      【讨论】:

        猜你喜欢
        • 2017-09-16
        • 2011-02-03
        • 2016-06-28
        • 1970-01-01
        • 2014-03-13
        • 2017-04-22
        • 2017-04-30
        • 2015-07-12
        • 1970-01-01
        相关资源
        最近更新 更多