A ViewModel build with ReactiveUI 8 to get web images

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












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);

_status = _currentState.Select(s => s.ToString()).ObserveOn(RxApp.MainThreadScheduler)
.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);

_searchCommand.SelectMany(HtmlDownloadService.GetHtmlDocument)
.Zip(_searchCommand, Tuple.Create)
.Do(_ => _currentState.OnNext(MainViewModelState.ExtractingImageUrl))
.Select(tuple => ImageExtractService.ExtractAllImageAddress(tuple.Item1, tuple.Item2).Distinct())
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(
urls =>

_currentState.OnNext(MainViewModelState.PopulatingList);
urls.ToObservable().ObserveOn(RxApp.MainThreadScheduler).Subscribe(url =>
ImageList.Add(new ScrappedWebImageViewModel ImageUrl = url));
_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);
, canClear, RxApp.MainThreadScheduler);


#endregion

#region Properties

private IHtmlDownloadService _htmlDownloadService;

private IHtmlDownloadService HtmlDownloadService =>
_htmlDownloadService ?? (_htmlDownloadService = Locator.Current.GetService<IHtmlDownloadService>());

private IImageExtractService _imageExtractService;

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

private readonly BehaviorSubject<MainViewModelState> _currentState;

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

private readonly ObservableAsPropertyHelper<string> _status;

public string Status => _status.Value;

private readonly ObservableAsPropertyHelper<string> _progress;

public string Progress => _progress.Value;

private string _targetUrl;

public string TargetUrl

get => _targetUrl;
set => this.RaiseAndSetIfChanged(ref _targetUrl, value);


#endregion

#region Commands

private readonly ReactiveCommand<Unit, string> _searchCommand;

public ICommand SearchCommand => _searchCommand;

private readonly ReactiveCommand<Unit, Unit> _clearCommand;

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?







share|improve this question



















  • 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 at 11:16
















up vote
1
down vote

favorite












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);

_status = _currentState.Select(s => s.ToString()).ObserveOn(RxApp.MainThreadScheduler)
.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);

_searchCommand.SelectMany(HtmlDownloadService.GetHtmlDocument)
.Zip(_searchCommand, Tuple.Create)
.Do(_ => _currentState.OnNext(MainViewModelState.ExtractingImageUrl))
.Select(tuple => ImageExtractService.ExtractAllImageAddress(tuple.Item1, tuple.Item2).Distinct())
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(
urls =>

_currentState.OnNext(MainViewModelState.PopulatingList);
urls.ToObservable().ObserveOn(RxApp.MainThreadScheduler).Subscribe(url =>
ImageList.Add(new ScrappedWebImageViewModel ImageUrl = url));
_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);
, canClear, RxApp.MainThreadScheduler);


#endregion

#region Properties

private IHtmlDownloadService _htmlDownloadService;

private IHtmlDownloadService HtmlDownloadService =>
_htmlDownloadService ?? (_htmlDownloadService = Locator.Current.GetService<IHtmlDownloadService>());

private IImageExtractService _imageExtractService;

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

private readonly BehaviorSubject<MainViewModelState> _currentState;

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

private readonly ObservableAsPropertyHelper<string> _status;

public string Status => _status.Value;

private readonly ObservableAsPropertyHelper<string> _progress;

public string Progress => _progress.Value;

private string _targetUrl;

public string TargetUrl

get => _targetUrl;
set => this.RaiseAndSetIfChanged(ref _targetUrl, value);


#endregion

#region Commands

private readonly ReactiveCommand<Unit, string> _searchCommand;

public ICommand SearchCommand => _searchCommand;

private readonly ReactiveCommand<Unit, Unit> _clearCommand;

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?







share|improve this question



















  • 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 at 11:16












up vote
1
down vote

favorite









up vote
1
down vote

favorite











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);

_status = _currentState.Select(s => s.ToString()).ObserveOn(RxApp.MainThreadScheduler)
.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);

