我已经使用 WPF 一段时间了,但我是命令的新手,但想开始正确使用它们一次。在代码示例之后,我建立了一个单独的静态 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 中的按钮控件,但OpenDocument_CanExecute方法需要查看 MainWindow.xaml 中的 DataGrid 以查看是否选择了某个项目。
如何连接内容,使方法可以看到数据网格?
溶液
受到Ken的回复的启发(再次感谢!),我把以下内容放在适当的位置,效果很好。
MainWindow.xaml.cs
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Loaded += delegate
{
DataContext = ViewModel.Current;
Commands.BindCommands(this);
};
}
}
视图模型.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; }
}
命令.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)
{
}
}
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实现紧密耦合,为什么还要实现命令呢?只需响应数据网格。选择更改并编码应该发生的事情。
否则,请将其放入视图模型中。让 ViewModel 监视其状态并评估 CanExe 何时为真。
编辑
另一方面,你可以将参数传递给你的命令,以及 Exe() 和 CanExe() 方法。
//where T is the type you want to operate on
public static RoutedUICommand<T> OpenDocument { get; set; }
如果您正在执行 MVVM 解决方案,这将是实现发布/订阅聚合器的最佳时机,该聚合器允许控件相互"交谈"。 其背后的要点是数据网格将发布一个事件"打开文档"。 后续控件可以订阅事件并对"打开文档"的调用做出反应。发布/订阅模式可防止数据网格和控件紧密耦合。 对事件聚合器进行一些搜索,我想你会在路上。