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>());
        }
예제 #2
0
        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>());
        }