了解 Prism 中的委托命令

Understanding Delegate Command in Prism

我正在努力理解委托命令(来自 Prism)的用法,我构建了一个虚拟应用程序,我打算在其中执行以下操作。

我的命令是

private readonly DelegateCommand selectAll;

public ICommand SelectAll
{
    get { return selectAll; }
}

并将其用作

selectAll= new DelegateCommand(SelectAll,CanSelectAll);

private bool CanSelectAll()
{
   if (AllSelectedItems.Count()>3)
   {
      return true;
   }
   return false;
}
public IList<Student> AllItemsSelected
{
    get => m_Items;
    set => Set(ref m_Items, value);
}

当我的 ViewModel 初始化时,我可以看到按钮按预期被禁用,但即使有时这个 AllSelectedItems.count > 3,它似乎也没有更新并通知 UI。

我做错了什么?

创建命令时,告诉它观察属性 AllItemsSelected,像这样:

selectAll= new DelegateCommand(SelectAll,CanSelectAll)
                         .ObservesProperty(() => AllItemsSelected);

这将使命令的状态在每次 AllItemsSelected 更改时更新。

这个功能,ObservesProperty 是 Prism 的一个很好的功能。它允许您设置 one-time 监控该命令状态所依赖的所有属性。

CanSelectAll 方法不会在集合更改时自动调用,毕竟命令应该如何知道何时重新评估条件?您必须明确告诉它这样做。

一个ICommand公开了一个CanExecutChanged event that must be raised to notify the element binding the command to call the CanExecute方法来评估命令是否可以执行。这通常启用或禁用 [​​=66=] 中的元素,例如一个Button。何时以及如何引发此事件取决于 ICommand 接口的具体实现。

DelegateCommands 的 Prism 中,这可以通过两种不同的方式完成。

  • 在命令上调用 RaiseCanExecuteChanged。这可以在 AllItemsSelected 属性.

    的 setter 中完成
    public IList<Student> AllItemsSelected
    {
        get => m_Items;
        set 
        {
           Set(ref m_Items, value);
           selectAll.RaiseCanExecuteChanged();
        }
    }
    
  • 另一种方法是使用 ObservesProperty method when instantiating the command. You pass a lambda for the property to be observed and the command will automatically raise the CanExecuteChanged event once a PropertyChanged event is raised for it. That means this mechanism only works if your view model implements INotifyPropertyChanged 并且你的 属性 加注 PropertyChanged.

    selectAll= new DelegateCommand(SelectAll, CanSelectAll).ObservesProperty(() => AllItemsSelected);
    

选择哪种机制由您决定。对于您的具体情况,了解 AllItemsSelected 的变化方式很重要。如果您总是在选择更改后分配一个新集合,则上面的示例将起作用,因为每次调用 属性 的 setter 并引发 PropertyChanged,因此 ObservesProperty 将拾取零钱并调用 CanExecutChanged 例如。

但是,如果您重复使用同一个集合,例如仅从其中添加和删除项目,这将不起作用,因为实际的集合对象不会更改,这意味着不会调用 setter 也不会调用 PropertyChanged。在这种情况下,将对 RaiseCanExecuteChanged 的调用放入添加、删除或修改集合的方法中。


以防集合在其他地方被修改,例如项目通过 UI 直接添加到集合中,您必须使用支持通知集合更改的集合类型,如 ObservableCollection<T>(通过 CollectionChanged 事件)。您可以向 CollectionChanged 添加一个处理程序,它调用 RaiseCanExecuteChanged.

public class MyViewModel : BindableBase
{
   private readonly DelegateCommand _selectAll;

   public MyViewModel()
   {
      _selectAll = new DelegateCommand(ExecuteSelectAll, CanExecuteSelectAll);
      AllSelectedItems = new ObservableCollection<Student>();
      AllSelectedItems.CollectionChanged += OnAllSelectedItemsChanged;
   }

   public ICommand SelectAll => _selectAll;

   public ObservableCollection<Student> AllSelectedItems
   {
      get => m_Items;
      set => Set(ref m_Items, value);
   }

   private void ExecuteSelectAll()
   {
      // ...your code.
   }

   private bool CanExecuteSelectAll()
   {
      return AllSelectedItems.Count > 3;
   }

   private void OnAllSelectedItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
   {
      _selectAll.RaiseCanExecuteChanged();
   }
}