public void LetsSeeWhetherWeCanRandomlyHitARaceCondition()
        {
            var ids = ObservableChangeSet.Create <long, long>(sourceCache => { return(Observable.Range(1, 1000000, Scheduler.Default).Subscribe(x => sourceCache.AddOrUpdate(x))); }, x => x);

            var itemsCache = new SourceCache <Thing, long>(x => x.Id);

            itemsCache.AddOrUpdate(
                new[]
            {
                new Thing {
                    Id = 300, Name = "Quick"
                },
                new Thing {
                    Id = 600, Name = "Brown"
                },
                new Thing {
                    Id = 900, Name = "Fox"
                },
                new Thing {
                    Id = 1200, Name = "Hello"
                },
            });

            ids.InnerJoin(itemsCache.Connect(), x => x.Id, (_, thing) => thing).Subscribe((z) => { }, ex => { }, () => { });
        }
        public void LoadsAndDisposeFromObservableCache()
        {
            bool isDisposed = false;

            var observable = ObservableChangeSet.Create <Person, string>(cache => { return(() => { isDisposed = true; }); }, p => p.Name);

            observable.AsObservableCache().Dispose();
            isDisposed.Should().BeTrue();
        }
Exemple #3
0
 public static IObservable <IChangeSet <int> > FromTask(Func <Task <IEnumerable <int> > > loader)
 {
     return(ObservableChangeSet.Create <int>(async list =>
     {
         var items = await loader();
         list.AddRange(items);
         return () => { };
     }));
 }
Exemple #4
0
 /// <summary>
 /// Create an observable change set from a task
 /// </summary>
 /// <returns></returns>
 public static IObservable <IChangeSet <int> > FromTask()
 {
     return(ObservableChangeSet.Create <int>(async list =>
     {
         var items = await LoadFromTask();
         list.AddRange(items);
         return () => { };
     }));
 }
        public static ViewModel.InteractiveCollectionViewModel <T, object> Build <T>(Func <T, object> getkey, IObservable <IEnumerable <T> > elems, IObservable <IFilter> filter, IObservable <T> DeletedSubject, IObservable <object> ClearedSubject, System.Reactive.Concurrency.DispatcherScheduler UI, IObservable <Func <T, object> > getkeys = null, bool isReadOnly = false)
        {
            var dx = Observable.Create <string>(_ => () => { });

            ViewModel.InteractiveCollectionViewModel <T, object> interactivecollection = null;
            ISubject <Exception> exs = new Subject <Exception>();
            var sx = ObservableChangeSet.Create(cache =>
            {
                var dels = DeletedSubject /*.WithLatestFrom(RemoveSubject.StartWith(Remove).DistinctUntilChanged(), (d, r) => new { d, r })*/.Subscribe(_ =>
                {
                    try
                    {
                        cache.Remove(_);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("error removing " + _.ToString() + " from cache");
                        Console.WriteLine(ex.Message);
                        exs.OnNext(ex);
                        //ArgumentNullException
                    }
                });

                ClearedSubject.Subscribe(_ => cache.Clear());

                elems.Subscribe(_ =>
                {
                    foreach (var g in _)
                    {
                        try
                        {
                            cache.AddOrUpdate(g);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("error adding " + g.ToString() + " from cache");
                            Console.WriteLine(ex);
                            exs.OnNext(ex);
                        }
                    }
                });
                return(new System.Reactive.Disposables.CompositeDisposable(dels));
            }, getkey)
                     .Filter(filter.Select(_ => { Func <T, bool> f = aa => _.Filter(aa); return(f); }).StartWith(ft));

            getkeys?.Subscribe(_ =>
            {
                sx.ChangeKey(_);
            });

            interactivecollection = new ViewModel.InteractiveCollectionViewModel <T, object>(sx, UI, DeletedSubject, _ => (IConvertible)getkey(_));

            exs.Subscribe(ex =>
                          (interactivecollection.Errors as System.Reactive.Subjects.ISubject <Exception>).OnNext(ex));

            return(interactivecollection);
        }
