ReactiveCommand с комбинированными критериями для CanExecute

Я только начал с 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 не является нулевым или пустым
  2. Коллекция SelectedAccounts содержит хотя бы одно значение

Я пробовал следующее, но оно не работает, так как кнопка, подключенная к команде, никогда не включается:

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: Использование CanExecute с ReactiveCommand

Исходя из этого, я попробовал следующее:

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

Это работает для второй части моих критериев выполнения, потому что, как только элементы добавляются или удаляются из коллекции, кнопка, подключенная к команде, включается или отключается правильно.

Мой вопрос: как мне теперь совместить это с проверкой того, что свойство ShareText не является нулевым или пустым?

Я больше не могу использовать метод this.WhenAny(..), так как переменная accountSelected не является свойством.

Спасибо

2 ответа

Решение

Использование 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(...);вышеупомянутое утверждение все еще будет работать, тогда как вышеупомянутое будет все еще слушать старую коллекцию.

Я считаю, что есть разные способы получить ожидаемый результат, и это только один из способов.

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);
Другие вопросы по тегам