2017-02-23 49 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事件。没有“干净”的方式来做到这一点。