[英]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.