_searchCommand.SelectMany(HtmlDownloadService.GetHtmlDocument)
.Zip(_searchCommand, Tuple.Create)
.Do(_ => _currentState.OnNext(MainViewModelState.ExtractingImageUrl))
.Select(tuple => ImageExtractService.ExtractAllImageAddress(tuple.Item1, tuple.Item2).Distinct())
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(
urls =>

_currentState.OnNext(MainViewModelState.PopulatingList);
urls.ToObservable().ObserveOn(RxApp.MainThreadScheduler).Subscribe(url =>
ImageList.Add(new ScrappedWebImageViewModel ImageUrl = url));
_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);
, canClear, RxApp.MainThreadScheduler);


#endregion

#region Properties

private IHtmlDownloadService _htmlDownloadService;

private IHtmlDownloadService HtmlDownloadService =>
_htmlDownloadService ?? (_htmlDownloadService = Locator.Current.GetService<IHtmlDownloadService>());

private IImageExtractService _imageExtractService;

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

private readonly BehaviorSubject<MainViewModelState> _currentState;

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

private readonly ObservableAsPropertyHelper<string> _status;

public string Status => _status.Value;

private readonly ObservableAsPropertyHelper<string> _progress;

public string Progress => _progress.Value;

private string _targetUrl;

public string TargetUrl

get => _targetUrl;
set => this.RaiseAndSetIfChanged(ref _targetUrl, value);


#endregion

#region Commands

private readonly ReactiveCommand<Unit, string> _searchCommand;

public ICommand SearchCommand => _searchCommand;

private readonly ReactiveCommand<Unit, Unit> _clearCommand;

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?







share|improve this question











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);

_status = _currentState.Select(s => s.ToString()).ObserveOn(RxApp.MainThreadScheduler)
.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);

_searchCommand.SelectMany(HtmlDownloadService.GetHtmlDocument)
.Zip(_searchCommand, Tuple.Create)
.Do(_ => _currentState.OnNext(MainViewModelState.ExtractingImageUrl))
.Select(tuple => ImageExtractService.ExtractAllImageAddress(tuple.Item1, tuple.Item2).Distinct())
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(
urls =>

_currentState.OnNext(MainViewModelState.PopulatingList);
urls.ToObservable().ObserveOn(RxApp.MainThreadScheduler).Subscribe(url =>
ImageList.Add(new ScrappedWebImageViewModel ImageUrl = url));
_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);
, canClear, RxApp.MainThreadScheduler);


#endregion

#region Properties

private IHtmlDownloadService _htmlDownloadService;

private IHtmlDownloadService HtmlDownloadService =>
_htmlDownloadService ?? (_htmlDownloadService = Locator.Current.GetService<IHtmlDownloadService>());

private IImageExtractService _imageExtractService;

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

private readonly BehaviorSubject<MainViewModelState> _currentState;

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

private readonly ObservableAsPropertyHelper<string> _status;

public string Status => _status.Value;

private readonly ObservableAsPropertyHelper<string> _progress;

public string Progress => _progress.Value;

private string _targetUrl;

public string TargetUrl

get => _targetUrl;
set => this.RaiseAndSetIfChanged(ref _targetUrl, value);


#endregion

#region Commands

private readonly ReactiveCommand<Unit, string> _searchCommand;

public ICommand SearchCommand => _searchCommand;

private readonly ReactiveCommand<Unit, Unit> _clearCommand;

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?









share|improve this question










share|improve this question




share|improve this question









asked Feb 8 at 10:25









wuLiao

61




61











  • 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 at 11:16
















  • 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 at 11:16















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 at 11:16




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 at 11:16















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187082%2fa-viewmodel-build-with-reactiveui-8-to-get-web-images%23new-answer', 'question_page');

);

Post as a guest



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187082%2fa-viewmodel-build-with-reactiveui-8-to-get-web-images%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation