具有CanExecute组合标准的ReactiveCommand

时间:2013-03-18 10:03:08

标签: c# system.reactive reactiveui

我刚开始使用ReactiveUI。我有以下课程:

public class MainViewModel : ReactiveObject, IRoutableViewModel 
{
   private string shareText;

   public ReactiveCollection<SharingAccountViewModel> SelectedAccounts { get; private set; }

   public string ShareText 
   { 
      get { return shareText; }
      set
      {
          this.RaiseAndSetIfChanged(ref shareText, value);
      }
   }

   public IReactiveCommand ShareCommand { get; private set; }
}

我想要做的是在以下条件为真时允许命令执行:

  1. ShareText属性不为null或为空
  2. SelectedAccounts集合包含至少一个值
  3. 我已经尝试了以下但是它不起作用,因为连接到命令的按钮永远不会被启用:

    ShareCommand = new ReactiveCommand(this.WhenAny(viewModel => viewModel.ShareText,
      viewModel => viewModel.SelectedAccounts,
      (x, y) => !String.IsNullOrEmpty(x.Value) && y.Value.Count > 0));
    

    如果我只是检查ShareText属性,它可以正常工作:

      ShareCommand = new ReactiveCommand(this.WhenAny(viewModel => viewModel.ShareText,
                (x) => !String.IsNullOrEmpty(x.Value)));
    

    我查看了问题ReactiveUI: Using CanExecute with a ReactiveCommand

    的答案

    基于此,我尝试了以下内容:

    var accountsSelected = SelectedAccounts.CollectionCountChanged.Select(count => count > 0);
    ShareCommand = new ReactiveCommand(accountsSelected);
    

    这适用于我的执行标准的第二部分,因为只要在集合中添加或删除项目,连接到命令的按钮就会被正确启用或禁用。

    我的问题是我现在如何将它与检查ShareText属性不为null或为空?

    我不能使用this.WhenAny(..)方法,因为accountsSelected变量不是属性。

    由于

2 个答案:

答案 0 :(得分:6)

将WhenAny与IObservable一起使用有点棘手。我就是这样做的:

var canShare = Observable.CombineLatest(
    this.WhenAnyObservable(x => x.SelectedAccounts.CollectionCountChanged),
    this.WhenAny(x => x.ShareText, x => x.Value),
    (count, text) => count > 0 && !String.IsNullOrWhitespace(text));

此处WhenAnyObservable的优势在于,如果您决定重新分配 SelectedAccounts(即SelectedAccounts = new ReactiveCollection(...);,则上述语句仍然有效,而上述语句仍然可以听老收藏。

答案 1 :(得分:1)

我相信有不同的方法来获得预期的结果,这只是一种方式。

var canExecute = this.ObservableForProperty(v => v.ShareText)
                         .Select(_ => Unit.Default)
                  .Merge(SelectedAccounts.CollectionCountChanged
                                     .Select(_ => Unit.Default))
                  .Select(_ => !String.IsNullOrEmpty(ShareText)
                                    && SelectedAccounts.Any())
                  .StartWith(false);

ShareCommand = new ReactiveCommand(canExecute);