Reputation: 548
I have just started with ReactiveUI. I have the following class:
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; }
}
What I would like to do is to be allow the command to execute when the following criteria is true:
I have tried the following but it does not work as the button which is hooked up to the command never gets enabled:
ShareCommand = new ReactiveCommand(this.WhenAny(viewModel => viewModel.ShareText,
viewModel => viewModel.SelectedAccounts,
(x, y) => !String.IsNullOrEmpty(x.Value) && y.Value.Count > 0));
If I just check for the ShareText property however, it works fine:
ShareCommand = new ReactiveCommand(this.WhenAny(viewModel => viewModel.ShareText,
(x) => !String.IsNullOrEmpty(x.Value)));
I looked at the answer for the question ReactiveUI: Using CanExecute with a ReactiveCommand
Based on that I tried the following:
var accountsSelected = SelectedAccounts.CollectionCountChanged.Select(count => count > 0);
ShareCommand = new ReactiveCommand(accountsSelected);
This is working for the second part of my execution criteria because as soon as items are added or removed from the collection, the button which is hooked up to the command gets enabled or disabled correctly.
My question is how do I now combine that with checking that the ShareText property is not null or empty?
I cannot use the this.WhenAny(..) method anymore as the accountsSelected variable is not a property.
Thanks
Upvotes: 1
Views: 2527
Reputation: 74652
Using WhenAny with an IObservable
is a bit tricky. Here's how I would do it:
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));
The advantage of WhenAnyObservable
here, is that if you decided to reassign SelectedAccounts (i.e. SelectedAccounts = new ReactiveCollection(...);
, the above statement would still work, whereas the one above would still be listening to the old collection.
Upvotes: 8
Reputation: 192
I believe that there are different ways to get the expected result and this is just one way.
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);
Upvotes: 1