行。这是场景。这是WPF + MVVM(.net 4.0)应用程序:
DataGrid
和两个按钮上移/下移,这些按钮可以在DataGrid
中向上或向下移动选定的记录。网格和按钮都使用基于XAML的绑定。DataView
类型的公共属性,我的DataGrid
将绑定到该属性。然后,下面列出了两个ICommand
实现。这两个按钮将绑定到这两个命令。最后但并非最不重要的是,有两个名为MoveUp()
和MoveDown()
的函数可以做到这一点。ICommand
实现:在每个命令中,CanExecute()
返回所选记录是否可以分别向上或向下移动,Execute()
实际上通过调用ViewModel的MoveUp()
移动记录和我上面描述的MoveDown()
函数。这些命令对象在其构造函数中获取VM对象的引用。首先,我想知道这个架构是否正确并符合MVVM模式?其次,当我在DataGrid
更改所选记录时,我的按钮无法启用/禁用,这会带来2个子问题:
CanExecute()
以及何时?CommandManager.InvalidateRequerySuggested()
,但这也无济于事。这是我的CommandBase
类,我的Command类都从这个类继承:
internal abstract class CommandBase : DependencyObject, ICommand
{
public virtual bool CanExecute(Object parameter)
{
return true;
}
public abstract void Execute(Object parameter);
public event EventHandler CanExecuteChanged;
protected void OnCanExecuteChanged(Object sender, EventArgs e)
{
CanExecuteChanged(sender, e);
}
}
答案 0 :(得分:5)
我想知道这个架构是否正确并符合MVVM 图案?
是的,这完全符合MVVM模式。
谁调用CanExecute()以及什么时候?
每当CanExecuteChanged
事件被引发时,就会调用CanExecute()。
命令内部挂钩此事件和启用/禁用按钮或任何基于CanExecute委托返回的bool属性的frameworkElement。
如何手动调用?
首先在具体实现中创建RaiseCanExecuteChanged()
方法(如果还没有),以便可以手动调用它。这将是这样的:
public void RaiseCanExecuteChanged()
{
EventHandler canExecuteChangedHandler = CanExecuteChanged;
if (canExecuteChangedHandler != null)
{
canExecuteChangedHandler(this, EventArgs.Empty);
}
}
因为在您的情况下,只要dataGrid中的SelectedItem发生更改,您就需要调用CanExecute()
。我建议将DataGrid的SelectedItem
绑定到ViewModel中的某个属性,并在setter中手动调用RaiseCanExecuteChanged()
,以便可以在命令实例上调用CanExecute。
但是,如果您不想手动调用RaiseCanExecuteChanged()
方法,还有另一种方法。每当CommandManager.RequerySuggested
感觉需要刷新UI时,您就可以挂钩CommandManager
事件。
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
RequerySuggested事件发生时 System.Windows.Input.CommandManager 检测可能的情况 改变命令执行的能力。
因此,每当CommandManager.RequerySuggested
被引发时,它最终会引发你的CanExecuteChanged
,从而调用你的命令CanExecute
。因此,根据CanExecute委托返回的bool启用/禁用按钮。
答案 1 :(得分:0)
用此替换'OnExcuteChanged'......
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
答案 2 :(得分:0)
我个人总是使用Josh Smith的实现RelayCommand
:
internal class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
引用此link的CanExecutedChanged
事件:
CanExecuteChanged事件是ICommand接口实现的一部分,它具有一些有趣的功能。它将事件订阅委托给CommandManager.RequerySuggested事件。这可以确保WPF命令基础结构询问所有RelayCommand对象是否可以在它询问内置命令时执行。
在您的情况下,此事件不起作用,并且该对象未收到有关执行命令的可能性的信息。