Exemple #6
0
 /// <summary>
 ///     Converts this directory's incoming change observables into a
 ///     single <see cref="IChangeSet{DirectoryEntry}" /> observable.
 ///     <para>
 ///         This observer is then used to feed <see cref="Files" />,
 ///         which in turn feeds the UI view of the directory contents.
 ///     </para>
 /// </summary>
 /// <returns>
 ///     An observable that reports changes in a directory in the form
 ///     of <see cref="IChangeSet{DirectoryEntry}" /> objects.
 /// </returns>
 private IObservable <IChangeSet <DirectoryEntry> > DirectoryChanges()
 {
     return(ObservableChangeSet.Create <DirectoryEntry>(list =>
     {
         var adder = ThisDirectoryFileAdd.Subscribe(x =>
                                                    list.Insert((int)x.Index, new DirectoryEntry(x.DirectoryId, x.Description)));
         var clearer = ThisDirectoryPrepare.Subscribe(_ => list.Clear());
         return new CompositeDisposable(adder, clearer);
     }));
 }
Exemple #7
0
 /// <summary>
 /// Reload data and maintain list using edit diff which calculates a diff set from the previous load which can significantly reduce noise by poreventing
 /// unnecessary updates
 /// </summary>
 public static IObservable <IChangeSet <int> > ReloadableWithEditDiff(IObservable <Unit> loadObservable, Func <Task <IEnumerable <int> > > loader)
 {
     return(ObservableChangeSet.Create <int>(list =>
     {
         return loadObservable
         .StartWith(Unit.Default)     //ensure inital load
         .SelectMany(_ => loader())
         .Subscribe(items => list.EditDiff(items, EqualityComparer <int> .Default));
     }));
 }
Exemple #8
0
        public void Create()
        {
            Task <T> CreateTask <T>(T value) => Task.FromResult(value);

            SubscribeAndAssert(ObservableChangeSet.Create <int>(async list =>
            {
                var value = await CreateTask <int>(10);
                list.Add(value);
                return(() => { });
            }));
        }
Exemple #9
0
        public LocalLibraryService(
            ITracksRepository tracksRepository,
            ITrackFactory trackFactory,
            IPlaylistsRepository playlistsRepository,
            IPlaylistFactory playlistFactory)
        {
            this._tracksRepository    = tracksRepository ?? throw new ArgumentNullException(nameof(tracksRepository));
            this._trackFactory        = trackFactory ?? throw new ArgumentNullException(nameof(trackFactory));
            this._playlistsRepository = playlistsRepository ?? throw new ArgumentNullException(nameof(playlistsRepository));
            this._playlistFactory     = playlistFactory ?? throw new ArgumentNullException(nameof(playlistFactory));

            this._playlistBaseChangesSubscription = new SerialDisposable().DisposeWith(this._disposables);
            this._tracksChangesSubscription       = new SerialDisposable().DisposeWith(this._disposables);

            this.TracksChanges = ObservableChangeSet.Create <Track, uint>(
                async cache =>
            {
                var items = await this._tracksRepository.GetAllAsync();
                cache.AddOrUpdate(items);

                //return new CompositeDisposable(
                //    //this._tracksRepository.TracksAddeded.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems))),
                //    //this._tracksRepository.TracksRemoved.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.Remove(addedItems))),
                //    //this._tracksRepository.TracksUpdated.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems)))
                //    );
            },
                x => x.Id)
                                 // TODO: add synchronization to handle multiple subscriptions?
                                 .RefCount()
                                 //.Multicast(new ReplaySubject<IChangeSet<Track, uint>>())
                                 //.AutoConnect(1, subscription => this._tracksChangesSubscription.Disposable = subscription)
            ;

            this.PlaylistsChanges = ObservableChangeSet.Create <PlaylistBase, uint>(
                async cache =>
            {
                var items = await this._playlistsRepository.GetAllPlaylistsAsync();
                cache.AddOrUpdate(items);

                //return new CompositeDisposable(
                ////    this._playlistsRepository.Addeded.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems))),
                ////    this._playlistsRepository.Removed.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.Remove(addedItems))),
                ////    this._playlistsRepository.Updated.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems)))
                //);
            },
                x => x.Id)
                                    .RefCount()
                                    //.Multicast(new ReplaySubject<IChangeSet<PlaylistBase, uint>>())
                                    //.AutoConnect(1, subscription => this._playlistBaseChangesSubscription.Disposable = subscription)
            ;
        }
Exemple #10
0
        public void LoadsAndDisposeUsingDisposable()
        {
            bool isDisposed = false;

            SubscribeAndAssert(ObservableChangeSet.Create <Person, string>(cache =>
            {
                Person[] people = Enumerable.Range(1, 100).Select(i => new Person($"Name.{i}", i)).ToArray();
                cache.AddOrUpdate(people);
                return(Disposable.Create(() => { isDisposed = true; }));
            }, p => p.Name),
                               checkContentAction: result => result.Count.Should().Be(100));

            isDisposed.Should().BeTrue();
        }
