public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection, ISchedulerProvider schedulerProvider)
        {
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;
            
            ReadOnlyObservableCollection<SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta => new SearchOptionsProxy(meta, swatches,m => metadataCollection.Remove(m.SearchText)))
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the cache
                    return so.WhenAnyPropertyChanged()
                        .Subscribe(_ => metadataCollection.Add(new SearchMetadata(so.Text, so.Filter, so.Highlight)));
                })
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy=>proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out data)
                .Subscribe();

            Data = data;

            AddSearchCommand = new Command(() =>
            {
                    metadataCollection.Add(new SearchMetadata(SearchText,false,true));
                    SearchText = string.Empty;

            }, () => SearchText.IsLongerThanOrEqualTo(3) && !metadataCollection.Metadata.Lookup((CaseInsensitiveString)SearchText).HasValue);


            var commandRefresher = this.WhenValueChanged(vm => vm.SearchText)
                                    .Subscribe(_ => ((Command) AddSearchCommand).Refresh());
            
            //User feedback to guide them whilst typing
            SearchHint = this.WhenValueChanged(vm => vm.SearchText)
                            .Select(text =>
                            {
                                if (string.IsNullOrEmpty(text)) return "Type to highlight";
                                return text.Length < 3 ? "Enter at least 3 characters" : "Hit enter for more options";
                            }).ForBinding();
            
            _cleanUp = new CompositeDisposable(commandRefresher, userOptions, SearchHint);
        }
