public void Initialize <TState>(ReduxStore <TState> store) where TState : class, new() { if (store.TimeTravelEnabled) { // TODO : Cannot activate History component } // Observe UI events UndoButton.Events().Click .Subscribe(_ => store.Undo()); RedoButton.Events().Click .Subscribe(_ => store.Redo()); ResetButton.Events().Click .Subscribe(_ => store.Reset()); PlayPauseButton.Events().Click .Subscribe(_ => _internalStore.Dispatch(new TogglePlayPauseAction())); Slider.Events().ValueChanged .Where(_ => Slider.FocusState != FocusState.Unfocused) .Subscribe(e => { int newPosition = (int)e.NewValue; _internalStore.Dispatch(new MoveToPositionAction { Position = newPosition }); }); // Observe changes on internal state _internalStore.Select(state => state.MaxPosition) .Subscribe(maxPosition => { Slider.Maximum = maxPosition; }); Observable.CombineLatest( _internalStore.Select(state => state.CurrentPosition), _internalStore.Select(state => state.PlaySessionActive), _internalStore.Select(state => state.MaxPosition), store.ObserveCanUndo(), store.ObserveCanRedo(), Tuple.Create ) .ObserveOnDispatcher() .Subscribe(x => { var(currentPosition, playSessionActive, maxPosition, canUndo, canRedo) = x; Slider.Value = currentPosition; if (playSessionActive) { UndoButton.IsEnabled = false; RedoButton.IsEnabled = false; ResetButton.IsEnabled = false; PlayPauseButton.IsEnabled = true; Slider.IsEnabled = false; PlayPauseButton.Content = "\xE769"; } else { UndoButton.IsEnabled = canUndo; RedoButton.IsEnabled = canRedo; ResetButton.IsEnabled = canUndo || canRedo; PlayPauseButton.IsEnabled = canRedo; Slider.IsEnabled = maxPosition > 0; PlayPauseButton.Content = "\xE768"; } }); _internalStore.ObserveAction <MoveToPositionAction>() .Subscribe(a => { if (a.Position < _internalStore.State.CurrentPosition) { for (int i = 0; i < _internalStore.State.CurrentPosition - a.Position; i++) { store.Undo(); } } if (a.Position > _internalStore.State.CurrentPosition) { for (int i = 0; i < a.Position - _internalStore.State.CurrentPosition; i++) { store.Redo(); } } }); // Observe changes on listened state var goForwardNormalActionOrigin = store.ObserveAction() .Select(action => new { Action = action, BreaksTimeline = true }); var goForwardRedoneActionOrigin = store.ObserveAction(ActionOriginFilter.Redone) .Select(action => new { Action = action, BreaksTimeline = false }); goForwardNormalActionOrigin.Merge(goForwardRedoneActionOrigin) .ObserveOnDispatcher() .Subscribe(x => { _internalStore.Dispatch(new GoForwardAction { Action = x.Action, BreaksTimeline = x.BreaksTimeline }); if (_internalStore.State.PlaySessionActive && !store.CanRedo) { _internalStore.Dispatch(new TogglePlayPauseAction()); } }); store.ObserveUndoneAction() .ObserveOnDispatcher() .Subscribe(_ => _internalStore.Dispatch(new GoBackAction())); store.ObserveReset() .ObserveOnDispatcher() .Subscribe(_ => _internalStore.Dispatch(new ResetAction())); _internalStore.Select(state => state.PlaySessionActive) .Select(playSessionActive => playSessionActive ? Observable.Interval(TimeSpan.FromSeconds(1)) : Observable.Empty <long>() ) .Switch() .ObserveOnDispatcher() .Subscribe(_ => { bool canRedo = store.Redo(); if (!canRedo) { _internalStore.Dispatch(new TogglePlayPauseAction()); } }); // Track redux actions _internalStore.ObserveAction() .Subscribe(action => { TrackReduxAction(action); }); }