在WPF中,Command的CanExecute方法如何获得其他UI元素的可见性?

时间:2012-04-26 17:45:39

标签: c# wpf command

我一直在使用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)
    {

    }
}

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

如果你将它与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; }

答案 2 :(得分:0)

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