Esempio n. 2
0
        public void Remove(string searchText)
        {
            var item = Searches.Lookup(searchText);

            if (!item.HasValue)
            {
                return;
            }


            if (!item.Value.IsGlobal)
            {
                _localMetadataCollection.Remove(searchText);
            }
            else
            {
                _combinedSearchMetadataCollection.Global.Remove(searchText);
            }
        }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection, 
            ISchedulerProvider schedulerProvider,
            SearchHints searchHints)
        {
            SearchHints = searchHints;
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;
            
            ReadOnlyObservableCollection<SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta => new SearchOptionsProxy(meta, swatches,m => metadataCollection.Remove(m.SearchText)))
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the cache
                    return so.WhenAnyPropertyChanged()
                        .Subscribe(_ => metadataCollection.Add(new SearchMetadata(so.Text, so.Filter, so.Highlight,so.UseRegex,so.IgnoreCase)));
                })
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy=>proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out data)
                .Subscribe();

            Data = data;

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                metadataCollection.Add(new SearchMetadata(request.Text, false, true, request.UseRegEx, true));
            });

            
            _cleanUp = new CompositeDisposable(searchInvoker, userOptions, searchInvoker);
        }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection, 
            ISchedulerProvider schedulerProvider,
            SearchHints searchHints)
        {
            SearchHints = searchHints;
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;

            bool binding = false;

            var orderChanged = Observable.FromEventPattern<OrderChangedEventArgs>(
                                            h => PositionMonitor.OrderChanged += h,
                                            h => PositionMonitor.OrderChanged -= h)
                                    .Select(evt => evt.EventArgs)
                                    .Where(args=>args.PreviousOrder!=null && args.NewOrder.Length == args.PreviousOrder.Length)
                                    .Select(positionChangedArgs =>
                                    {
                                            //reprioritise filters and highlights
                                            return positionChangedArgs.NewOrder
                                            .OfType<SearchOptionsProxy>()
                                            .Select((item, index) => new {Meta=(SearchMetadata)item, index})
                                            //.Where(x => x.index != x.Meta.Position)
                                            .Select(x => new SearchMetadata(x.Meta, x.index))
                                            .ToArray();
                                    })
                                    .Subscribe(positionChangedArgs =>
                                    {
                                       
                                        positionChangedArgs.ForEach(metadataCollection.AddorUpdate);
                                    });

            ReadOnlyObservableCollection<SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta => new SearchOptionsProxy(meta, swatches, m => metadataCollection.Remove(m.SearchText)))
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the cache
                    return so.WhenAnyPropertyChanged()

                        .Subscribe(_ =>metadataCollection.AddorUpdate(new SearchMetadata(metadataCollection.Metadata.Count,
                                    so.Text, so.Filter, so.Highlight, so.UseRegex, so.IgnoreCase)));
                })
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))

                .ObserveOn(schedulerProvider.MainThread)
                .Bind(out data)
                .Subscribe();
            
            Data = data;

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                schedulerProvider.Background.Schedule(() =>
                {
                    metadataCollection.AddorUpdate(new SearchMetadata(metadataCollection.NextIndex(), request.Text, false, true, request.UseRegEx, true));
                });
            });
        
            
            _cleanUp = new CompositeDisposable(searchInvoker, 
                userOptions, 
                searchInvoker,
                orderChanged);
        }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
                                      ISearchMetadataFactory searchMetadataFactory,
                                      ISchedulerProvider schedulerProvider,
                                      IColourProvider colourProvider,
                                      IIconProvider iconsProvider,
                                      SearchHints searchHints)
        {
            SearchHints = searchHints;

            var proxyItems = metadataCollection.Metadata.Connect()
                             .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                             .Transform(meta =>
            {
                return(new SearchOptionsProxy(meta,
                                              colourProvider,
                                              new IconSelector(iconsProvider, schedulerProvider),
                                              m => metadataCollection.Remove(m.SearchText),
                                              iconsProvider.DefaultIconSelector,
                                              Id));
            })
                             .SubscribeMany(so =>
            {
                //when a value changes, write the original value back to the cache
                return(so.WhenAnyPropertyChanged()
                       .Select(_ => (SearchMetadata)so)
                       .Subscribe(metadataCollection.AddorUpdate));
            })
                             .AsObservableCache();

            var monitor = MonitorPositionalChanges()
                          .Subscribe(positionChangedArgs =>
            {
                positionChangedArgs.ForEach(metadataCollection.AddorUpdate);
            });


            //load data onto grid
            var collection = new ObservableCollectionExtended <SearchOptionsProxy>();

            var userOptions = proxyItems.Connect()
                              .Sort(SortExpressionComparer <SearchOptionsProxy> .Ascending(proxy => proxy.Position))
                              .ObserveOn(schedulerProvider.MainThread)
                              //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                              .Bind(collection, new ObservableCollectionAdaptor <SearchOptionsProxy, string>(0))
                              .DisposeMany()
                              .Subscribe();

            Data = new ReadOnlyObservableCollection <SearchOptionsProxy>(collection);

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                schedulerProvider.Background.Schedule(() =>
                {
                    var meta = searchMetadataFactory.Create(request.Text,
                                                            request.UseRegEx,
                                                            metadataCollection.NextIndex(),
                                                            false);
                    metadataCollection.AddorUpdate(meta);
                });
            });

            _cleanUp = new CompositeDisposable(searchInvoker,
                                               userOptions,
                                               searchInvoker,
                                               monitor,
                                               SearchHints);
        }