Exemple #11
0
        /// <summary>
        /// Create an observable change set from 2 observables i) the initial load 2) a subscriber
        /// </summary>
        public static IObservable <IChangeSet <int> > FromObservable(IObservable <IEnumerable <int> > initialLoad, IObservable <int> subscriptions)
        {
            return(ObservableChangeSet.Create <int>(list =>
            {
                //in an enterprise app, would have to account for the gap between load and subscribe
                var initialSubscriber = initialLoad
                                        .Take(1)
                                        .Subscribe(list.AddRange);

                var subscriber = subscriptions
                                 .Subscribe(list.Add);

                return new CompositeDisposable(initialSubscriber, subscriber);
            }));
        }
Exemple #12
0
        public void LoadsAndDisposeUsingActionAsync()
        {
            Task <Person[]> CreateTask() => Task.FromResult(Enumerable.Range(1, 100).Select(i => new Person($"Name.{i}", i)).ToArray());

            bool isDisposed = false;

            SubscribeAndAssert(ObservableChangeSet.Create <Person, string>(async cache =>
            {
                var people = await CreateTask();
                cache.AddOrUpdate(people);
                return(() => { isDisposed = true; });
            }, p => p.Name),
                               checkContentAction: result => result.Count.Should().Be(100));

            isDisposed.Should().BeTrue();
        }
        public TracksService(TracksRepository tracksRepository)
        {
            this._tracksRepository = tracksRepository ?? throw new ArgumentNullException(nameof(tracksRepository));

            this.TracksChangeSets = ObservableChangeSet.Create <Track, uint>(
                async sourceCache =>
            {
                var load        = this._tracksRepository.GetAllAsync();
                var delayedLoad = Task.WhenAll(load, Task.Delay(TimeSpan.FromSeconds(5)));

                await delayedLoad;

                var tracks = await load;
                sourceCache.AddOrUpdate(tracks);
            },
                b => b.Id)
                                    .RefCount();
        }
Exemple #14
0
        public TrackViewModelsProxy()
        {
            this.TracksChangeSets = ObservableChangeSet.Create <Track, uint>(
                async sourceCache =>
            {
                var tracks = await this.GetAllTracksAsync(
                    TimeSpan.FromSeconds(3)
                    );
                sourceCache.AddOrUpdate(tracks);
            },
                x => x.Id)
                                    .RefCount();

            this.TrackViewModelsChangeSets = this.TracksChangeSets
                                             .Transform(b => new TrackViewModel(b))
                                             .DisposeMany()
                                             .RefCount();
        }
        public LocalLibraryService(
            ITracksRepository tracksRepository,
            ITrackFactory trackFactory,
            IPlaylistsRepository playlistsRepository,
            IPlaylistFactory playlistFactory)
        {
            this._tracksRepository    = tracksRepository ?? throw new ArgumentNullException(nameof(tracksRepository));
            this._trackFactory        = trackFactory ?? throw new ArgumentNullException(nameof(trackFactory));
            this._playlistsRepository = playlistsRepository ?? throw new ArgumentNullException(nameof(playlistsRepository));
            this._playlistFactory     = playlistFactory ?? throw new ArgumentNullException(nameof(playlistFactory));

            this.TracksChanges = ObservableChangeSet.Create <Track, uint>(
                async cache =>
            {
                var items = await this.GetTracksAsync(
                    //TimeSpan.FromSeconds(3)
                    );
                GC.Collect();
                cache.AddOrUpdate(items);
                GC.Collect();

                //return new CompositeDisposable(
                //    this._tracksRepository.Addeded.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems))),
                //    this._tracksRepository.Removed.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.Remove(addedItems))),
                //    this._tracksRepository.Updated.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems))));
            },
                x => x.Id)
                                 // TODO: add synchronization to handle multiple subscriptions?
                                 .RefCount();

            this.PlaylistsChanges = ObservableChangeSet.Create <PlaylistBase, uint>(
                async cache =>
            {
                var items = await this._playlistsRepository.GetAllPlaylistsAsync();
                cache.AddOrUpdate(items);

                //return new CompositeDisposable(
                //    this._playlistsRepository.Addeded.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems))),
                //    this._playlistsRepository.Removed.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.Remove(addedItems))),
                //    this._playlistsRepository.Updated.Subscribe(addedItems => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(addedItems))));
            },
                x => x.Id)
                                    .RefCount();
        }
        public ConnectionService()
        {
            mServerDiscovery = new ServerDiscovery();

            AvailableServers = ObservableChangeSet.Create <Server, int>(list =>
            {
                return(Observable.Interval(TimeSpan.FromSeconds(1))
                       .StartWith(0)
                       .Select(_ => mServerDiscovery.Scan())
                       .Subscribe(servers => list.EditDiff(servers, (s1, s2) => s1.ProcessId == s2.ProcessId)));
            }, server => server.ProcessId);

            mConnectionSubject = new BehaviorSubject <IConnectionModel>(null);

            mProfilersLocation =
                Path.Combine(
                    Path.GetDirectoryName(
                        new Uri(Assembly.GetEntryAssembly().CodeBase).LocalPath),
                    "profiler");
        }
