public SelectLocationViewModel(AppViewModel screen, IConfigurationService configurationService, IGeocodeService geocoder) { this.HostScreen = screen; this.configurationService = configurationService; this.geocoder = geocoder; ExecuteSearch = ReactiveCommand.CreateFromTask <string, IEnumerable <Location> >( async searchTerm => await geocoder.SearchForLocationsAsync(searchTerm) ); this.SaveSelectedLocation = ReactiveCommand.CreateFromTask(async() => { await configurationService.ChangeSavedLocationAsync(this.SelectedLocation); //Attempt to re-load app screen.LoadCommand.Execute().Subscribe(); }, this.WhenAny(vm => vm.SelectedLocation, location => location.GetValue() != null)); this.WhenAnyValue(x => x.SearchTerm) .Throttle(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler) .Select(x => x?.Trim()) .DistinctUntilChanged() .Where(x => !string.IsNullOrWhiteSpace(x)) .InvokeCommand(ExecuteSearch); this.ExecuteSearch.IsExecuting.ToProperty(this, x => x.IsSearching, out this.isSearching, false); searchResults = ExecuteSearch.ToProperty(this, x => x.SearchResults, new List <Location>()); }
public MainViewModel() { ExecuteSearch = ReactiveCommand.CreateAsyncTask(_ => GetSearchResultsFromFlickr(SearchTerm)); /* Creating our UI declaratively * * The Properties in this ViewModel are related to each other in different * ways - with other frameworks, it is difficult to describe each relation * succinctly; the code to implement "The UI spinner spins while the search * is live" usually ends up spread out over several event handlers. * * However, with RxUI, we can describe how properties are related in a very * organized clear way. Let's describe the workflow of what the user does in * this application, in the order they do it. */ // We're going to take a Property and turn it into an Observable here - this // Observable will yield a value every time the Search term changes (which in // the XAML, is connected to the TextBox). // // We're going to use the Throttle operator to ignore changes that // happen too quickly, since we don't want to issue a search for each // key pressed! We then pull the Value of the change, then filter // out changes that are identical, as well as strings that are empty. // // Finally, we use RxUI's InvokeCommand operator, which takes the String // and calls the Execute method on the ExecuteSearch Command, after // making sure the Command can be executed via calling CanExecute. this.WhenAnyValue(x => x.SearchTerm) .Throttle(TimeSpan.FromMilliseconds(800)) .Select(x => x.Trim()) .DistinctUntilChanged() .Where(x => !string.IsNullOrWhiteSpace(x)) .InvokeCommand(ExecuteSearch); // How would we describe when to show the spinner in English? We // might say something like, "The spinner's visibility is whether // the search is running". RxUI lets us write these kinds of // statements in code. // // ExecuteSearch has an IObservable<bool> called IsExecuting that // fires every time the command changes execution state. We Select() that into // a Visibility then we will use RxUI's // ToProperty operator, which is a helper to create an // ObservableAsPropertyHelper object. _spinnerVisibility = ExecuteSearch.IsExecuting .ToProperty(this, x => x.SpinnerVisibility, false); // We subscribe to the "ThrownExceptions" property of our ReactiveCommand, // where ReactiveUI pipes any exceptions that are thrown in // "GetSearchResultsFromFlickr" into. See the "Error Handling" section // for more information about this. ExecuteSearch.ThrownExceptions.Subscribe(ex => { /* Handle errors here */ }); // Here, we're going to actually describe what happens when the Command // gets invoked - we're going to run the GetSearchResultsFromFlickr every // time the Command is executed. // // The important bit here is the return value - an Observable. We're going // to end up here with a Stream of FlickrPhoto Lists: every time someone // calls Execute, we eventually end up with a new list which we then // immediately put into the SearchResults property, that will then // automatically fire INotifyPropertyChanged. _searchResults = ExecuteSearch.ToProperty(this, x => x.SearchResults, new List <FlickrPhoto>()); }