public PatchersRunVM(ConfigurationVM parent, ProfileVM profile) { Config = parent; RunningProfile = profile; Patchers.AddOrUpdate(RunningProfile.Patchers.Items .Where(x => x.IsOn) .Select(p => p.ToRunner(this))); PatchersDisplay = Patchers.Connect() .ToObservableCollection(this); if (profile.SelectedPatcher != null && Patchers.TryGetValue(profile.SelectedPatcher.InternalID, out var run)) { SelectedPatcher = run; } BackCommand = ReactiveCommand.Create(() => { profile.DisplayedObject = SelectedPatcher?.Config; parent.MainVM.ActivePanel = parent; }, canExecute: this.WhenAnyValue(x => x.Running) .Select(running => !running)); CancelCommand = ReactiveCommand.CreateFromTask( execute: Cancel, canExecute: this.WhenAnyValue(x => x.Running)); _reporter.Overall .ObserveOnGui() .Subscribe(ex => { Log.Logger.Error(ex, "Error while running patcher pipeline"); ResultError = ex; }) .DisposeWith(this); _reporter.PrepProblem .Select(data => (data, type: "prepping")) .Merge(_reporter.RunProblem .Select(data => (data, type: "running"))) .ObserveOnGui() .Subscribe(i => { var vm = Patchers.Get(i.data.Key); vm.State = GetResponse <RunState> .Fail(RunState.Error, i.data.Error); SelectedPatcher = vm; Log.Logger .ForContext(nameof(PatcherVM.DisplayName), i.data.Run.Name) .Error(i.data.Error, $"Error while {i.type}"); }) .DisposeWith(this); _reporter.Starting .ObserveOnGui() .Subscribe(i => { var vm = Patchers.Get(i.Key); vm.State = GetResponse <RunState> .Succeed(RunState.Started); Log.Logger .ForContext(nameof(PatcherVM.DisplayName), i.Run.Name) .Information($"Starting"); // Handle automatic selection advancement if (_previousPatcher == SelectedPatcher && (SelectedPatcher?.AutoScrolling ?? true)) { SelectedPatcher = vm; } _previousPatcher = vm; }) .DisposeWith(this); _reporter.RunSuccessful .ObserveOnGui() .Subscribe(i => { var vm = Patchers.Get(i.Key); vm.State = GetResponse <RunState> .Succeed(RunState.Finished); Log.Logger .ForContext(nameof(PatcherVM.DisplayName), i.Run.Name) .Information("Finished {RunTime}", vm.RunTime); }) .DisposeWith(this); _reporter.Output .Subscribe(s => { Log.Logger .ForContextIfNotNull(nameof(PatcherVM.DisplayName), s.Run?.Name) .Information(s.String); }) .DisposeWith(this); _reporter.Error .Subscribe(s => { Log.Logger .ForContextIfNotNull(nameof(PatcherVM.DisplayName), s.Run?.Name) .Error(s.String); }) .DisposeWith(this); // Clear selected patcher on showing error this.ShowOverallErrorCommand.StartingExecution() .Subscribe(_ => this.SelectedPatcher = null) .DisposeWith(this); _DetailDisplay = Observable.Merge( this.WhenAnyValue(x => x.SelectedPatcher) .Select(i => i as object), this.ShowOverallErrorCommand.EndingExecution() .Select(_ => ResultError == null ? null : new ErrorVM("Patching Error", ResultError.ToString()))) .ToGuiProperty(this, nameof(DetailDisplay), default); }