Модель представления сборки с ReactiveUI 8, чтобы получить веб-изображений


Это практика применения, которую я построил, чтобы узнать Rx.Net & RxUI. Следует шаблоне MVVM и написан на C# с использованием WPF. Вот ссылка на вопрос, который я задал в ходе разработки, которая включает в себя некоторую информацию об этом приложении. Теперь, когда он наконец закончится, я хочу, чтобы улучшить его, устраняя любые потенциальные недостатки в коде, который представлен следующим образом:

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
}

Во время моих тестов, я заметил, что когда извлечения URL-адреса, интерфейс стал отвечать, но я не могу выяснить, лучший способ, чтобы сделать это. Также хочу добавить, функции отмены, но это кажется довольно сложно реализовать с текущим кодом, возможно, я не слежу за лучшие практики?



247
1
задан 8 февраля 2018 в 10:02 Источник Поделиться
Комментарии