2017-02-23 91 views
0

如何強制使用MVVM 我有一個標籤控件和每個選項卡項目的編輯控制一個簡單的應用程序調用CanExecute帶狀調用CanExecute的功能區。它鏈接到一個ViewModel,其中也定義了命令(不是路由的)。它們在菜單中使用。到目前爲止,一切正常。如何強制使用MVVM

現在我想使用與根據一些條件下使能按鈕的帶狀(例如,保存或自動換行只在情況下,將有活性的任何選項卡項被啓用)。不幸的是,所有命令的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(); 
    } 
} 

命令自動換行:

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)); 
    } 
} 

ñ ewFile命令執行:

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> 

在開始的時候,有沒有文件打開,因此自動換行被禁用。功能區上的按鈕也是如此。當執行NewFileCommand時,將使用該控件創建新選項卡,但WordWrap命令保持禁用狀態。

我發現這篇文章WPF MVVM command canexecute enable/disable button其中建議是呼籲RaiseCanExecuteChanged在二傳手的ActiveDocument:

public Document ActiveDocument 
{ 
    get { return _ActiveDocument; } 
    set 
    { 
     _ActiveDocument = value; 
     OnPropertyChanged(nameof(ActiveDocument)); 
     ChangeWordWrapCommand.RaiseCanExecuteChanged();///really 
    } 
} 

雖然這個工作,這聽起來很奇怪,我。爲什麼財產應該知道使用它的所有命令並且應該照顧它們?這個問題有沒有更清晰的解決方案?

+0

CommandManager.RequerySuggested? – Aybe

回答

0

爲什麼要財產知道使用它,應該照顧他們所有的命令?

因爲這是視圖模型類實現的應用程序邏輯的一部分。除了這個班,沒有人可以知道什麼時候調用命令的CanExecute方法。

所以你實際上需要提高CanExecuteChanged事件來告訴WPF刷新命令/按鈕的狀態,只要你願意,你這樣做的方式就是調用DelegateCommandRaiseCanExecuteChanged方法。無論何時和每次你想刷新命令。

有任何清潔劑解決這個問題?

你可以看看ReactiveUI。這是一個具有反應性和無功指令的概念,這使得它更容易刷新命令的MVVM庫每當屬性發生變化:

ChangeWordWrapCommand = ReactiveCommand.Create(this.WhenAnyValue(x => x.ActiveDocument)); 

但是,如果你不使用這樣的反應框架應該叫RaiseCanExecuteChanged可以在您想要刷新命令的狀態時提升CanExecuteChanged事件。沒有「乾淨」的方式來做到這一點。