【发布时间】:2017-07-13 22:59:48
【问题描述】:
如何使用 MVVM 在 Ribbon 中强制调用 CanExecute 我有一个简单的应用程序,其中包含每个选项卡项上的选项卡控件和编辑控件。它链接到一个 ViewModel,其中还定义了命令(不是路由的)。它们用于菜单。到目前为止一切正常。
现在我想使用带有根据某些条件启用的按钮的功能区(例如,只有在任何选项卡项处于活动状态时才会启用保存或 WordWrap)。不幸的是,所有命令的 CanExecute 方法在应用程序加载时只调用一次。当 ViewModel 中的某些内容发生更改时,如何确保检查它?
更多细节(WPF 4.6.1):
中继命令:
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();
}
}
自动换行命令:
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 和 Opened 文档属性:
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 command canexecute enable/disable button 建议在 ActiveDocument 设置器中调用 RaiseCanExecuteChanged:
public Document ActiveDocument
{
get { return _ActiveDocument; }
set
{
_ActiveDocument = value;
OnPropertyChanged(nameof(ActiveDocument));
ChangeWordWrapCommand.RaiseCanExecuteChanged();///really
}
}
虽然这可行,但对我来说听起来很奇怪。为什么属性应该知道所有使用它的命令并且应该处理它们?这个问题有什么更干净的解决方案吗?
【问题讨论】:
-
CommandManager.RequerySuggested ?