[英]How to force to call CanExecute in Ribbon using MVVM
如何使用MVVM在功能区中强制调用CanExecute我有一个简单的应用程序,带有选项卡控件和每个选项卡项目上的编辑控件。 它链接到ViewModel,在ViewModel上还定义了命令(而不是路由命令)。 它们在菜单中使用。 到目前为止,一切工作正常。
现在,我想使用功能区,其中包含根据某些条件启用的按钮(例如,只有在任何选项卡项处于活动状态时,才启用“保存”或“ WordWrap”)。 不幸的是,应用程序加载时,所有命令的CanExecute方法仅被调用一次。 如何更改ViewModel中的某些内容时进行检查?
更多详细信息(WPF 4.6.1):
RelayCommand:
public class RelayCommand : ICommand
{
private Action _execute;
private Func<bool> _canExecute;
public RelayCommand(Action execute, Func<bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
return _canExecute();
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_execute();
}
}
WordWrap命令:
private RelayCommand _ChangeWordWrapCommand;
public RelayCommand ChangeWordWrapCommand
{
get
{
if (_ChangeWordWrapCommand == null)
_ChangeWordWrapCommand = new RelayCommand(
() => { ((TextDocument)ActiveDocument).WordWrap = !((TextDocument)ActiveDocument).WordWrap; },
() => { return (ActiveDocument != null); }
);
return _ChangeWordWrapCommand;
}
}
ActiveDocument和打开的文档属性:
public ObservableCollection<Document> OpenedDocuments { get; private set; }
private Document _ActiveDocument;
public Document ActiveDocument
{
get { return _ActiveDocument; }
set
{
_ActiveDocument = value;
OnPropertyChanged(nameof (ActiveDocument));
}
}
NewFile命令执行:
private Document NewFile()
{
TextDocument result = new TextDocument(new Model.TextDocument());
result.FileName = $"Untitled {UntitledFileNumber++}";
OpenedDocuments.Add(result);
ActiveDocument = result;
return result;
}
功能区定义(仅一部分):
<Ribbon x:Name="Ribbon" SelectedIndex="0" UseLayoutRounding="False">
<RibbonTab Header="Home" KeyTip="H" >
<RibbonGroup x:Name="Files" Header="Files" >
<RibbonButton Label="New" KeyTip="N" Command="{Binding Path=NewFileCommand, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
<RibbonButton Label="WordWrap" KeyTip="W" Command="{Binding Path=ChangeWordWrapCommand, Mode=OneWay, UpdateSourceTrigger=Default}" />
</RibbonGroup>
</RibbonTab>
</Ribbon>
在开始时,没有打开文件,因此禁用了WordWrap。 功能区上的按钮也是如此。 当执行NewFileCommand时,将使用控件创建新选项卡,但WordWrap命令将保持禁用状态。
我发现本文的WPF MVVM命令可以执行启用/禁用按钮 ,建议在ActiveDocument设置器中调用RaiseCanExecuteChanged:
public Document ActiveDocument
{
get { return _ActiveDocument; }
set
{
_ActiveDocument = value;
OnPropertyChanged(nameof(ActiveDocument));
ChangeWordWrapCommand.RaiseCanExecuteChanged();///really
}
}
尽管这有效,但对我来说听起来很奇怪。 为什么该属性应该知道使用该属性的所有命令并应加以照顾? 有没有更清洁的解决方案来解决这个问题?
为什么该属性应该知道使用该属性的所有命令并应加以照顾?
因为这是视图模型类实现的应用程序逻辑的一部分。 除了这个类,没有人可以知道何时调用命令的CanExecute
方法。
因此,您实际上需要引发CanExecuteChanged
事件,以告诉WPF随时刷新命令/按钮的状态,而执行此RaiseCanExecuteChanged
方法是调用DelegateCommand
的RaiseCanExecuteChanged
方法。 无论何时何地,您都希望刷新命令。
有没有更清洁的解决方案来解决这个问题?
您可以看看ReactiveUI 。 这是一个MVVM库,具有反应性属性和反应性命令的概念,每当属性更改时,刷新该命令将变得更加容易:
ChangeWordWrapCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.ActiveDocument));
但是,如果您不使用这种反应式框架, CanExecuteChanged
每当您要刷新命令状态时,都应调用RaiseCanExecuteChanged
引发CanExecuteChanged
事件。 没有“更清洁”的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.