/// <summary>
        /// Initializes a new instance of the <see cref="ImageEditorViewModel" /> class.
        /// </summary>
        /// <param name="imageService">Service for image loading and manipulation.</param>
        public ImageEditorViewModel(IImageService imageService = null)
        {
            _imageService = imageService ?? Locator.Current.GetService <IImageService>();

            IObservable <ImageHandle> selectionChanges = this.WhenAnyValue(x => x.SelectedImage).Publish().RefCount();

            ImageExplorer = new ImageExplorerViewModel(_source.AsObservableCache());
            ImagePreview  = new ImagePreviewViewModel(selectionChanges);
            Settings      = new ImageSettingsViewModel(selectionChanges);

            SelectFolder = new Interaction <string, string>();

            LoadImage         = ReactiveCommand.CreateFromObservable <string, ImageHandle>(x => _imageService.LoadImage(x));
            ExportSelected    = ReactiveCommand.CreateFromObservable(ExportSelectedImpl);
            ExportAll         = ReactiveCommand.CreateFromObservable(ExportAllImpl);
            _calculatePreview = ReactiveCommand.CreateFromObservable <ImageHandle, ImageHandle>(x => _imageService.CalculatePreview(x));

            var connection = _source.Connect();

            this.WhenActivated(d =>
            {
                // Dispose handles removed from the source collection
                connection
                .DisposeMany()
                .ObserveOn(RxApp.MainThreadScheduler)
                .Bind(out _images)
                .Subscribe()
                .DisposeWith(d);

                // Recaluclate image when quality changes
                connection.WhenPropertyChanged(x => x.ManipulationState.Quality, false)
                .Throttle(TimeSpan.FromMilliseconds(50))
                .Select(x => x.Sender)
                .InvokeCommand(_calculatePreview)
                .DisposeWith(d);

                // Notify about successful export.
                ExportSelected
                .Do(name => this.Notify().PublishInfo($"Image export to {name}", "Export completed!", TimeSpan.FromSeconds(3)))
                .Subscribe()
                .DisposeWith(d);

                // Notify about successful export.
                ExportAll
                .Do(path => this.Notify().PublishInfo($"All images exported to {path}", "Export completed!", TimeSpan.FromSeconds(3)))
                .Subscribe()
                .DisposeWith(d);

                // Add loaded images to source
                LoadImage
                .ObserveOn(RxApp.TaskpoolScheduler)
                .Where(x => x != null)
                .SelectMany(x => _calculatePreview.Execute(x))
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(handle => _source.AddOrUpdate(handle))
                .DisposeWith(d);

                // Show image loading error
                LoadImage.ThrownExceptions
                .OfType <ImageLoadingException>()
                .Subscribe(ex => this.Notify()
                           .PublishError($"Sorry. \"{ex.FilePath}\" does not have a supported file format.", "Error", TimeSpan.FromSeconds(5)))
                .DisposeWith(d);

                // Pipe loadings to property
                Observable.CombineLatest(
                    LoadImage.IsExecuting,
                    ExportSelected.IsExecuting,
                    ExportAll.IsExecuting,
                    _calculatePreview.IsExecuting,
                    (a, b, c, d) => a || b || c || d)
                .ObserveOn(RxApp.MainThreadScheduler)
                .ToPropertyEx(this, x => x.IsLoading)
                .DisposeWith(d);

                // React on close requests from explorer view
                this.WhenAnyObservable(x => x.ImageExplorer.DeletionRequests)
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(x => _source.Remove(x))
                .DisposeWith(d);

                // Select explorer item
                this.WhenAnyObservable(x => x.ImageExplorer.Selections)
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(x => SelectedImage = x)
                .DisposeWith(d);
            });
        }