Esempio n. 6
0
        public SearchProxyCollection(ISearchMetadataCollection metadataCollection,
            Guid id,
            Action<SearchMetadata> changeScopeAction,
            ISchedulerProvider schedulerProvider,
            IColourProvider colourProvider,
            IIconProvider iconsProvider,
            ITextAssociationCollection textAssociationCollection,
            IThemeProvider themeProvider)
        {
            var proxyItems = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta =>
                {
                    return new SearchOptionsProxy(meta,
                        changeScopeAction,
                        colourProvider,
                        themeProvider,
                        new IconSelector(iconsProvider, schedulerProvider),
                        m => metadataCollection.Remove(m.SearchText),
                        iconsProvider.DefaultIconSelector,
                        id);
                })
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the metadata collection
                    var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                        .Select(_ => (SearchMetadata) so)
                        .Subscribe(metadataCollection.AddorUpdate);

                    //when an icon or colour has changed we need to record user choice so
                    //the same choice can be used again
                    var iconChanged = so.WhenValueChanged(proxy => proxy.IconKind, false).ToUnit();
                    var colourChanged = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                    var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.CaseSensitive, false).ToUnit();

                    var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                        .Throttle(TimeSpan.FromMilliseconds(250))
                        .Select(_ => new TextAssociation(so.Text, so.CaseSensitive, so.UseRegex, so.HighlightHue.Swatch,
                            so.IconKind.ToString(), so.HighlightHue.Name, DateTime.UtcNow))
                        .Subscribe(textAssociationCollection.MarkAsChanged);

                    return new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged);
                })
                .AsObservableCache();

            Count = proxyItems.CountChanged.StartWith(0).ForBinding();

            var monitor = MonitorPositionalChanges().Subscribe(metadataCollection.Add);

            //load data onto grid
            var collection = new ObservableCollectionExtended<SearchOptionsProxy>();

            var includedLoader = proxyItems
                .Connect(proxy => !proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(collection, new ObservableCollectionAdaptor<SearchOptionsProxy, string>(0))
                .DisposeMany()
                .Subscribe();

            ReadOnlyObservableCollection<SearchOptionsProxy> excluded;
            var excludedLoader = proxyItems
                .Connect(proxy => proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(out excluded)
                .DisposeMany()
                .Subscribe();

            Excluded = excluded;
            Included = new ReadOnlyObservableCollection<SearchOptionsProxy>(collection);

            _cleanUp = new CompositeDisposable(proxyItems, includedLoader, excludedLoader, monitor);
        }
Esempio n. 7
0
        public SearchProxyCollection(ISearchMetadataCollection metadataCollection,
            Guid id,
            Action<SearchMetadata> changeScopeAction,
            ISchedulerProvider schedulerProvider,
            IColourProvider colourProvider,
            IIconProvider iconsProvider,
            ITextAssociationCollection textAssociationCollection,
            IThemeProvider themeProvider)
        {
            var proxyItems = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta =>
                {
                    return new SearchOptionsProxy(meta,
                        changeScopeAction,
                        colourProvider,
                        themeProvider,
                        new IconSelector(iconsProvider, schedulerProvider),
                        m => metadataCollection.Remove(m.SearchText),
                        iconsProvider.DefaultIconSelector,
                        id);
                })
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the metadata collection
                    var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                        .Select(_ => (SearchMetadata) so)
                        .Subscribe(metadataCollection.AddorUpdate);

                    //when an icon or colour has changed we need to record user choice so 
                    //the same choice can be used again
                    var iconChanged = so.WhenValueChanged(proxy => proxy.IconKind, false).ToUnit();
                    var colourChanged = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                    var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.CaseSensitive, false).ToUnit();

                    var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                        .Throttle(TimeSpan.FromMilliseconds(250))
                        .Select(_ => new TextAssociation(so.Text, so.CaseSensitive, so.UseRegex, so.HighlightHue.Swatch,
                            so.IconKind.ToString(), so.HighlightHue.Name, DateTime.UtcNow))
                        .Subscribe(textAssociationCollection.MarkAsChanged);

                    return new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged);
                })
                .AsObservableCache();

            Count = proxyItems.CountChanged.StartWith(0).ForBinding();

            var monitor = MonitorPositionalChanges().Subscribe(metadataCollection.Add);
            
            //load data onto grid
            var collection = new ObservableCollectionExtended<SearchOptionsProxy>();

            var includedLoader = proxyItems
                .Connect(proxy => !proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(collection, new ObservableCollectionAdaptor<SearchOptionsProxy, string>(0))
                .DisposeMany()
                .Subscribe();

            var excludedLoader = proxyItems
                .Connect(proxy => proxy.IsExclusion)
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Text))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(out var excluded)
                .DisposeMany()
                .Subscribe();


            Excluded = excluded;
            Included = new ReadOnlyObservableCollection<SearchOptionsProxy>(collection);

            _cleanUp = new CompositeDisposable(proxyItems, includedLoader, excludedLoader, monitor);
        }
