public void AllowConcurrentExecutionTest() { (new TestScheduler()).With(sched => { var fixture = new ReactiveCommand(null, true, sched); Assert.True(fixture.CanExecute(null)); var result = fixture.RegisterAsync(_ => Observable.Return(4).Delay(TimeSpan.FromSeconds(5), sched)) .CreateCollection(); Assert.Equal(0, result.Count); sched.AdvanceToMs(25); Assert.Equal(0, result.Count); fixture.Execute(null); Assert.True(fixture.CanExecute(null)); Assert.Equal(0, result.Count); sched.AdvanceToMs(2500); Assert.True(fixture.CanExecute(null)); Assert.Equal(0, result.Count); sched.AdvanceToMs(5500); Assert.True(fixture.CanExecute(null)); Assert.Equal(1, result.Count); }); }
public void ReactiveCommandAllFlow() { var testScheduler = new TestScheduler(); var @null = (object)null; var recorder1 = testScheduler.CreateObserver<object>(); var recorder2 = testScheduler.CreateObserver<object>(); var cmd = new ReactiveCommand(); cmd.Subscribe(recorder1); cmd.Subscribe(recorder2); cmd.CanExecute().Is(true); cmd.Execute(); testScheduler.AdvanceBy(10); cmd.Execute(); testScheduler.AdvanceBy(10); cmd.Execute(); testScheduler.AdvanceBy(10); cmd.Dispose(); cmd.CanExecute().Is(false); cmd.Dispose(); // dispose again recorder1.Messages.Is( OnNext(0, @null), OnNext(10, @null), OnNext(20, @null), OnCompleted<object>(30)); recorder2.Messages.Is( OnNext(0, @null), OnNext(10, @null), OnNext(20, @null), OnCompleted<object>(30)); }
public void DisallowConcurrentExecutionTest() { (new TestScheduler()).With(sched => { var fixture = new ReactiveCommand(null, false, sched); Assert.True(fixture.CanExecute(null)); var result = fixture.RegisterAsync(_ => Observable.Return(4).Delay(TimeSpan.FromSeconds(5), sched)) .CreateCollection(); Assert.Equal(0, result.Count); sched.AdvanceToMs(25); Assert.Equal(0, result.Count); fixture.Execute(null); Assert.False(fixture.CanExecute(null)); Assert.Equal(0, result.Count); sched.AdvanceToMs(2500); Assert.False(fixture.CanExecute(null)); Assert.Equal(0, result.Count); sched.AdvanceToMs(5500); Assert.True(fixture.CanExecute(null)); Assert.Equal(1, result.Count); }); }
public void MultipleSubscribersShouldntDecrementRefcountBelowZero() { (new TestScheduler()).With(sched => { var fixture = new ReactiveCommand(); var results = new List <int>(); bool[] subscribers = new[] { false, false, false, false, false }; var output = fixture.RegisterAsync(_ => Observable.Return(5).Delay(TimeSpan.FromMilliseconds(5000), sched)); output.Subscribe(x => results.Add(x)); Enumerable.Range(0, 5).Run(x => output.Subscribe(_ => subscribers[x] = true)); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(2000); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(6000); Assert.True(fixture.CanExecute(null)); Assert.True(results.Count == 1); Assert.True(results[0] == 5); Assert.True(subscribers.All(x => x)); }); }
public void ReactiveCommandAllFlow() { var testScheduler = new TestScheduler(); var @null = (object)null; var recorder1 = testScheduler.CreateObserver <object>(); var recorder2 = testScheduler.CreateObserver <object>(); var cmd = new ReactiveCommand(); cmd.Subscribe(recorder1); cmd.Subscribe(recorder2); cmd.CanExecute().Is(true); cmd.Execute(); testScheduler.AdvanceBy(10); cmd.Execute(); testScheduler.AdvanceBy(10); cmd.Execute(); testScheduler.AdvanceBy(10); cmd.Dispose(); cmd.CanExecute().Is(false); cmd.Dispose(); // dispose again recorder1.Messages.Is( OnNext(0, @null), OnNext(10, @null), OnNext(20, @null), OnCompleted <object>(30)); recorder2.Messages.Is( OnNext(0, @null), OnNext(10, @null), OnNext(20, @null), OnCompleted <object>(30)); }
public void CanExecuteShouldChangeOnInflightOp() { (new TestScheduler()).With(sched => { var canExecute = sched.CreateHotObservable( sched.OnNextAt(0, true), sched.OnNextAt(250, false), sched.OnNextAt(500, true), sched.OnNextAt(750, false), sched.OnNextAt(1000, true), sched.OnNextAt(1100, false) ); var fixture = new ReactiveCommand(canExecute); int calculatedResult = -1; bool latestCanExecute = false; fixture.RegisterAsync(x => Observable.Return((int)x*5).Delay(TimeSpan.FromMilliseconds(900), RxApp.MainThreadScheduler)) .Subscribe(x => calculatedResult = x); fixture.CanExecuteObservable.Subscribe(x => latestCanExecute = x); // CanExecute should be true, both input observable is true // and we don't have anything inflight sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); // Invoke a command 10ms in fixture.Execute(1); // At 300ms, input is false sched.AdvanceToMs(300); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // At 600ms, input is true, but the command is still running sched.AdvanceToMs(600); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // After we've completed, we should still be false, since from // 750ms-1000ms the input observable is false sched.AdvanceToMs(900); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); Assert.Equal(-1, calculatedResult); sched.AdvanceToMs(1010); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); Assert.Equal(calculatedResult, 5); sched.AdvanceToMs(1200); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); }); }
public static void Bind(this Button button, ReactiveCommand command) { button.Enabled = command.CanExecute(); command.CanExecuteChanged += (_, __) => { button.BeginInvoke((Action) delegate() { button.Enabled = command.CanExecute(); }); }; button.Click += (_, __) => command.Execute(); }
public async Task ReactiveCommandTest() { var c = new ReactiveCommand(true); var v = false; c.CanExecuteChanged += (o, e) => v = c.CanExecute(null); c.ListenCanExecuteObservable(Observable.Delay(Observable.Range(0, 1).Select(xxx => false), DateTimeOffset.Now.AddMilliseconds(15))); Assert.AreEqual(c.CanExecute(null), true); await Task.Delay(100); Assert.AreEqual(v, false); }
public void RaisesCanExecuteChangedWithNextCanExecuteImplementation( Subject <Func <object, bool> > source, object parameter) { var sut = new ReactiveCommand <Unit>( source, _ => Task.FromResult(Unit.Default)); sut.MonitorEvents(); source.OnNext(p => p == parameter); sut.ShouldRaise(nameof(sut.CanExecuteChanged)) .WithSender(sut).WithArgs <EventArgs>(a => a == EventArgs.Empty); sut.CanExecute(parameter).Should().BeTrue(); sut.CanExecute(new object()).Should().BeFalse(); }
public void ReactiveCommandInitialConditionNewBehavior() { (new TestScheduler()).With(sched => { var canExecute = sched.CreateHotObservable( sched.OnNextAt(0, false), sched.OnNextAt(250, true) ); var fixture = new ReactiveCommand(canExecute, initialCondition: false); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(10); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(255); Assert.True(fixture.CanExecute(null)); }); }
public void CommandInitialConditionShouldBeAdjustable() { var sub = new Subject <bool>(); var cmd = new ReactiveCommand(sub); Assert.Equal(true, cmd.CanExecute(null)); var cmd2 = new ReactiveCommand(sub, false); Assert.Equal(false, cmd2.CanExecute(null)); }
/// <summary> /// To the event handler. /// </summary> /// <typeparam name="TEventArgs">The type of the event arguments.</typeparam> /// <param name="self">The self.</param> /// <returns></returns> public static EventHandler <TEventArgs> ToEventHandler <TEventArgs>(this ReactiveCommand self) { EventHandler <TEventArgs> h = (s, e) => { if (self.CanExecute()) { self.Execute(); } }; return(h); }
public void CommandCanExecute_Test() { //Given string result = null; string expected = Any.Create<string>(); ICommand command = new ReactiveCommand<string>(t => result = t, _ => false); //When bool canExecute = command.CanExecute(null); command.Execute(expected); //Then Assert.That(canExecute, Is.False); Assert.That(result, Is.Null); }
public void Command_Test() { //Given string result = null; string expected = Any.Create<string>(); ICommand command = new ReactiveCommand<string>(t => result = t, _ => true); //When bool canExecute = command.CanExecute(null); command.Execute(expected); //Then Assert.That(expected, Is.EqualTo(result)); Assert.That(canExecute, Is.True); }
/// <summary> /// To the event handler. /// </summary> /// <typeparam name="TEventArgs">The type of the event arguments.</typeparam> /// <typeparam name="T"></typeparam> /// <param name="self">The self.</param> /// <param name="converter">The converter.</param> /// <returns></returns> public static EventHandler <TEventArgs> ToEventHandler <TEventArgs, T>(this ReactiveCommand <T> self, Func <TEventArgs, T> converter) { EventHandler <TEventArgs> h = (s, e) => { var parameter = converter(e); if (self.CanExecute()) { self.Execute(parameter); } }; return(h); }
public void CanExecuteShouldChangeOnInflightOp() { (new TestScheduler()).With(sched => { var canExecute = sched.CreateHotObservable( sched.OnNextAt(0, true), sched.OnNextAt(250, false), sched.OnNextAt(500, true), sched.OnNextAt(750, false), sched.OnNextAt(1000, true), sched.OnNextAt(1100, false) ); var fixture = new ReactiveCommand(canExecute); int calculatedResult = -1; bool latestCanExecute = false; fixture.RegisterAsync(x => Observable.Return((int)x * 5).Delay(TimeSpan.FromMilliseconds(900), RxApp.MainThreadScheduler)) .Subscribe(x => calculatedResult = x); fixture.CanExecuteObservable.Subscribe(x => latestCanExecute = x); // CanExecute should be true, both input observable is true // and we don't have anything inflight sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); // Invoke a command 10ms in fixture.Execute(1); // At 300ms, input is false sched.AdvanceToMs(300); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // At 600ms, input is true, but the command is still running sched.AdvanceToMs(600); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); // After we've completed, we should still be false, since from // 750ms-1000ms the input observable is false sched.AdvanceToMs(900); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); Assert.Equal(-1, calculatedResult); sched.AdvanceToMs(1010); Assert.True(fixture.CanExecute(1)); Assert.True(latestCanExecute); Assert.Equal(calculatedResult, 5); sched.AdvanceToMs(1200); Assert.False(fixture.CanExecute(1)); Assert.False(latestCanExecute); }); }
public void RegisterAsyncFunctionSmokeTest() { (new TestScheduler()).With(sched => { var fixture = new ReactiveCommand(); IReactiveDerivedList <int> results; results = fixture.RegisterAsync(_ => Observable.Return(5).Delay(TimeSpan.FromSeconds(5), sched)).CreateCollection(); var inflightResults = fixture.IsExecuting.CreateCollection(); sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(1005); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(5100); Assert.True(fixture.CanExecute(null)); new[] { false, true, false }.AssertAreEqual(inflightResults); new[] { 5 }.AssertAreEqual(results); }); }
public void CompletelyDefaultReactiveCommandShouldFire() { var sched = new TestScheduler(); var fixture = new ReactiveCommand(null, sched); Assert.IsTrue(fixture.CanExecute(null)); string result = null; fixture.Subscribe(x => result = x as string); fixture.Execute("Test"); sched.Start(); Assert.AreEqual("Test", result); fixture.Execute("Test2"); sched.Start(); Assert.AreEqual("Test2", result); }
public void FullCommand_Test() { //Given const string message = "Reactive"; string result = null; bool completed = false; Exception exception = null; string expected = Any.Create<string>(); var command = new ReactiveCommand<string>(t => result = t, _ => true,ex => exception = ex,() => completed = true ); //When bool canExecute = command.CanExecute(null); command.Execute(expected); command.OnError(new Exception(message)); command.OnCompleted(); //Then Assert.True(canExecute); Assert.AreEqual(result, expected); Assert.That(exception.Message, Is.EqualTo(message)); Assert.True(completed); }
internal static IDisposable BindToCheckBox(this ReactiveCommand command, CheckBox checkBox) { CompositeDisposable disposable = new CompositeDisposable(); command .CanExecuteChangedAsObservable() .ToReadOnlyReactivePropertySlim(mode: ReactivePropertyMode.RaiseLatestValueOnSubscribe) .Subscribe(_ => checkBox.Enabled = command.CanExecute()) .AddTo(disposable); Observable.FromEvent <EventHandler, EventArgs>( h => (s, e) => h(e), h => checkBox.Click += h, h => checkBox.Click -= h ) .Subscribe(_ => command.Execute()) .AddTo(disposable); return(disposable); }
internal static IDisposable BindToButton <T>(this ReactiveCommand <T> command, T value, ToolStripMenuItem button) { CompositeDisposable disposable = new CompositeDisposable(); command .CanExecuteChangedAsObservable() .ToReadOnlyReactivePropertySlim(mode: ReactivePropertyMode.RaiseLatestValueOnSubscribe) .Subscribe(_ => button.Enabled = command.CanExecute()) .AddTo(disposable); Observable.FromEvent <EventHandler, EventArgs>( h => (s, e) => h(e), h => button.Click += h, h => button.Click -= h ) .Subscribe(_ => command.Execute(value)) .AddTo(disposable); return(disposable); }
OleMenuCommand BindNavigatorCommand <T>(IServiceProvider paneServiceProvider, int commandId, ReactiveCommand <T> command) { Guard.ArgumentNotNull(paneServiceProvider, nameof(paneServiceProvider)); Guard.ArgumentNotNull(command, nameof(command)); Func <bool> canExecute = () => Content == navigator && command.CanExecute(null); var result = paneServiceProvider.AddCommandHandler( Guids.guidGitHubToolbarCmdSet, commandId, canExecute, () => command.Execute(null), true); Observable.CombineLatest( this.WhenAnyValue(x => x.Content), command.CanExecuteObservable, (c, e) => c == navigator && e) .Subscribe(x => result.Enabled = x); return(result); }
public TaxonManagementVM( IConnectivityService Connectivity, ITaxonService Taxa, IDiversityServiceClient Service, INotificationService Notification ) { this.Connectivity = Connectivity; this.Service = Service; this.Taxa = Taxa; this.Notification = Notification; _IsOnlineAvailable = this.ObservableToProperty(Connectivity.WifiAvailable(), x => x.IsOnlineAvailable); var localLists = this.FirstActivation() .SelectMany(_ => Taxa.getTaxonSelections() .ToObservable(ThreadPoolScheduler.Instance) .Select(list => new TaxonListVM(list))) .Publish(); LocalLists = localLists .ObserveOnDispatcher() .CreateCollection(); var onlineLists = localLists .IgnoreElements() //only download lists once the local ones are loaded .Concat(Observable.Return(null as TaxonListVM)) .CombineLatest(this.OnActivation(), (_, _2) => _2) .CheckConnectivity(Connectivity, Notification) .SelectMany(_ => { return Service.GetTaxonLists() .DisplayProgress(Notification, DiversityResources.TaxonManagement_State_DownloadingLists) .TakeUntil(this.OnDeactivation()); }) .ObserveOnDispatcher() .SelectMany(lists => lists.Where(list => !LocalLists.Any(loc => loc.Model == list)) // Filter lists already present locally .Select(list => new TaxonListVM(list)) ) .Publish(); PersonalLists = onlineLists.Where(vm => !vm.Model.IsPublicList) .CreateCollection(); PublicLists = onlineLists.Where(vm => vm.Model.IsPublicList) .CreateCollection(); onlineLists.Connect(); localLists.Connect(); Select = new ReactiveCommand<TaxonListVM>(vm => !vm.IsSelected && !vm.IsDownloading); Select.Subscribe(taxonlist => { foreach (var list in LocalLists) { if (list.Model.TaxonomicGroup == taxonlist.Model.TaxonomicGroup) list.Model.IsSelected = false; } Taxa.selectTaxonList(taxonlist.Model); }); Download = new ReactiveCommand<TaxonListVM>(vm => !vm.IsDownloading); Download .CheckConnectivity(Connectivity, Notification) .Subscribe(taxonlist => { if (Taxa.getTaxonTableFreeCount() > 0) { CurrentPivot = Pivot.Local; taxonlist.IsDownloading = true; makeListLocal(taxonlist); DownloadTaxonList(taxonlist) .DisplayProgress(Notification, DiversityResources.TaxonManagement_State_DownloadingList) .ObserveOnDispatcher() .ShowServiceErrorNotifications(Notification) .Subscribe(_ => { //Download Succeeded taxonlist.IsDownloading = false; if (Select.CanExecute(taxonlist)) Select.Execute(taxonlist); }, _ => //Download Failed { taxonlist.IsDownloading = false; removeLocalList(taxonlist); }, () => { }); } }); Delete = new ReactiveCommand<TaxonListVM>(vm => !vm.IsDownloading); Delete .Subscribe(taxonlist => { removeLocalList(taxonlist); }); Refresh = new ReactiveCommand<TaxonListVM>(vm => !vm.IsDownloading); Refresh .Subscribe(taxonlist => { if (Delete.CanExecute(taxonlist)) //Deletes synchronously Delete.Execute(taxonlist); if (Download.CanExecute(taxonlist)) Download.Execute(taxonlist); }); //Download all only on Personal pivot var canDownloadAll = this.WhenAny(x => x.CurrentPivot, x => x.GetValue()) .Select(p => p == Pivot.Personal) .CombineLatest(Connectivity.WifiAvailable(), (p, wi) => p && wi); DownloadAll = new ReactiveCommand(canDownloadAll, initialCondition: false); DownloadAll .SelectMany(_ => PersonalLists.ToArray()) .Where(vm => Download.CanExecute(vm)) .Subscribe(Download.Execute); }
public MainWindowViewModel() { ImageHistory = new ReactiveList <string>(); VisiblityCommand = new ReactiveCommand(); DropCommand = new ReactiveCommand(); SettingsCommand = new ReactiveCommand(); UploadCommand = new ReactiveCommand(); ScreenCommand = new ReactiveCommand(); SelectionCommand = new ReactiveCommand(this.WhenAnyValue(x => x.IsCaptureWindowOpen).Select(x => !x)); SelectionCommand.Subscribe(_ => IsCaptureWindowOpen = true); DropCommand.Subscribe(async ev => { var e = ev as DragEventArgs; if (e == null) { return; } if (!e.Data.GetDataPresent(DataFormats.FileDrop)) { return; } var data = e.Data.GetData(DataFormats.FileDrop) as IEnumerable <string>; if (data == null) { return; } foreach (var file in data) { await App.Uploader.Upload(file); } }); OpenCommand = new ReactiveCommand(); OpenCommand.Subscribe(async files => { foreach (var file in (IEnumerable <string>)files) { await App.Uploader.Upload(file); } }); MessageBus.Current.Listen <object>("CaptureWindow").Subscribe(_ => IsCaptureWindowOpen = false); Observable.FromEventPattern <KeyPressedEventArgs>(handler => App.HotKeyManager.KeyPressed += handler, handler => App.HotKeyManager.KeyPressed -= handler).Select(x => x.EventArgs).Subscribe(e => { var hk = e.HotKey; if (hk.Equals(App.Settings.ScreenKey)) { ScreenCommand.Execute(null); } else if (hk.Equals(App.Settings.SelectionKey)) { if (SelectionCommand.CanExecute(null)) { SelectionCommand.Execute(null); } } }); Observable.FromEventPattern <UploaderEventArgs>(handler => App.Uploader.ImageUploadSuccess += handler, handler => App.Uploader.ImageUploadSuccess -= handler).Select(x => x.EventArgs).Subscribe(e => { if (App.Settings.CopyLinks) { Clipboard.SetDataObject(e.ImageUrl); } ImageHistory.Add(e.ImageUrl); if (!App.Settings.Notifications) { return; } var msg = string.Format("Image Uploaded: {0}", e.ImageUrl); MessageBus.Current.SendMessage(new NotificationMessage(Title, msg, BalloonIcon.Info)); }); Observable.FromEventPattern <UploaderEventArgs>(handler => App.Uploader.ImageUploadFailed += handler, handler => App.Uploader.ImageUploadFailed -= handler).Select(x => x.EventArgs).Subscribe(e => { if (!App.Settings.Notifications) { return; } var msg = string.Format("Image Failed: {0}", e.Exception.Message); MessageBus.Current.SendMessage(new NotificationMessage(Title, msg, BalloonIcon.Error)); }); App.Settings.ObservableForProperty(x => x.AlwaysOnTop).Subscribe(_ => this.RaisePropertyChanged("IsTopmost")); }
public void RaisesCanExecuteChangedWithNextCanExecuteImplementation( Subject<Func<object, bool>> source, object parameter) { var sut = new ReactiveCommand<Unit>( source, _ => Task.FromResult(Unit.Default)); sut.MonitorEvents(); source.OnNext(p => p == parameter); sut.ShouldRaise(nameof(sut.CanExecuteChanged)) .WithSender(sut).WithArgs<EventArgs>(a => a == EventArgs.Empty); sut.CanExecute(parameter).Should().BeTrue(); sut.CanExecute(new object()).Should().BeFalse(); }
/// <summary> /// Command binding method. /// </summary> /// <typeparam name="T">Command type.</typeparam> /// <param name="self">IObservable</param> /// <param name="command">Command</param> /// <returns>Command binding token</returns> public static IDisposable SetCommand <T>(this IObservable <T> self, ReactiveCommand <T> command) => self .Where(_ => command.CanExecute()) .Subscribe(x => command.Execute(x));
public SearchPageViewModel( IScheduler scheduler, ApplicationLayoutManager applicationLayoutManager, NiconicoSession niconicoSession, SearchProvider searchProvider, PageManager pageManager, SearchHistoryRepository searchHistoryRepository ) { _scheduler = scheduler; ApplicationLayoutManager = applicationLayoutManager; NiconicoSession = niconicoSession; SearchProvider = searchProvider; PageManager = pageManager; _searchHistoryRepository = searchHistoryRepository; HashSet <string> HistoryKeyword = new HashSet <string>(); foreach (var item in _searchHistoryRepository.ReadAllItems().OrderByDescending(x => x.LastUpdated)) { if (HistoryKeyword.Contains(item.Keyword)) { continue; } SearchHistoryItems.Add(new SearchHistoryListItemViewModel(item, this)); HistoryKeyword.Add(item.Keyword); } SearchText = new ReactiveProperty <string>(_LastKeyword) .AddTo(_CompositeDisposable); TargetListItems = new List <SearchTarget>() { SearchTarget.Keyword, SearchTarget.Tag, SearchTarget.Niconama, }; SelectedTarget = new ReactiveProperty <SearchTarget>(_LastSelectedTarget) .AddTo(_CompositeDisposable); DoSearchCommand = new ReactiveCommand() .AddTo(_CompositeDisposable); #if DEBUG SearchText.Subscribe(x => { Debug.WriteLine($"検索:{x}"); }); #endif #if DEBUG DoSearchCommand.CanExecuteChangedAsObservable() .Subscribe(x => { Debug.WriteLine(DoSearchCommand.CanExecute()); }); #endif IsNavigationFailed = new ReactiveProperty <bool>(); NavigationFailedReason = new ReactiveProperty <string>(); }
public void MultipleSubscribersShouldntDecrementRefcountBelowZero() { (new TestScheduler()).With(sched => { var fixture = new ReactiveCommand(); var results = new List<int>(); bool[] subscribers = new[] {false, false, false, false, false}; var output = fixture.RegisterAsync(_ => Observable.Return(5).Delay(TimeSpan.FromMilliseconds(5000), sched)); output.Subscribe(x => results.Add(x)); Enumerable.Range(0, 5).Run(x => output.Subscribe(_ => subscribers[x] = true)); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(2000); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(6000); Assert.True(fixture.CanExecute(null)); Assert.True(results.Count == 1); Assert.True(results[0] == 5); Assert.True(subscribers.All(x => x)); }); }
public SearchViewModel() { SearchResults = new ObservableCollection <SearchResult>(); // ReactiveCommand has built-in support for background operations and // guarantees that this block will only run exactly once at a time, and // that the CanExecute will auto-disable and that property IsExecuting will // be set according whilst it is running. Search = ReactiveCommand.CreateAsyncTask( // Here we're describing here, in a *declarative way*, the conditions in // which the Search command is enabled. Now our Command IsEnabled is // perfectly efficient, because we're only updating the UI in the scenario // when it should change. Observable .CombineLatest( this.WhenAnyValue(vm => vm.SearchQuery).Select(searchQuery => !string.IsNullOrEmpty(searchQuery)).DistinctUntilChanged(), this.WhenAnyObservable(x => x.Search.IsExecuting).DistinctUntilChanged(), (hasSearchQuery, isExecuting) => hasSearchQuery && !isExecuting) .Do(cps => System.Diagnostics.Debug.WriteLine($"Can Perform Search: {cps}")) .DistinctUntilChanged(), async _ => { var random = new Random(Guid.NewGuid().GetHashCode()); await Task.Delay(random.Next(250, 2500)); //This is just here so simulate a network type exception if (DateTime.Now.Second % 3 == 0) { throw new TimeoutException("Unable to connec to web service"); } var searchService = Locator.CurrentMutable.GetService <IDuckDuckGoApi>(); var searchResult = await searchService.Search(SearchQuery); return(searchResult .RelatedTopics .Select(rt => new SearchResult { DisplayText = rt.Text, ImageUrl = rt?.Icon?.Url ?? string.Empty }) .ToList()); }); //// ReactiveCommands are themselves IObservables, whose value are the results //// from the async method, guaranteed to arrive on the given scheduler. //// We're going to take the list of search results that the background //// operation loaded, and them into our SearchResults. Search .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(searchResult => { SearchResults.Clear(); foreach (var item in searchResult) { SearchResults.Add(item); } }); // ThrownExceptions is any exception thrown from the CreateFromObservable piped // to this Observable. Subscribing to this allows you to handle errors on // the UI thread. Search .ThrownExceptions .Subscribe(async ex => { var result = await UserError.Throw("Potential Network Connectivity Error", ex); if (result == RecoveryOptionResult.RetryOperation && Search.CanExecute(null)) { Search.Execute(null); } }); //Behaviors this.WhenAnyValue(x => x.SearchQuery) .Throttle(TimeSpan.FromSeconds(.75), TaskPoolScheduler.Default) .Do(x => System.Diagnostics.Debug.WriteLine($"Throttle fired for {x}")) .ObserveOn(RxApp.MainThreadScheduler) .InvokeCommand(Search); }
public void CommandInitialConditionShouldBeAdjustable() { var sub = new Subject<bool>(); var cmd = new ReactiveCommand(sub); Assert.Equal(true, cmd.CanExecute(null)); var cmd2 = new ReactiveCommand(sub, false); Assert.Equal(false, cmd2.CanExecute(null)); }
public MainWindowViewModel() { ImageHistory = new ReactiveList<string>(); VisiblityCommand = new ReactiveCommand(); DropCommand = new ReactiveCommand(); SettingsCommand = new ReactiveCommand(); UploadCommand = new ReactiveCommand(); ScreenCommand = new ReactiveCommand(); SelectionCommand = new ReactiveCommand(this.WhenAnyValue(x => x.IsCaptureWindowOpen).Select(x => !x)); SelectionCommand.Subscribe(_ => IsCaptureWindowOpen = true); DropCommand.Subscribe(async ev => { var e = ev as DragEventArgs; if (e == null) return; if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return; var data = e.Data.GetData(DataFormats.FileDrop) as IEnumerable<string>; if (data == null) return; foreach (var file in data) await App.Uploader.Upload(file); }); OpenCommand = new ReactiveCommand(); OpenCommand.Subscribe(async files => { foreach (var file in (IEnumerable<string>)files) await App.Uploader.Upload(file); }); MessageBus.Current.Listen<object>("CaptureWindow").Subscribe(_ => IsCaptureWindowOpen = false); Observable.FromEventPattern<KeyPressedEventArgs>(handler => App.HotKeyManager.KeyPressed += handler, handler => App.HotKeyManager.KeyPressed -= handler).Select(x => x.EventArgs).Subscribe(e => { var hk = e.HotKey; if (hk.Equals(App.Settings.ScreenKey)) ScreenCommand.Execute(null); else if (hk.Equals(App.Settings.SelectionKey)) { if (SelectionCommand.CanExecute(null)) SelectionCommand.Execute(null); } }); Observable.FromEventPattern<UploaderEventArgs>(handler => App.Uploader.ImageUploadSuccess += handler, handler => App.Uploader.ImageUploadSuccess -= handler).Select(x => x.EventArgs).Subscribe(e => { if (App.Settings.CopyLinks) Clipboard.SetDataObject(e.ImageUrl); ImageHistory.Add(e.ImageUrl); if (!App.Settings.Notifications) return; var msg = string.Format("Image Uploaded: {0}", e.ImageUrl); MessageBus.Current.SendMessage(new NotificationMessage(Title, msg, BalloonIcon.Info)); }); Observable.FromEventPattern<UploaderEventArgs>(handler => App.Uploader.ImageUploadFailed += handler, handler => App.Uploader.ImageUploadFailed -= handler).Select(x => x.EventArgs).Subscribe(e => { if (!App.Settings.Notifications) return; var msg = string.Format("Image Failed: {0}", e.Exception.Message); MessageBus.Current.SendMessage(new NotificationMessage(Title, msg, BalloonIcon.Error)); }); App.Settings.ObservableForProperty(x => x.AlwaysOnTop).Subscribe(_ => this.RaisePropertyChanged("IsTopmost")); }
public void RegisterAsyncFunctionSmokeTest() { (new TestScheduler()).With(sched => { var fixture = new ReactiveCommand(); IReactiveDerivedList<int> results; results = fixture.RegisterAsync(_ => Observable.Return(5).Delay(TimeSpan.FromSeconds(5), sched)).CreateCollection(); var inflightResults = fixture.IsExecuting.CreateCollection(); sched.AdvanceToMs(10); Assert.True(fixture.CanExecute(null)); fixture.Execute(null); sched.AdvanceToMs(1005); Assert.False(fixture.CanExecute(null)); sched.AdvanceToMs(5100); Assert.True(fixture.CanExecute(null)); new[] {false, true, false}.AssertAreEqual(inflightResults); new[] {5}.AssertAreEqual(results); }); }