A ViewModel build with ReactiveUI 8 to get web images

This is a practice application that I built to learn Rx.Net & RxUI. It follows the MVVM pattern and is written in C# with WPF. Here is a link to a question I asked during the development, which includes some information about this application. Now that it finally runs, I want to improve it by eliminating any potential flaws in the code, which is presented as follows:

public class MainViewModel : ReactiveObject
{
#region Constructors

public MainViewModel()
{
_currentState = new BehaviorSubject<MainViewModelState>(MainViewModelState.Idle);

.ToProperty(this, nameof(Status));
_progress = _currentState.Select(s => ((int) s).ToString()).ObserveOn(RxApp.MainThreadScheduler)
.ToProperty(this, nameof(Progress));

var canSearch = this.WhenAnyValue(x => x.TargetUrl, x => !string.IsNullOrEmpty(x))
.CombineLatest(_currentState, (b, state) => b && _currentState.Value == MainViewModelState.Idle);

_searchCommand = ReactiveCommand.Create(() =>
{
_currentState.OnNext(MainViewModelState.FetchingHtmlDoc);
return TargetUrl;
}, canSearch);

.Zip(_searchCommand, Tuple.Create)
.Do(_ => _currentState.OnNext(MainViewModelState.ExtractingImageUrl))
.Subscribe(
urls =>
{
_currentState.OnNext(MainViewModelState.PopulatingList);
_currentState.OnNext(MainViewModelState.Idle);
},
ex => this.Log().Error(ex));

var canClear = _currentState.Select(x => x == MainViewModelState.Idle).ObserveOn(RxApp.MainThreadScheduler);

_clearCommand = ReactiveCommand.Create(() =>
{
_currentState.OnNext(MainViewModelState.ClearingList);
ImageList.Clear();
_currentState.OnNext(MainViewModelState.Idle);
}

#endregion

#region Properties

private IImageExtractService _imageExtractService;

private IImageExtractService ImageExtractService =>
_imageExtractService ?? (_imageExtractService = Locator.Current.GetService<IImageExtractService>());

public ReactiveList<ScrappedWebImageViewModel> ImageList =
new ReactiveList<ScrappedWebImageViewModel>();

public string Status => _status.Value;

public string Progress => _progress.Value;

private string _targetUrl;

public string TargetUrl
{
get => _targetUrl;
set => this.RaiseAndSetIfChanged(ref _targetUrl, value);
}

#endregion

#region Commands

public ICommand SearchCommand => _searchCommand;

public ICommand ClearCommand => _clearCommand;

#endregion

#region Methods

#endregion

#region Types

private enum MainViewModelState
{
Idle = 0,
FetchingHtmlDoc,
ExtractingImageUrl,
PopulatingList,
ClearingList
}

#endregion
}


During my test runs, I noticed that when extracting Urls, the UI became unresponsive, but I can't figure out a better way to do it. Also I wish to add cancellation functionalities but it seems quite difficult to implement with the current code, perhaps I'm not following the best practice?

• Because we don't deal with code not yet implemented, don't expect someone to show you how to add your cancellation. But it's quite appropriate to ask how changes to your code would make it easier to add that yourself. So your question is welcome here. – Toby Speight Feb 8 '18 at 11:16