Esempio n. 8
0
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
                                      ISearchMetadataFactory searchMetadataFactory,
                                      ISchedulerProvider schedulerProvider,
                                      IColourProvider colourProvider,
                                      IIconProvider iconsProvider,
                                      ITextAssociationCollection textAssociationCollection,
                                      SearchHints searchHints)
        {
            SearchHints = searchHints;

            var proxyItems = metadataCollection.Metadata.Connect()
                             .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                             .Transform(meta =>
            {
                return(new SearchOptionsProxy(meta,
                                              colourProvider,
                                              new IconSelector(iconsProvider, schedulerProvider),
                                              m => metadataCollection.Remove(m.SearchText),
                                              iconsProvider.DefaultIconSelector,
                                              Id));
            })
                             .SubscribeMany(so =>
            {
                //when a value changes, write the original value back to the metadata collection
                var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                                            .Select(_ => (SearchMetadata)so)
                                            .Subscribe(metadataCollection.AddorUpdate);

                //when an icon or colour has changed we need to record user choice so
                //the same choice can be used again
                var iconChanged       = so.WhenValueChanged(proxy => proxy.IconKind, false).ToUnit();
                var colourChanged     = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.IgnoreCase, false).ToUnit();

                var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                                             .Throttle(TimeSpan.FromMilliseconds(250))
                                             .Select(_ => new TextAssociation(so.Text, so.IgnoreCase, so.UseRegex, so.HighlightHue.Swatch, so.IconKind.ToString(), so.HighlightHue.Name, DateTime.Now))
                                             .Subscribe(textAssociationCollection.MarkAsChanged);

                return(new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged));
            })
                             .AsObservableCache();

            var monitor = MonitorPositionalChanges()
                          .Subscribe(metadataCollection.Add);


            //load data onto grid
            var collection = new ObservableCollectionExtended <SearchOptionsProxy>();

            var userOptions = proxyItems.Connect()
                              .Sort(SortExpressionComparer <SearchOptionsProxy> .Ascending(proxy => proxy.Position))
                              .ObserveOn(schedulerProvider.MainThread)
                              //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                              .Bind(collection, new ObservableCollectionAdaptor <SearchOptionsProxy, string>(0))
                              .DisposeMany()
                              .Subscribe();

            Data = new ReadOnlyObservableCollection <SearchOptionsProxy>(collection);

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested
                                .ObserveOn(schedulerProvider.Background)
                                .Subscribe(request =>
            {
                var meta = searchMetadataFactory.Create(request.Text,
                                                        request.UseRegEx,
                                                        metadataCollection.NextIndex(),
                                                        false);
                metadataCollection.AddorUpdate(meta);
            });

            _cleanUp = new CompositeDisposable(searchInvoker,
                                               userOptions,
                                               searchInvoker,
                                               monitor,
                                               SearchHints);
        }