Exemple #17
0
        public void HandlesAsyncError()
        {
            Exception error = null;

            Task <IEnumerable <Person> > Loader()
            {
                throw new Exception("Broken");
            }

            var observable = ObservableChangeSet.Create <Person, string>(async cache =>
            {
                var people = await Loader();
                cache.AddOrUpdate(people);
                return(() => { });
            }, p => p.Name);

            using (var dervived = observable.AsObservableCache())
                using (dervived.Connect().Subscribe(_ => { }, ex => error = ex))
                {
                    error.Should().NotBeNull();
                }
        }
Exemple #18
0
        public virtual ViewModel.InteractiveCollectionViewModel <object, IConvertible> React(/*string key,*/ string childrenpath, IEnumerable enumerable, IObservable <bool> ischecked, System.Reactive.Concurrency.DispatcherScheduler UI, System.Windows.Threading.Dispatcher dispatcher)
        {
            var sx = ObservableChangeSet.Create <object, IConvertible>(cache =>
            {
                foreach (var val in enumerable)
                {
                    cache.AddOrUpdate(val);
                }
                return(System.Reactive.Disposables.Disposable.Empty);
            }, GetKey);

            var kx = new ViewModel.InteractiveCollectionViewModel <object, IConvertible>(sx, ChildrenPath, ischecked, ExpandSubject.StartWith(Expand).DistinctUntilChanged(), UI, dispatcher);

            kx.GetChecked();
            kx.GetSelectedItem(ischecked).Subscribe(_ =>
            {
                this.Dispatcher.InvokeAsync(() => SelectedItem = _, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            });
            kx.GetCheckedChildItems(ischecked, childrenpath).Subscribe(_ =>
            {
                this.Dispatcher.InvokeAsync(() => CheckedItems = _, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            });

            AllCheckedItems = kx.@checked;

            //kx.GetSelected().WithLatestFrom(ischecked,(a,b)=>new { a, b }).Subscribe(_=>
            //{
            //    if (@checked.Contains(_) || _.b==false)
            //    {
            //        this.Dispatcher.InvokeAsync(() => SelectedItem = _.a, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //        this.Dispatcher.InvokeAsync(() => CheckedItems = ReflectionHelper.RecursivePropValues(_.a, childrenpath).Cast<object>().Where(a => @checked.Contains(a)).ToList(), System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //    }
            //});

            //kx.ChildSubject.Where(_=>_.Value.Interaction==Interaction.Select &&((int) _.Value.Value)>0).WithLatestFrom(ischecked, (a, b) => new { a, b }).Subscribe(_ =>
            //{
            //    if (@checked.Contains(_.a.Key) || _.b == false)
            //    {
            //        this.Dispatcher.InvokeAsync(() => SelectedItem = _.a.Key, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //        this.Dispatcher.InvokeAsync(() => CheckedItems = ReflectionHelper.RecursivePropValues(_.a.Key, childrenpath).Cast<object>().Where(a => @checked.Contains(a)).ToList(), System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //    }
            //});

            //kx.ChildSubject.Where(_ => _.Value.Interaction == Interaction.Check).Subscribe(_ =>
            //{
            //    if (!((bool)_.Value.Value))
            //        if (@checked.Contains(_.Key))
            //        {
            //            @checked.Remove(_.Key);
            //            this.Dispatcher.InvokeAsync(() => SelectedItem = null, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //            this.Dispatcher.InvokeAsync(() => CheckedItems = null, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //        }

            //   else if (((bool)_.Value.Value))
            //            if (@unchecked.Contains(_.Key))
            //            {
            //                @unchecked.Remove(_.Key);
            //                this.Dispatcher.InvokeAsync(() => SelectedItem = _.Key, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //                this.Dispatcher.InvokeAsync(() => CheckedItems = ReflectionHelper.RecursivePropValues(_.Key, childrenpath).Cast<object>().Where(a => @checked.Contains(a)).ToList(), System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //            }

            //});

            //kx.DoubleClicked.Subscribe(_ =>
            //{
            //    this.Dispatcher.InvokeAsync(() => DoubleClickedItem = _, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //});

            //SelectedItemSubject.Subscribe(_ =>

            //kx.Deleted.Subscribe(_ =>
            //{
            //    this.Dispatcher.InvokeAsync(() => Deleted = _, System.Windows.Threading.DispatcherPriority.Background, default(System.Threading.CancellationToken));
            //});
            return(kx);
        }
Exemple #19
0
        public LocalSuppliersService(
            IBillingUnitOfWorkFactory _billingUnitOfWorkFactory
            )
        {
            this._billingUnitOfWorkFactory = _billingUnitOfWorkFactory ?? throw new ArgumentNullException(nameof(_billingUnitOfWorkFactory));

            this._added_Subject   = new Subject <SupplierDto>().DisposeWith(this._disposables);
            this._updated_Subject = new Subject <IReadOnlyCollection <SupplierDto> >().DisposeWith(this._disposables);
            this._removed_Subject = new Subject <IReadOnlyCollection <long> >().DisposeWith(this._disposables);

            //this._isBusy_BehaveiorSubject = new BehaviorSubject<bool>(false).DisposeWith(this._disposables);
            //this.IsBusyChanged = this._isBusy_BehaveiorSubject.DistinctUntilChanged();

            this._suppliersChangesSubscription = new SerialDisposable().DisposeWith(this._disposables);
            var supplierDtoChangeSets = ObservableChangeSet.Create <SupplierDto, long>(
                async cache =>
            {
                //await Task.Delay(3_000);
                var supplierDTOs = await this.GetAllAsync().ConfigureAwait(false);

                cache.AddOrUpdate(supplierDTOs);

                var crudSubscriptions = new CompositeDisposable();

                this.Added
                .Subscribe(supplierDto => cache.Edit(cacheUpdater => cacheUpdater.AddOrUpdate(supplierDto)))
                .DisposeWith(crudSubscriptions);

                this.Updated
                .Subscribe(e =>
                {
                    cache.Edit(cacheUpdater =>
                    {
                        var updates = e
                                      .Select(
                            updatedSupplierDto =>
                        {
                            var oldVersion = cacheUpdater.Lookup(updatedSupplierDto.Id);

                            return(new Change <SupplierDto, long>(
                                       ChangeReason.Update,
                                       updatedSupplierDto.Id,
                                       updatedSupplierDto,
                                       oldVersion));
                        })
                                      .ToArray();

                        var changes = new ChangeSet <SupplierDto, long>(updates);

                        cacheUpdater.Clone(changes);
                    });
                })
                .DisposeWith(crudSubscriptions);

                this.Removed
                .Subscribe(e => cache.Edit(cacheUpdater => cacheUpdater.Remove(e)))
                .DisposeWith(crudSubscriptions);

                return(crudSubscriptions);
            },
                x => x.Id)
                                        //this.SuppliersChanges = supplierDtoChangeSets
                                        //    //.RefCount()
                                        //    //.Transform(supplier => this._supplierViewModelFactoryMethod.Invoke(supplier), new ParallelisationOptions(ParallelType.Parallelise))
                                        //    //.DisposeMany()
                                        //    .Sort(SortExpressionComparer<SupplierDto>.Ascending(vm => vm.Name))
                                        //.Multicast(new ReplaySubject<IChangeSet<SupplierDto, int>>())
                                        //.AutoConnect(1, subscription => this._suppliersChangesSubscription.Disposable = subscription)
            ;

            this.Suppliers = supplierDtoChangeSets
                                                   //.Sort(SortExpressionComparer<SupplierDto>.Ascending(vm => vm.Name))
                             .RefCount()
                             .AsObservableCache(); // applyLocking: false);
        }