void setupRx() { var countAsBehavior = Observable.Concat( Observable.Defer(() => Observable.Return(_NavigationStack.Count)), NavigationStack.CountChanged); NavigateBack = ReactiveCommand.CreateAsyncObservable( countAsBehavior.Select(x => x > 1), _ => Observable.Return(Unit.Default)); NavigateBack.Subscribe(_ => NavigationStack.RemoveAt(NavigationStack.Count - 1)); Navigate = new ReactiveCommand <object>(Observable.Return(true), x => Observable.Return(x)); Navigate.Subscribe(x => { var vm = x as IRoutableViewModel; if (vm == null) { throw new Exception("Navigate must be called on an IRoutableViewModel"); } NavigationStack.Add(vm); }); NavigateAndReset = new ReactiveCommand <object>(Observable.Return(true), x => Observable.Return(x)); NavigateAndReset .SelectMany(x => { NavigationStack.Clear(); return(Navigate.ExecuteAsync(x)); }).Subscribe(); CurrentViewModel = Observable.Concat( Observable.Defer(() => Observable.Return(NavigationStack.LastOrDefault())), NavigationStack.Changed.Select(_ => NavigationStack.LastOrDefault())); }
public IssuesViewModel(INetworkConnectivityService networkConnectivityService, IWeeklyXamarinService weeklyXamarinService) { Ensure.ArgumentNotNull(networkConnectivityService, nameof(networkConnectivityService)); Ensure.ArgumentNotNull(weeklyXamarinService, nameof(weeklyXamarinService)); _networkConnectivityService = networkConnectivityService; _weeklyXamarinService = weeklyXamarinService; SearchResults = new ReactiveList <IssuesResult>(); // Here we're describing here, in a *declarative way*, the conditions in // which the Search command is enabled. Now our Command IsEnabled is // perfectly efficient, because we're only updating the UI in the scenario // when it should change. var canSearch = this.WhenAnyValue(vm => vm.SearchQuery, value => !string.IsNullOrWhiteSpace(value)); // ReactiveCommand has built-in support for background operations and // guarantees that this block will only run exactly once at a time, and // that the CanExecute will auto-disable and that property IsExecuting will // be set according whilst it is running. Search = ReactiveCommand.CreateAsyncObservable(canSearch, x => _weeklyXamarinService.Search(SearchQuery)); // ReactiveCommands are themselves IObservables, whose value are the results // from the async method, guaranteed to arrive on the UI thread. We're going // to take the list of search results that the background operation loaded, // and them into our SearchResults. Search.Subscribe(results => { SearchResults.Clear(); SearchResults.AddRange(results); }); // ThrownExceptions is any exception thrown from the CreateAsyncTask piped // to this Observable. Subscribing to this allows you to handle errors on // the UI thread. Search.ThrownExceptions .Subscribe(ex => { UserError.Throw("Potential Network Connectivity Error", ex); }); // Whenever the Search query changes, we're going to wait for one second // of "dead airtime", then automatically invoke the subscribe command. this.WhenAnyValue(x => x.SearchQuery) .Throttle(TimeSpan.FromSeconds(1), RxApp.MainThreadScheduler) .InvokeCommand(this, x => x.Search); }