Esempio n. 9
0
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
                                      ISchedulerProvider schedulerProvider,
                                      SearchHints searchHints)
        {
            SearchHints = searchHints;
            //TODO: options for colour

            var swatches = new SwatchesProvider().Swatches;

            bool binding = false;

            var orderChanged = Observable.FromEventPattern <OrderChangedEventArgs>(
                h => PositionMonitor.OrderChanged += h,
                h => PositionMonitor.OrderChanged -= h)
                               .Throttle(TimeSpan.FromMilliseconds(125))
                               .Select(evt => evt.EventArgs)
                               .Where(args => args.PreviousOrder != null && args.NewOrder.Length == args.PreviousOrder.Length)
                               .Select(positionChangedArgs =>
            {
                //reprioritise filters and highlights
                return(positionChangedArgs.NewOrder
                       .OfType <SearchOptionsProxy>()
                       .Select((item, index) => new { Meta = (SearchMetadata)item, index })
                       //.Where(x => x.index != x.Meta.Position)
                       .Select(x => new SearchMetadata(x.Meta, x.index))
                       .ToArray());
            })
                               .Subscribe(positionChangedArgs =>
            {
                positionChangedArgs.ForEach(metadataCollection.AddorUpdate);
            });

            ReadOnlyObservableCollection <SearchOptionsProxy> data;

            var userOptions = metadataCollection.Metadata.Connect()
                              .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                              .Transform(meta => new SearchOptionsProxy(meta, swatches, m => metadataCollection.Remove(m.SearchText)))
                              .SubscribeMany(so =>
            {
                //when a value changes, write the original value back to the cache
                return(so.WhenAnyPropertyChanged()
                       .Select(_ => new SearchMetadata(so.Position, so.Text, so.Filter, so.Highlight, so.UseRegex, so.IgnoreCase))
                       .Subscribe(metadataCollection.AddorUpdate));
            })
                              .Sort(SortExpressionComparer <SearchOptionsProxy> .Ascending(proxy => proxy.Position))

                              .ObserveOn(schedulerProvider.MainThread)
                              .Bind(out data)
                              .Subscribe();

            Data = data;

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested.Subscribe(request =>
            {
                schedulerProvider.Background.Schedule(() =>
                {
                    metadataCollection.AddorUpdate(new SearchMetadata(metadataCollection.NextIndex(), request.Text, false, true, request.UseRegEx, true));
                });
            });


            _cleanUp = new CompositeDisposable(searchInvoker,
                                               userOptions,
                                               searchInvoker,
                                               orderChanged);
        }
 public void Remove(string searchText)
 {
     _metadataCollection.Remove(searchText);
 }
        public SearchOptionsViewModel(ISearchMetadataCollection metadataCollection,
            ISearchMetadataFactory searchMetadataFactory,
            ISchedulerProvider schedulerProvider,
            IColourProvider colourProvider,
            IIconProvider iconsProvider,
            ITextAssociationCollection textAssociationCollection,
            SearchHints searchHints,
            IThemeProvider themeProvider)
        {
            SearchHints = searchHints;

            var proxyItems = metadataCollection.Metadata.Connect()
                .WhereReasonsAre(ChangeReason.Add, ChangeReason.Remove) //ignore updates because we update from here
                .Transform(meta =>
                {
                    return new SearchOptionsProxy(meta,
                        colourProvider,
                        themeProvider,
                        new IconSelector(iconsProvider, schedulerProvider),
                        m => metadataCollection.Remove(m.SearchText),
                        iconsProvider.DefaultIconSelector,
                        Id);
                })
                .SubscribeMany(so =>
                {
                    //when a value changes, write the original value back to the metadata collection
                    var anyPropertyHasChanged = so.WhenAnyPropertyChanged()
                        .Select(_ => (SearchMetadata) so)
                        .Subscribe(metadataCollection.AddorUpdate);

                    //when an icon or colour has changed we need to record user choice so
                    //the same choice can be used again
                    var iconChanged = so.WhenValueChanged(proxy => proxy.IconKind,false).ToUnit();
                    var colourChanged = so.WhenValueChanged(proxy => proxy.HighlightHue, false).ToUnit();
                    var ignoreCaseChanged = so.WhenValueChanged(proxy => proxy.IgnoreCase, false).ToUnit();

                    var textAssociationChanged = iconChanged.Merge(colourChanged).Merge(ignoreCaseChanged)
                                .Throttle(TimeSpan.FromMilliseconds(250))
                                .Select(_=> new TextAssociation(so.Text, so.IgnoreCase, so.UseRegex, so.HighlightHue.Swatch, so.IconKind.ToString(), so.HighlightHue.Name, DateTime.Now))
                                .Subscribe(textAssociationCollection.MarkAsChanged);

                    return new CompositeDisposable(anyPropertyHasChanged, textAssociationChanged);
                })
                .AsObservableCache();

            var monitor = MonitorPositionalChanges()
                .Subscribe(metadataCollection.Add);

            //load data onto grid
            var collection = new ObservableCollectionExtended<SearchOptionsProxy>();

            var userOptions = proxyItems.Connect()
                .Sort(SortExpressionComparer<SearchOptionsProxy>.Ascending(proxy => proxy.Position))
                .ObserveOn(schedulerProvider.MainThread)
                //force reset for each new or removed item dues to a bug in the underlying dragablz control which inserts in an incorrect position
                .Bind(collection, new ObservableCollectionAdaptor<SearchOptionsProxy, string>(0))
                .DisposeMany()
                .Subscribe();

            Data = new ReadOnlyObservableCollection<SearchOptionsProxy>(collection);

            //command to add the current search to the tail collection
            var searchInvoker = SearchHints.SearchRequested
                .ObserveOn(schedulerProvider.Background)
                .Subscribe(request =>
                {
                    var meta = searchMetadataFactory.Create(request.Text,
                        request.UseRegEx,
                        metadataCollection.NextIndex(),
                        false);
                    metadataCollection.AddorUpdate(meta);
                });

            _cleanUp = new CompositeDisposable(searchInvoker,
                userOptions,
                searchInvoker,
                monitor,
                SearchHints);
        }