internal MainWindowViewModel(AppController controller) { this._controller = controller ?? throw new ArgumentNullException(nameof(controller)); Profiles = _controller.Profiles .ToReadOnlyReactiveCollection(x => new ProfileItemViewModel(_controller, x)) .AddTo(this.Subscription); Profiles .ObserveElementObservableProperty(x => x.Position) .Throttle(TimeSpan.FromMilliseconds(10)) .ObserveOn(SynchronizationContext.Current) .Subscribe(_ => ProfilesView.Refresh()) // ListCollectionView.Refresh method seems not thread-safe. .AddTo(this.Subscription); OrganizesPriority = new ReactiveProperty <bool>() .AddTo(this.Subscription); ShowsAvailable = Settings.Current.ToReactivePropertyAsSynchronized(x => x.ShowsAvailable) .AddTo(this.Subscription); ShowsAvailable .Subscribe(_ => ManageFilter()) .AddTo(this.Subscription); IsUpdating = _controller.IsUpdating .Where(_ => !_controller.IsWorking.Value) //.Select(x => Observable.Empty<bool>() // .Delay(TimeSpan.FromMilliseconds(10)) // .StartWith(x)) //.Concat() .ObserveOnUIDispatcher() .ToReadOnlyReactiveProperty() .AddTo(this.Subscription); #region Work var isNotWorking = _controller.IsWorking .Inverse() .StartWith(true) // This is necessary to start combined sequence. .Publish(); var selectedProfile = Profiles .ObserveElementObservableProperty(x => x.IsSelected) .Where(x => x.Value) .Select(x => x.Instance) .Publish(); var canProfileMovedUp = selectedProfile .Select(x => x.Position.Value > 0); MoveUpCommand = new[] { isNotWorking, canProfileMovedUp } .CombineLatestValuesAreAllTrue() .ObserveOnUIDispatcher() // This is for thread access by ReactiveCommand. .ToReactiveCommand(); MoveUpCommand .Subscribe(async _ => await _controller.MoveUpProfileAsync()) .AddTo(this.Subscription); var canProfileMovedDown = selectedProfile .Select(x => x.Position.Value < x.PositionCount.Value - 1); MoveDownCommand = new[] { isNotWorking, canProfileMovedDown } .CombineLatestValuesAreAllTrue() .ObserveOnUIDispatcher() // This is for thread access by ReactiveCommand. .ToReactiveCommand(); MoveDownCommand .Subscribe(async _ => await _controller.MoveDownProfileAsync()) .AddTo(this.Subscription); var canProfileDeleted = selectedProfile .Select(x => x.IsConnected) .Switch() .Inverse(); CanDelete = new[] { isNotWorking, canProfileDeleted } .CombineLatestValuesAreAllTrue() .ObserveOnUIDispatcher() // This is for thread access by ReactiveCommand. .ToReadOnlyReactiveProperty() .AddTo(this.Subscription); DeleteCommand = CanDelete .ToReactiveCommand(); DeleteCommand .Subscribe(async _ => await _controller.DeleteProfileAsync()) .AddTo(this.Subscription); isNotWorking.Connect().AddTo(this.Subscription); selectedProfile.Connect().AddTo(this.Subscription); #endregion }
public MainWindowViewModel() { Op = new Operation( //new MockWorker() ?? //new NetshWorker() ?? new NativeWifiWorker() as IWlanWorker); this.Profiles = Op.Profiles.ToReadOnlyReactiveCollection(x => new ProfileItemViewModel(x)); #region AutoReloadEnabled/Suspended/ConfigMode IsAutoReloadEnabled = Op .ToReactivePropertyAsSynchronized(x => x.IsAutoReloadEnabled); IsSuspended = Op .ToReactivePropertyAsSynchronized(x => x.IsSuspended); IsConfigMode = new ReactiveProperty <bool>(); IsAutoReloadEnabled .Merge(IsSuspended) .Where(x => x) .Subscribe(_ => IsConfigMode.Value = false); IsConfigMode .Where(x => x) .Subscribe(_ => IsAutoReloadEnabled.Value = false); #endregion #region Load IsLoading = Op.IsLoading .Where(_ => !Op.IsWorking.Value) //.Select(x => Observable.Empty<bool>() // .Delay(TimeSpan.FromMilliseconds(10)) // .StartWith(x)) //.Concat() .ObserveOnUIDispatcher() .ToReadOnlyReactiveProperty(); ReloadCommand = IsLoading .Select(x => !x) .ToReactiveCommand(); ReloadCommand .Subscribe(async _ => await Op.LoadProfilesAsync(true)); Profiles .ObserveElementObservableProperty(x => x.Position) .Throttle(TimeSpan.FromMilliseconds(10)) .ObserveOn(SynchronizationContext.Current) .Subscribe(_ => ProfilesView.Refresh()); // ListCollectionView.Refresh method seems not thread-safe. #endregion #region Work IsNotWorking = Op.IsWorking .Select(x => !x) .StartWith(true) // This is necessary for initial query. .ObserveOnUIDispatcher() .ToReadOnlyReactiveProperty(); // Query for a profile which is selected. var querySelectedProfiles = Profiles .ObserveElementObservableProperty(x => x.IsSelected) .Where(x => x.Value) .Select(x => x.Instance) .Publish(); // Query for the selected profile which is connected or disconnected. var queryConnectedProfiles = Profiles .ObserveElementObservableProperty(x => x.IsConnected) .Where(x => x.Instance.IsSelected.Value) .Select(x => x.Instance) .Publish(); // Query for the selected profile which changes to be available or unavailable. var queryAvailableProfiles = Profiles .ObserveElementObservableProperty(x => x.IsAvailable) .Where(x => x.Instance.IsSelected.Value) .Select(x => x.Instance) .Publish(); #region MoveUp var queryMoveUp = querySelectedProfiles .Select(x => x.Position.Value > 0); MoveUpCommand = new[] { IsNotWorking, queryMoveUp } .CombineLatestValuesAreAllTrue() .ToReactiveCommand(); MoveUpCommand .Subscribe(async _ => await Op.MoveUpProfileAsync()); #endregion #region MoveDown var queryMoveDown = querySelectedProfiles .Select(x => x.Position.Value < x.PositionCount.Value - 1); MoveDownCommand = new[] { IsNotWorking, queryMoveDown } .CombineLatestValuesAreAllTrue() .ToReactiveCommand(); MoveDownCommand .Subscribe(async _ => await Op.MoveDownProfileAsync()); #endregion #region Delete DeleteCommand = IsNotWorking .ToReactiveCommand(); DeleteCommand .Subscribe(async _ => await Op.DeleteProfileAsync()); #endregion #region Connect var queryConnect = Observable.Merge(querySelectedProfiles, queryConnectedProfiles, queryAvailableProfiles) .Select(x => !x.IsConnected.Value && x.IsAvailable.Value); ConnectCommand = new[] { IsNotWorking, queryConnect } .CombineLatestValuesAreAllTrue() .ToReactiveCommand(); ConnectCommand .Subscribe(async _ => await Op.ConnectNetworkAsync()); #endregion #region Disconnect var queryDisconnect = Observable.Merge(querySelectedProfiles, queryConnectedProfiles) .Select(x => x.IsConnected.Value); DisconnectCommand = new[] { IsNotWorking, queryDisconnect } .CombineLatestValuesAreAllTrue() .ToReactiveCommand(); DisconnectCommand .Subscribe(async _ => await Op.DisconnectNetworkAsync()); #endregion querySelectedProfiles.Connect(); queryConnectedProfiles.Connect(); queryAvailableProfiles.Connect(); #endregion }