C# 在这种情况下,如何调用ICommand.CanExecute?
嗯。下面是一个场景。这是WPF+MVVM(.net 4.0)应用程序:C# 在这种情况下,如何调用ICommand.CanExecute?,c#,.net,wpf,xaml,mvvm,C#,.net,Wpf,Xaml,Mvvm,嗯。下面是一个场景。这是WPF+MVVM(.net 4.0)应用程序: 视图:有一个DataGrid和两个向上/向下移动按钮,用于在DataGrid中向上或向下移动所选记录。网格和按钮都使用基于XAML的绑定 ViewModel:具有一个公共属性,其类型为DataView,myDataGrid将绑定到该属性。下面列出了两个ICommand实现。这两个按钮将绑定到这两个命令。最后但并非最不重要的是,有两个函数名为MoveUp()和MoveDown() 两个ICommand实现:在每个命令中,Can
DataGrid
和两个向上/向下移动按钮,用于在DataGrid
中向上或向下移动所选记录。网格和按钮都使用基于XAML的绑定DataView
,myDataGrid
将绑定到该属性。下面列出了两个ICommand
实现。这两个按钮将绑定到这两个命令。最后但并非最不重要的是,有两个函数名为MoveUp()
和MoveDown()
ICommand
实现:在每个命令中,CanExecute()
返回所选记录是否可以分别上移或下移,并且Execute()
通过调用ViewModel的MoveUp()
和MoveDown()
函数实际移动记录。这些命令对象在其构造函数中获取VM对象的引用数据网格
中更改所选记录时,我的按钮没有被启用/禁用,这带来了两个子问题:
CanExecute()
以及何时调用CommandManager.invalidateRequestSuggested()
,但也没有任何帮助CommandBase
类,我的两个命令类都从中继承:
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);
}
}
将您的“OnExcuteChanged”替换为此
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
我想知道这个架构是否正确,是否符合MVVM
模式
是的,这完全符合MVVM模式
谁调用CanExecute()以及何时调用 每当引发
CanExecuteChanged
事件时,都会调用CanExecute()
命令在内部钩住此事件,并根据CanExecute委托返回的bool属性启用/禁用按钮或任何frameworkElement
我如何手动调用它 首先,在具体实现中创建
raisecancecutechanged()
方法(如果还没有),以便可以手动调用它。这将如下所示:
public void RaiseCanExecuteChanged()
{
EventHandler canExecuteChangedHandler = CanExecuteChanged;
if (canExecuteChangedHandler != null)
{
canExecuteChangedHandler(this, EventArgs.Empty);
}
}
因为在您的情况下,只要dataGrid中的SelectedItem发生更改,就需要调用CanExecute()
。我建议将DataGrid的SelectedItem
绑定到ViewModel中的某个属性,并在setter中手动调用raiseCanecuteChanged()
,以便可以在命令实例上调用CanExecute
但是,如果您不想手动调用
raisecancecutechanged()
方法,还有另一种方法。您可以挂接到CommandManager.RequerySuggested
事件,只要CommandManager
感觉需要刷新该UI,就会引发该事件
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
当
System.Windows.Input.CommandManager检测可能导致以下情况的条件
更改命令的执行能力
因此,每当引发
CommandManager.RequerySuggested
时,它最终将引发您的CanExecuteChanged
,从而调用您的命令的CanExecute
。因此,根据CanExecute委托返回的bool启用/禁用按钮。我个人总是使用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);
}
}
内部类RelayCommand:ICommand
{
私有只读操作\u执行;
私有只读谓词_canExecute;
public RelayCommand(Action execute):这个(execute,null)
{
}
公共RelayCommand(操作执行,谓词canExecute)
{
if(execute==null)
{
抛出新的ArgumentNullException(“执行”);
}
_执行=执行;
_canExecute=canExecute;
}
公共布尔CanExecute(对象参数)
{
返回_canExecute==null?true:_canExecute(参数);
}
公共事件事件处理程序CanExecuteChanged
{
添加
{
CommandManager.RequerySuggested+=值;
}
去除
{
CommandManager.RequerySuggested-=值;
}
}
public void Execute(对象参数)
{
_执行(参数);
}
}
引用以下内容中有关CanExecutedChanged
事件的内容:
CanExecuteChanged事件是ICommand接口实现的一部分,具有一些有趣的特性。它将事件订阅委托给CommandManager.RequerySuggested事件。这确保了WPF命令基础结构询问所有RelayCommand对象是否可以在其询问内置命令时执行
在您的情况下,此事件不起作用,并且对象未收到有关执行命令可能性的信息。您使用的是哪个版本的
ICommand
?您所说的版本是什么意思?System.Windows.Input
(PresentationCore.dll 4.0.0)中只有一个ICommand
。是的,我的意思是DelegateCommand
或RelayCommand
或您自己派生的ICommand
?mmm…不确定。我正在粘贴上面的CommandBase
类。我所有的具体命令类都继承自它。CanExecute
方法总是从基类方法返回true。我希望您在具体的命令实现中将其设置为实际的谓词
,否则命令CanExecute
willa始终返回true,按钮将永远不会被禁用。超级!你也能输入一些解释吗?谢谢你的详细输入。有一个问题:raisecancecutechanged()
被标记为受保护。我的ViewModel将无法访问它。没有?对,我只是复制了你的OnCanExecuteChanged()
。应该是公共的