public TimerStartCommandViewModel() { // ctorからカウント開始 var ctorDateTime = DateTime.Now; MyTimer1 = Observable.Interval(TimeSpan.FromSeconds(1)) .Select(_ => DateTime.Now - ctorDateTime) .ToReadOnlyReactivePropertySlim() .AddTo(CompositeDisposable); #if false // 1. DataTime.Now からの差分でカウント ◆もう少しかっちょよい実装ない? var clickDateTime = DateTime.MinValue; MyTimer2 = Observable.Interval(TimeSpan.FromSeconds(1)) .Where(_ => clickDateTime != DateTime.MinValue) .Select(_ => DateTime.Now - clickDateTime) .ToReadOnlyReactivePropertySlim() .AddTo(CompositeDisposable); StartCommand = new ReactiveCommand() .WithSubscribe(() => clickDateTime = DateTime.Now, CompositeDisposable.Add); StopCommand = new ReactiveCommand() .WithSubscribe(() => clickDateTime = DateTime.MinValue, CompositeDisposable.Add); #else // 2. BooleanNotifier で管理。Command.CanExecute も取れるので良い感じ var timerRunning = new BooleanNotifier(); // BooleanNotifier は IDisposable じゃないので Good! //var timerRunning = new ReactivePropertySlim<bool>(initialValue: false).AddTo(CompositeDisposable); MyTimer2 = Observable.Interval(TimeSpan.FromSeconds(1)) .TakeWhile(_ => timerRunning.Value) .Repeat() .Select(sec => TimeSpan.FromSeconds(sec)) .ToReadOnlyReactivePropertySlim() .AddTo(CompositeDisposable); StartCommand = timerRunning.Inverse() .ToReactiveCommand(!timerRunning.Value) .WithSubscribe(() => timerRunning.TurnOn(), CompositeDisposable.Add); // ◆BooleanNotifier は (Rpと違って) Subscribe 時に LatestValue を発行しないので初期値の指定が必要する StopCommand = timerRunning .ToReactiveCommand(timerRunning.Value) .WithSubscribe(() => timerRunning.TurnOff(), CompositeDisposable.Add); #endif }
public MainController(StartupAgent agent, IWlanWorker worker) { StartupAgent = agent ?? throw new ArgumentNullException(nameof(agent)); Profiles = new ObservableCollection <ProfileItem>(); BindingOperations.EnableCollectionSynchronization(Profiles, _profilesLock); NotifyIconContainer = new NotifyIconContainer(); NotifyIconContainer.MouseLeftButtonClick += OnMainWindowShowRequested; NotifyIconContainer.MouseRightButtonClick += OnMenuWindowShowRequested; this._worker = worker; IsUpdating = new BooleanNotifier(); IsWorking = new BooleanNotifier(); ShowUpdatingTime(); // For debug ShowWorkingTime(); // For debug RushesRescan = new ReactiveProperty <bool>() .AddTo(this.Subscription); EngagesPriority = new ReactiveProperty <bool>() .AddTo(this.Subscription); EngagesPriority .Subscribe(_ => SetNotifyIconText()) .AddTo(this.Subscription); #region Update RescanTimer = new ReactiveTimer(TimeSpan.FromSeconds(Settings.Current.RescanInterval)) .AddTo(this.Subscription); RescanCommand = IsUpdating .Inverse() .ObserveOnUIDispatcher() // This is for thread access by ReactiveCommand. .ToReactiveCommand(); RescanCommand .Merge(EngagesPriority.Where(x => x).Select(x => x as object)) .Merge(RescanTimer.Select(x => x as object)) .Subscribe(async _ => await ScanNetworkAsync()) .AddTo(this.Subscription); Settings.Current .ObserveProperty(x => x.RescanInterval) .Subscribe(rescanInterval => RescanTimer.Interval = TimeSpan.FromSeconds(rescanInterval)) .AddTo(this.Subscription); RushesRescan .Subscribe(rushesRescan => { if (rushesRescan) { RescanTimer.Start(); } else { RescanTimer.Stop(); } SetNotifyIconText(); }) .AddTo(this.Subscription); var networkRefreshed = Observable.FromEventPattern( h => _worker.NetworkRefreshed += h, h => _worker.NetworkRefreshed -= h); var availabilityChanged = Observable.FromEventPattern( h => _worker.AvailabilityChanged += h, h => _worker.AvailabilityChanged -= h); var interfaceChanged = Observable.FromEventPattern( h => _worker.InterfaceChanged += h, h => _worker.InterfaceChanged -= h); var connectionChanged = Observable.FromEventPattern( h => _worker.ConnectionChanged += h, h => _worker.ConnectionChanged -= h); var profileChanged = Observable.FromEventPattern( h => _worker.ProfileChanged += h, h => _worker.ProfileChanged -= h); Observable.Merge(networkRefreshed, availabilityChanged, interfaceChanged, connectionChanged, profileChanged) .Throttle(TimeSpan.FromMilliseconds(100)) .Subscribe(async _ => { if (RushesRescan.Value) { RescanTimer.Start(TimeSpan.FromSeconds(Settings.Current.RescanInterval)); // Wait for due time. } await LoadProfilesAsync(); }) .AddTo(this.Subscription); #endregion #region Close CloseCommand = new ReactiveProperty <bool>(true) .ToReactiveCommand(); CloseCommand .Subscribe(_ => _current.Shutdown()) .AddTo(this.Subscription); #endregion }