// The original source allows for un-registered view models to be new()'d // this extension provides that same ability, but again with a strongly typed return value public static IReactiveCommand <T> StrongNewNavigateCommandFor <T>(this RoutingState This, IReactiveCommand <object> navigationCommand = null, IDependencyResolver dependencyResolver = null, string contract = null) where T : IRoutableViewModel, new() { navigationCommand = navigationCommand ?? This.Navigate; var ret = new ReactiveCommand <T>(navigationCommand.CanExecuteObservable.Skip(1), _ => Observable.Return((T)((IRoutableViewModel)(dependencyResolver ?? Locator.Current).GetService <T>(contract) ?? new T()))); ret.InvokeCommand(navigationCommand); return(ret); }
// My attempt to optimize the return value to be strongly typed // I'm not sure if this has any implications public static IReactiveCommand <T> NavigateCommandFor3 <T>(this RoutingState This, IReactiveCommand <object> navigationCommand = null, IDependencyResolver dependencyResolver = null, string contract = null) where T : IRoutableViewModel { navigationCommand = navigationCommand ?? This.Navigate; var ret = new ReactiveCommand <T>(navigationCommand.CanExecuteObservable, _ => Observable.Return((dependencyResolver ?? Locator.Current).GetService <T>(contract))); ret.InvokeCommand(navigationCommand); return(ret.SubscribeToCommand()); }
public SearchViewModel(IScreen hostScreen, ILoginMethods loginMethods, [Named("UserAccount")] IBlobCache userCache) { HostScreen = hostScreen; SearchResults = new ReactiveCollection <ISongTileViewModel>(); var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { hostScreen.Router.Navigate.Execute(RxApp.GetService <IWelcomeViewModel>()); return; } var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value)); PerformSearch = new ReactiveAsyncCommand(canSearch); this.ObservableForProperty(x => x.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .InvokeCommand(PerformSearch); var searchResults = PerformSearch.RegisterAsyncObservable(_ => userCache.GetOrFetchObject( "search__" + SearchQuery, () => playApi.Search(SearchQuery), RxApp.TaskpoolScheduler.Now + TimeSpan.FromMinutes(1.0))); SearchResults = searchResults .Do(_ => SearchResults.Clear()) .SelectMany(list => list.ToObservable()) .LoggedCatch(this, Observable.Empty <Song>()) .CreateCollection(x => (ISongTileViewModel) new SongTileViewModel(x, playApi)); PerformSearch.ItemsInflight.StartWith(0) .Select(x => x > 0 ? Visibility.Visible : Visibility.Hidden) .ToProperty(this, x => x.SearchBusySpinner); PerformSearch.ThrownExceptions.Subscribe(_ => { }); GoBack = new ReactiveCommand(); GoBack.InvokeCommand(hostScreen.Router.NavigateBack); }
public SearchViewModel(IScreen hostScreen, ILoginMethods loginMethods) { HostScreen = hostScreen; SearchResults = new ReactiveCollection<ISongTileViewModel>(); var playApi = loginMethods.CurrentAuthenticatedClient; if (playApi == null) { hostScreen.Router.Navigate.Execute(RxApp.GetService<IWelcomeViewModel>()); return; } var canSearch = this.WhenAny(x => x.SearchQuery, x => !String.IsNullOrWhiteSpace(x.Value)); PerformSearch = new ReactiveAsyncCommand(canSearch); this.ObservableForProperty(x => x.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(700), RxApp.DeferredScheduler) .InvokeCommand(PerformSearch); var searchResults = PerformSearch.RegisterAsyncObservable(_ => playApi.Search(SearchQuery)); SearchResults = searchResults .Do(_ => SearchResults.Clear()) .SelectMany(list => list.ToObservable()) .LoggedCatch(this, Observable.Empty<Song>()) .CreateCollection(x => (ISongTileViewModel) new SongTileViewModel(x, playApi)); PerformSearch.ItemsInflight.StartWith(0) .Select(x => x > 0 ? Visibility.Visible : Visibility.Collapsed) .ToProperty(this, x => x.SearchBusySpinner); PerformSearch.ThrownExceptions.Subscribe(_ => { }); GoBack = new ReactiveCommand(); GoBack.InvokeCommand(hostScreen.Router.NavigateBack); }
public ProviderViewModel( CreateFolderViewModelFactory createFolder, RenameFileViewModelFactory createRename, FileViewModelFactory createFile, IAuthViewModel authViewModel, IFileManager fileManager, IProvider provider, IScheduler current, IScheduler main) { _provider = provider; Folder = createFolder(this); Rename = createRename(this); var canInteract = this .WhenAnyValue( x => x.Folder.IsVisible, x => x.Rename.IsVisible, (folder, rename) => !folder && !rename); _canInteract = canInteract .DistinctUntilChanged() .ToProperty(this, x => x.CanInteract, scheduler: current); _refresh = ReactiveCommand.CreateFromTask( () => provider.Get(CurrentPath), canInteract, main); _files = _refresh .Select(files => files .Select(file => createFile(file, this)) .OrderByDescending(file => file.IsFolder) .ThenBy(file => file.Name) .ToList()) .StartWithEmpty() .Where(files => Files == null || files.Count != Files.Count() || !files.All(x => Files.Any(y => x.Path == y.Path && x.Modified == y.Modified))) .ToProperty(this, x => x.Files, scheduler: current); _isLoading = _refresh .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: current); _isReady = _refresh .IsExecuting .Select(executing => !executing) .Skip(1) .ToProperty(this, x => x.IsReady, scheduler: current); var canOpenCurrentPath = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && file.IsFolder) .CombineLatest(_refresh.IsExecuting, (folder, busy) => folder && !busy) .CombineLatest(canInteract, (open, interact) => open && interact); _open = ReactiveCommand.Create( () => Path.Combine(CurrentPath, SelectedFile.Name), canOpenCurrentPath, main); var canCurrentPathGoBack = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path.Length > provider.InitialPath.Length) .CombineLatest(_refresh.IsExecuting, (valid, busy) => valid && !busy) .CombineLatest(canInteract, (back, interact) => back && interact); _back = ReactiveCommand.Create( () => Path.GetDirectoryName(CurrentPath), canCurrentPathGoBack, main); _currentPath = _open .Merge(_back) .DistinctUntilChanged() .Log(this, $"Current path changed in {provider.Name}") .ToProperty(this, x => x.CurrentPath, provider.InitialPath, scheduler: current); this.WhenAnyValue(x => x.CurrentPath) .Skip(1) .Select(path => Unit.Default) .InvokeCommand(_refresh); this.WhenAnyValue(x => x.CurrentPath) .Subscribe(path => SelectedFile = null); _isCurrentPathEmpty = this .WhenAnyValue(x => x.Files) .Skip(1) .Where(files => files != null) .Select(files => !files.Any()) .ToProperty(this, x => x.IsCurrentPathEmpty, scheduler: current); _hasErrors = _refresh .ThrownExceptions .Select(exception => true) .Merge(_refresh.Select(x => false)) .ToProperty(this, x => x.HasErrors, scheduler: current); var canUploadToCurrentPath = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path != null) .CombineLatest(_refresh.IsExecuting, (up, loading) => up && !loading) .CombineLatest(canInteract, (upload, interact) => upload && interact); _uploadToCurrentPath = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(fileManager.OpenRead) .Where(response => response.Name != null && response.Stream != null) .Select(x => _provider.UploadFile(CurrentPath, x.Stream, x.Name)) .SelectMany(task => task.ToObservable()), canUploadToCurrentPath, main); _uploadToCurrentPath.InvokeCommand(_refresh); var canDownloadSelectedFile = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .CombineLatest(_refresh.IsExecuting, (down, loading) => down && !loading) .CombineLatest(canInteract, (download, interact) => download && interact); _downloadSelectedFile = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(() => fileManager.OpenWrite(SelectedFile.Name)) .Where(stream => stream != null) .Select(stream => _provider.DownloadFile(SelectedFile.Path, stream)) .SelectMany(task => task.ToObservable()), canDownloadSelectedFile, main); var isAuthEnabled = provider.SupportsDirectAuth || provider.SupportsOAuth; var canLogout = provider .IsAuthorized .Select(loggedIn => loggedIn && isAuthEnabled) .DistinctUntilChanged() .CombineLatest(canInteract, (logout, interact) => logout && interact) .ObserveOn(main); _logout = ReactiveCommand.CreateFromTask(provider.Logout, canLogout); _canLogout = canLogout .ToProperty(this, x => x.CanLogout, scheduler: current); var canDeleteSelection = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .CombineLatest(_refresh.IsExecuting, (del, loading) => del && !loading) .CombineLatest(canInteract, (delete, interact) => delete && interact); _deleteSelectedFile = ReactiveCommand.CreateFromTask( () => provider.Delete(SelectedFile.Path, SelectedFile.IsFolder), canDeleteSelection); _deleteSelectedFile.InvokeCommand(Refresh); var canUnselectFile = this .WhenAnyValue(x => x.SelectedFile) .Select(selection => selection != null) .CombineLatest(_refresh.IsExecuting, (sel, loading) => sel && !loading) .CombineLatest(canInteract, (unselect, interact) => unselect && interact); _unselectFile = ReactiveCommand.Create( () => { SelectedFile = null; }, canUnselectFile); _uploadToCurrentPath .ThrownExceptions .Merge(_deleteSelectedFile.ThrownExceptions) .Merge(_downloadSelectedFile.ThrownExceptions) .Merge(_refresh.ThrownExceptions) .Log(this, $"Exception occured in provider {provider.Name}") .Subscribe(); Auth = authViewModel; Activator = new ViewModelActivator(); this.WhenActivated(disposable => { this.WhenAnyValue(x => x.Auth.IsAuthenticated) .Where(authenticated => authenticated) .Select(ignore => Unit.Default) .InvokeCommand(_refresh) .DisposeWith(disposable); var interval = TimeSpan.FromSeconds(1); Observable.Timer(interval, interval) .Select(unit => RefreshingIn - 1) .Where(value => value >= 0) .ObserveOn(main) .Subscribe(x => RefreshingIn = x) .DisposeWith(disposable); this.WhenAnyValue(x => x.RefreshingIn) .Skip(1) .Where(refreshing => refreshing == 0) .Log(this, $"Refreshing provider {provider.Name} path {CurrentPath}") .Select(value => Unit.Default) .InvokeCommand(_refresh) .DisposeWith(disposable); const int refreshPeriod = 30; _refresh.Select(results => refreshPeriod) .StartWith(refreshPeriod) .Subscribe(x => RefreshingIn = x) .DisposeWith(disposable); this.WhenAnyValue(x => x.CanInteract) .Skip(1) .Where(interact => interact) .Select(x => Unit.Default) .InvokeCommand(_refresh); }); }
public CpTabViewModel(SimulationOptions options) : base("Порівняння") { var logger = Logger.New(typeof(CpTabViewModel)); using (logger.LogPerf("Init")) { InitComponents(options); m_Player = new Player(() => { Simulate(0.05d); }, () => { for (int i = 0; i < 50; i++) { Simulate(); } }, () => { UpdateVisualization.Execute().Subscribe(); }, TimeSpan.FromMilliseconds(10), DispatcherPriority.ContextIdle); UpdateVisualization = ReactiveCommand.Create(() => { using (logger.LogPerf("Visualization")) { PrVisualization = m_Visualizer.GenerateTableVisualization(m_PrSimulator.GetData()); StVisualization = m_Visualizer.GenerateEdgeTableVisualization(m_StSimulator.GetData()); DiffVisualization = m_Visualizer.GenerateEdgeTableVisualization(m_DiffGenerator.GetData()); PrSimulationInfo = m_PrSimulator.SimulationInfo; StSimulationInfo = m_StSimulator.SimulationInfo; } }); var notRunningOrPlaying = m_Player.WhenAny(x => x.RunningOrPlaying, r => !r.Value); var notSingleStepRunning = m_Player.WhenAny(x => x.SingleStepRunning, r => !r.Value); SimulateStep = ReactiveCommand.Create(() => { m_Player.StepOnce(); }, notRunningOrPlaying); PlayPause = new ReactivePlayPauseCommand("Програти", "Пауза", notSingleStepRunning); PlayPause.Subscribe(p => { if (p) { m_Player.Start(); } else { m_Player.Stop(); } }); Restart = ReactiveCommand.Create(() => { m_PrSimulator.Reset(); m_StSimulator.Reset(); }, notRunningOrPlaying); Restart.InvokeCommand(UpdateVisualization); OpenSimualationOptions = ReactiveCommand.Create(() => { SimulationOptionsDialog dialog = new SimulationOptionsDialog(SimulationOptions.FromSimulator(m_PrSimulator)); dialog.ShowDialog(); if (dialog.DialogResult.GetValueOrDefault(false)) { SimulationOptions result = dialog.SimulationOptions; InitComponents(result); } }, notRunningOrPlaying); OpenSimualationOptions.InvokeCommand(UpdateVisualization); Settings.SettingsChange .InvokeCommand(UpdateVisualization); UpdateVisualization.Execute().Subscribe(); } }
public RenameFileViewModel( IProviderViewModel providerViewModel, IProvider provider, IScheduler current, IScheduler main) { _oldName = providerViewModel .WhenAnyValue(x => x.SelectedFile) .Select(file => file?.Name) .ToProperty(this, x => x.OldName, scheduler: current); var canInteract = providerViewModel .WhenAnyValue(x => x.CanInteract); var oldNameValid = this .WhenAnyValue(x => x.OldName) .Select(old => !string.IsNullOrWhiteSpace(old)); var canOpen = this .WhenAnyValue(x => x.IsVisible) .Select(visible => !visible) .CombineLatest(oldNameValid, (visible, old) => visible && old) .CombineLatest(canInteract, (open, interact) => open && interact); _open = ReactiveCommand.Create( () => { IsVisible = true; }, canOpen, main); var canClose = this .WhenAnyValue(x => x.IsVisible) .Select(visible => visible); _close = ReactiveCommand.Create( () => { IsVisible = false; }, canClose, main); var canRename = this .WhenAnyValue(x => x.NewName) .Select(name => !string.IsNullOrWhiteSpace(name)) .CombineLatest(oldNameValid, (old, name) => old && name); _rename = ReactiveCommand.CreateFromTask( () => provider.RenameFile(providerViewModel.SelectedFile.Path, NewName), canRename, main); _isLoading = _rename .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: current); _hasErrors = _rename .ThrownExceptions .Select(exception => true) .Merge(_close.Select(x => false)) .ToProperty(this, x => x.HasErrors, scheduler: current); _errorMessage = _rename .ThrownExceptions .Select(exception => exception.Message) .Log(this, $"Rename file error occured in {provider.Name} for {OldName}") .Merge(_close.Select(x => string.Empty)) .ToProperty(this, x => x.ErrorMessage, scheduler: current); _rename.InvokeCommand(_close); _close.Subscribe(x => NewName = string.Empty); }
public ProviderViewModel( IAuthViewModel authViewModel, IFileManager fileManager, IScheduler currentThread, IScheduler mainThread, IProvider provider) { _provider = provider; _refresh = ReactiveCommand.CreateFromTask( () => provider.Get(CurrentPath), outputScheduler: mainThread); _files = _refresh .Select(files => files .OrderByDescending(file => file.IsFolder) .ThenBy(file => file.Name) .ToList()) .StartWithEmpty() .ToProperty(this, x => x.Files, scheduler: currentThread); _isLoading = _refresh .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: currentThread); _isReady = _refresh .IsExecuting .Select(executing => !executing) .Skip(1) .ToProperty(this, x => x.IsReady, scheduler: currentThread); var canOpenCurrentPath = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && file.IsFolder) .CombineLatest(_refresh.IsExecuting, (folder, busy) => folder && !busy); _open = ReactiveCommand.Create( () => Path.Combine(CurrentPath, SelectedFile.Name), canOpenCurrentPath, mainThread); var canCurrentPathGoBack = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path.Length > provider.InitialPath.Length) .CombineLatest(_refresh.IsExecuting, (valid, busy) => valid && !busy); _back = ReactiveCommand.Create( () => Path.GetDirectoryName(CurrentPath), canCurrentPathGoBack, mainThread); _currentPath = _open .Merge(_back) .DistinctUntilChanged() .ToProperty(this, x => x.CurrentPath, provider.InitialPath, scheduler: currentThread); this.WhenAnyValue(x => x.CurrentPath) .Skip(1) .Select(path => Unit.Default) .InvokeCommand(_refresh); this.WhenAnyValue(x => x.CurrentPath) .Subscribe(path => SelectedFile = null); _isCurrentPathEmpty = this .WhenAnyValue(x => x.Files) .Skip(2) .Where(files => files != null) .Select(files => !files.Any()) .ToProperty(this, x => x.IsCurrentPathEmpty, scheduler: currentThread); _hasErrors = _refresh .ThrownExceptions .Select(exception => true) .Merge(_refresh.Select(x => false)) .ToProperty(this, x => x.HasErrors, scheduler: currentThread); var canUploadToCurrentPath = this .WhenAnyValue(x => x.CurrentPath) .Select(path => path != null) .DistinctUntilChanged(); _uploadToCurrentPath = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(fileManager.OpenRead) .Where(response => response.Name != null && response.Stream != null) .Select(x => _provider.UploadFile(CurrentPath, x.Stream, x.Name)) .SelectMany(task => task.ToObservable()), canUploadToCurrentPath, mainThread); _uploadToCurrentPath.InvokeCommand(_refresh); var canDownloadSelectedFile = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder) .DistinctUntilChanged(); _downloadSelectedFile = ReactiveCommand.CreateFromObservable( () => Observable .FromAsync(() => fileManager.OpenWrite(SelectedFile.Name)) .Where(stream => stream != null) .Select(stream => _provider.DownloadFile(SelectedFile.Path, stream)) .SelectMany(task => task.ToObservable()), canDownloadSelectedFile, mainThread); _uploadToCurrentPath .ThrownExceptions .Merge(_downloadSelectedFile.ThrownExceptions) .Subscribe(Console.WriteLine); this.WhenAnyValue(x => x.SelectedFile) .Where(file => file != null && file.IsFolder) .Buffer(2, 1) .Select(files => (files.First().Path, files.Last().Path)) .DistinctUntilChanged() .Where(x => x.Item1 == x.Item2) .Select(ignore => Unit.Default) .InvokeCommand(_open); var isAuthEnabled = provider.SupportsDirectAuth || provider.SupportsOAuth; var canLogout = provider .IsAuthorized .Select(loggedIn => loggedIn && isAuthEnabled) .DistinctUntilChanged() .ObserveOn(mainThread); _logout = ReactiveCommand.CreateFromTask(provider.Logout, canLogout); _canLogout = canLogout .ToProperty(this, x => x.CanLogout, scheduler: currentThread); var canDeleteSelection = this .WhenAnyValue(x => x.SelectedFile) .Select(file => file != null && !file.IsFolder); _deleteSelectedFile = ReactiveCommand.CreateFromTask( () => provider.Delete(SelectedFile), canDeleteSelection); _deleteSelectedFile.InvokeCommand(Refresh); Auth = authViewModel; Activator = new ViewModelActivator(); this.WhenActivated(disposable => { this.WhenAnyValue(x => x.Auth.IsAuthenticated) .Where(authenticated => authenticated) .Select(ignore => Unit.Default) .InvokeCommand(_refresh) .DisposeWith(disposable); }); }
public CreateFolderViewModel( IProviderViewModel providerViewModel, IProvider provider, IScheduler current, IScheduler main) { _path = providerViewModel .WhenAnyValue(x => x.CurrentPath) .ToProperty(this, x => x.Path, scheduler: current); var canInteract = providerViewModel .WhenAnyValue(x => x.CanInteract); var pathValid = this .WhenAnyValue(x => x.Path) .Select(path => !string.IsNullOrWhiteSpace(path)); var canCreateFolder = this .WhenAnyValue(x => x.Name) .Select(name => !string.IsNullOrWhiteSpace(name)) .CombineLatest(pathValid, (name, path) => name && path); _create = ReactiveCommand.CreateFromTask( () => provider.CreateFolder(Path, Name), canCreateFolder, main); var canCreate = Observable.Return(provider.CanCreateFolder); var canOpen = this .WhenAnyValue(x => x.IsVisible) .Select(visible => !visible) .CombineLatest(canCreate, pathValid, (visible, can, path) => visible && path && can) .CombineLatest(canInteract, (open, interact) => open && interact); _open = ReactiveCommand.Create( () => { IsVisible = true; }, canOpen, main); var canClose = this .WhenAnyValue(x => x.IsVisible) .Select(visible => visible); _close = ReactiveCommand.Create( () => { IsVisible = false; }, canClose, main); _create.InvokeCommand(_close); _close.Subscribe(x => Name = string.Empty); _hasErrors = _create .ThrownExceptions .Select(exception => true) .Merge(_close.Select(unit => false)) .ToProperty(this, x => x.HasErrors, scheduler: current); _errorMessage = _create .ThrownExceptions .Select(exception => exception.Message) .Log(this, $"Create folder error occured in {provider.Name}") .Merge(_close.Select(unit => string.Empty)) .ToProperty(this, x => x.ErrorMessage, scheduler: current); _isLoading = _create .IsExecuting .ToProperty(this, x => x.IsLoading, scheduler: current); }