public StatisticService(INorthwindRepository northwindRepository) { this.northwindRepository = northwindRepository; productsList = new SourceList <Product>(); customersList = new SourceList <Customer>(); orderDetailsList = new SourceList <Order_Detail>(); ordersList = new SourceList <Order>(); #region Customers statistics customersByCountries = customersList.Connect(). GroupOn(customer => customer.Country). Transform(customersGroup => new CustomersByCountry() { CountryName = customersGroup.GroupKey, CustomersCount = customersGroup.List.Count }). ObserveOnDispatcher(). Bind(out _customersByCountries); purchasesByCustomers = orderDetailsList.Connect(). Transform(orderDetail => new { CompanyName = orderDetail.Order.Customer.CompanyName, PurchaseByOrderDetail = orderDetail.UnitPrice * orderDetail.Quantity }). GroupOn(orderDetail => orderDetail.CompanyName). Transform(groupOfOrderDetails => new PurchasesByCustomers() { CompanyName = groupOfOrderDetails.GroupKey, Purchases = groupOfOrderDetails.List.Items.Sum(a => a.PurchaseByOrderDetail) }). Sort(SortExpressionComparer <PurchasesByCustomers> .Descending(a => a.Purchases)). Top(10). ObserveOnDispatcher(). Bind(out _purchasesByCustomers); #endregion #region Employees statistics salesByEmployees = orderDetailsList.Connect(). Transform(orderDetail => new { LastName = orderDetail.Order.Employee.LastName, SaleByOrderDetail = orderDetail.UnitPrice * orderDetail.Quantity }). GroupOn(orderDetail => orderDetail.LastName). Transform(groupOfOrderDetail => new EmployeeSales() { LastName = groupOfOrderDetail.GroupKey, Sales = groupOfOrderDetail.List.Items.Sum(a => a.SaleByOrderDetail) }). ObserveOnDispatcher(). Sort(SortExpressionComparer <EmployeeSales> .Ascending(a => a.Sales)). Bind(out _salesByEmployees); #endregion #region Products statistics productsByCategories = productsList.Connect(). GroupOn(product => product.Category.CategoryName). Transform(groupOfProducts => new ProductsByCateogries() { CategoryName = groupOfProducts.GroupKey, NumberOfProducts = groupOfProducts.List.Count }). ObserveOnDispatcher(). Bind(out _productsByCategories); #endregion #region Orders statistics ordersByCountries = ordersList.Connect(). GroupOn(order => order.Customer.Country). Transform(groupOfOrders => new OrdersByCountry() { Country = groupOfOrders.GroupKey, NumberOfOrders = groupOfOrders.List.Count }). ObserveOnDispatcher(). Top(10). Bind(out _ordersByCountries); salesByCountries = orderDetailsList.Connect().Transform(orderDetail => new { Country = orderDetail.Order.Customer.Country, SaleByOrderDetail = orderDetail.UnitPrice * orderDetail.Quantity }). GroupOn(orderDetail => orderDetail.Country). Transform(groupOfOrderDetails => new SalesByCountry() { Country = groupOfOrderDetails.GroupKey, Sales = groupOfOrderDetails.List.Items.Sum(a => a.SaleByOrderDetail) }). Sort(SortExpressionComparer <SalesByCountry> .Ascending(a => a.Sales)). ObserveOnDispatcher(). Bind(out _salesByCountries); salesByCategories = orderDetailsList.Connect(). Transform(orderDetail => new { Category = orderDetail.Product.Category.CategoryName, SaleByOrderDetail = orderDetail.UnitPrice * orderDetail.Quantity }). GroupOn(orderDetail => orderDetail.Category). Transform(groupOfOrderDeatils => new SalesByCategory() { Category = groupOfOrderDeatils.GroupKey, Sales = groupOfOrderDeatils.List.Items.Sum(a => a.SaleByOrderDetail) }). ObserveOnDispatcher(). Bind(out _salesByCategories); #endregion FillCollections(); }
public MailBoxViewModel(IProfileDataQueryFactory queryFactory, IMailService mailService) { _queryFactory = queryFactory; _mailService = mailService; _mailFolderSelectionViewModel = new MailFolderSelectionViewModel(_sourceFolders.AsObservableCache()); var folderChanges = _sourceFolders.Connect(f => f.Type != FolderType.Root) .ObserveOn(RxApp.TaskpoolScheduler) .Sort(SortExpressionComparer <MailFolder> .Ascending(f => f.Type).ThenByAscending(f => f.Name)) .TransformToTree(f => f.ParentId) .Transform(n => new MailFolderViewModel(n, this, queryFactory, mailService)) .DisposeMany() .Publish(); folderChanges .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _allFolders) .Subscribe() .DisposeWith(_disposables); folderChanges .Filter(f => f.IsFavorite) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _favoriteFolders) .Subscribe() .DisposeWith(_disposables); folderChanges.Connect() .DisposeWith(_disposables); var folderCollection = folderChanges .ToCollection() .Publish(); folderCollection .Select(folders => folders.FirstOrDefault(f => f.Type == FolderType.Inbox)) .ObserveOn(RxApp.MainThreadScheduler) .ToPropertyEx(this, x => x.Inbox) .DisposeWith(_disposables); folderCollection.Connect() .DisposeWith(_disposables); _mailService.FolderChanges .ObserveOn(RxApp.TaskpoolScheduler) .Subscribe(changes => { _sourceFolders.Edit(updater => { foreach (var c in changes) { switch (c.State) { case DeltaState.Add: case DeltaState.Update: updater.AddOrUpdate(c.Entity); break; case DeltaState.Remove: updater.RemoveKey(c.Entity.Id); break; } } }); }) .DisposeWith(_disposables); Synchronize = ReactiveCommand.CreateFromTask(_mailService.SynchronizeFoldersAsync); //Synchronize.WithLatestFrom(folderCollection, (_, folders) => folders.Where(f => f.IsFavorite)) // .Subscribe(favoriteFolders => // { // foreach (var f in favoriteFolders) // { // f.Synchronize.Execute().Subscribe(); // } // }) // .DisposeWith(_disposables); Synchronize.ThrownExceptions .Subscribe(ex => this.Log().Error(ex)) .DisposeWith(_disposables); Synchronize.IsExecuting .ToPropertyEx(this, x => x.IsSynchronizing) .DisposeWith(_disposables); }
public MetricsViewModel(ISourcesCacheProvider cacheProvider) { _model = new MetricsModel { Caption = "Metrics", Cache = cacheProvider.CurrentCache }; Disposables.Add(_model); _model.WhenAnyValue(x => x.Caption, x => x.Online) .Subscribe(v => Title = v.Item1 + (v.Item2 ? " >" : " ||")); var dynamicFilter = _model.SelectedSourcesChanged .Select(_ => Filters.CreateFilterMetricBySources(_model)); var observable = _model.Cache.Metrics .Connect() .Filter(dynamicFilter) .Publish(); _metricsCache = observable .AsObservableCache() .DisposeWith(Disposables); observable .Transform(x => new MetricValueItem { Metric = x }) .Sort(SortExpressionComparer <MetricValueItem> .Ascending(x => x.Metric.Instance.Source.Name) .ThenByAscending(x => x.Metric.Instance.Name) .ThenByAscending(x => x.Metric.Name)) .ObserveOnDispatcher() .Bind(out var metricValuesStatic) .Subscribe() .DisposeWith(Disposables); observable .Connect() .DisposeWith(Disposables); var metricValuesDynamicSource = new SourceList <MetricValueItem>() .DisposeWith(Disposables); metricValuesDynamicSource .Connect() .ObserveOnDispatcher() .Bind(out var metricValuesDynamic) .Subscribe() .DisposeWith(Disposables); _model.WhenAnyValue(x => x.MetricDiagramVisible) .Subscribe(x => MetricValuesList = x ? metricValuesStatic : metricValuesDynamic); _model.SelectedSourcesChanged.Subscribe(_ => UpdateSelectedMetrics()); UpdateSelectedMetrics(); var canStart = _model.WhenAny(x => x.Online, x => !x.Value); StartCommand = ReactiveCommand.Create(OnStart, canStart); var canStop = _model.WhenAny(x => x.Online, x => x.Value); StopCommand = ReactiveCommand.Create(OnStop, canStop); UpdateCommand = ReactiveCommand.Create(OnUpdate, canStop); var mapper = Mappers.Xy <MetricValueItem>() .X(item => (double)item.Interval.Ticks / TimeSpan.FromMinutes(5).Ticks) .Y(item => item.Value); //lets save the mapper globally. Charting.For <MetricValueItem>(mapper); SeriesCollection = new ChartValues <MetricValueItem>(); //lets set how to display the X Labels DateTimeFormatter = value => new DateTime((long)value * TimeSpan.FromMinutes(5).Ticks).ToString("t"); UpdateCommand.Subscribe(results => { if (_model.MetricDiagramVisible) { SeriesCollection.Clear(); if (results != null) { SeriesCollection.AddRange(results); } } else { metricValuesDynamicSource.Edit(innerList => { innerList.Clear(); innerList.AddRange(results); }); } }); }
public TailViewModel([NotNull] ILogger logger, [NotNull] ISchedulerProvider schedulerProvider, [NotNull] IFileWatcher fileWatcher, [NotNull] ISelectionMonitor selectionMonitor, [NotNull] IClipboardHandler clipboardHandler, [NotNull] ISearchInfoCollection searchInfoCollection, [NotNull] IInlineViewerFactory inlineViewerFactory, [NotNull] ISetting <GeneralOptions> generalOptions, [NotNull] ISearchMetadataCollection searchMetadataCollection, [NotNull] IStateBucketService stateBucketService, [NotNull] SearchOptionsViewModel searchOptionsViewModel, [NotNull] ITailViewStateRestorer restorer, [NotNull] SearchHints searchHints, [NotNull] ITailViewStateControllerFactory tailViewStateControllerFactory) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (schedulerProvider == null) { throw new ArgumentNullException(nameof(schedulerProvider)); } if (fileWatcher == null) { throw new ArgumentNullException(nameof(fileWatcher)); } if (selectionMonitor == null) { throw new ArgumentNullException(nameof(selectionMonitor)); } if (clipboardHandler == null) { throw new ArgumentNullException(nameof(clipboardHandler)); } if (searchInfoCollection == null) { throw new ArgumentNullException(nameof(searchInfoCollection)); } if (inlineViewerFactory == null) { throw new ArgumentNullException(nameof(inlineViewerFactory)); } if (generalOptions == null) { throw new ArgumentNullException(nameof(generalOptions)); } if (searchMetadataCollection == null) { throw new ArgumentNullException(nameof(searchMetadataCollection)); } if (stateBucketService == null) { throw new ArgumentNullException(nameof(stateBucketService)); } if (searchOptionsViewModel == null) { throw new ArgumentNullException(nameof(searchOptionsViewModel)); } if (searchHints == null) { throw new ArgumentNullException(nameof(searchHints)); } Name = fileWatcher.FullName; SelectionMonitor = selectionMonitor; SearchOptions = searchOptionsViewModel; SearchHints = searchHints; SearchCollection = new SearchCollection(searchInfoCollection, schedulerProvider); CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); OpenFileCommand = new Command(() => Process.Start(fileWatcher.FullName)); OpenFolderCommand = new Command(() => Process.Start(fileWatcher.Folder)); SearchMetadataCollection = searchMetadataCollection; UsingDarkTheme = generalOptions.Value .ObserveOn(schedulerProvider.MainThread) .Select(options => options.Theme == Theme.Dark) .ForBinding(); HighlightTail = generalOptions.Value .ObserveOn(schedulerProvider.MainThread) .Select(options => options.HighlightTail) .ForBinding(); HighlightDuration = generalOptions.Value .ObserveOn(schedulerProvider.MainThread) .Select(options => new Duration(TimeSpan.FromSeconds(options.HighlightDuration))) .ForBinding(); //this deails with state when loading the system at start up and at shut-down _stateProvider = new TailViewPersister(this, restorer); //this controller responsible for loading and persisting user search stuff as the user changes stuff var stateController = tailViewStateControllerFactory.Create(this); //An observable which acts as a scroll command var autoChanged = this.WhenValueChanged(vm => vm.AutoTail); var scroller = _userScrollRequested.CombineLatest(autoChanged, (user, auto) => { var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User; return(new ScrollRequest(mode, user.PageSize, user.FirstIndex)); }) .Do(x => logger.Info("Scrolling to {0}/{1}", x.FirstIndex, x.PageSize)) .DistinctUntilChanged(); FileStatus = fileWatcher.Status.ForBinding(); //command to add the current search to the tail collection var searchInvoker = SearchHints.SearchRequested.Subscribe(request => { searchInfoCollection.Add(request.Text, request.UseRegEx); }); //User feedback to show file size FileSizeText = fileWatcher.Latest.Select(fn => fn.Size) .Select(size => size.FormatWithAbbreviation()) .DistinctUntilChanged() .ForBinding(); //tailer is the main object used to tail, scroll and filter in a file var lineScroller = new LineScroller(SearchCollection.Latest.ObserveOn(schedulerProvider.Background), scroller); //load lines into observable collection var lineProxyFactory = new LineProxyFactory(new TextFormatter(searchMetadataCollection), new LineMatches(searchMetadataCollection)); var loader = lineScroller.Lines.Connect() .LogChanges(logger, "Received") .Transform(lineProxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 3)) .LogChanges(logger, "Sorting") .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data, 100) .LogChanges(logger, "Bound") .DisposeMany() .LogErrors(logger) .Subscribe(); //monitor matching lines and start index, Count = searchInfoCollection.All.Select(latest => latest.Count).ForBinding(); CountText = searchInfoCollection.All.Select(latest => $"{latest.Count.ToString("##,###")} lines").ForBinding(); LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding(); ////track first visible index var firstIndexMonitor = lineScroller.Lines.Connect() .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult() .ToCollection() .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1) .ObserveOn(schedulerProvider.MainThread) .Subscribe(first => { FirstIndex = first; }); //Create objects required for inline viewing var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected) .Where(selected => selected != null) .Select(selected => selected.IsUserDefined) .DistinctUntilChanged() .Replay(1) .RefCount(); var inlineViewerVisible = isUserDefinedChanged.CombineLatest(this.WhenValueChanged(vm => vm.ShowInline), (userDefined, showInline) => userDefined && showInline); CanViewInline = isUserDefinedChanged.ForBinding(); InlineViewerVisible = inlineViewerVisible.ForBinding(); //return an empty line provider unless user is viewing inline - this saves needless trips to the file var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : new EmptyLineProvider()); InlineViewer = inlineViewerFactory.Create(inline, this.WhenValueChanged(vm => vm.SelectedItem), lineProxyFactory); _cleanUp = new CompositeDisposable(lineScroller, loader, firstIndexMonitor, FileStatus, Count, LatestCount, FileSizeText, CanViewInline, InlineViewer, InlineViewerVisible, SearchCollection, searchInfoCollection, HighlightTail, UsingDarkTheme, searchHints, searchMetadataCollection, SelectionMonitor, SearchOptions, searchInvoker, stateController, _userScrollRequested.SetAsComplete()); }
public MailFolderViewModel(Node <MailFolder, string> node, MailBoxViewModel mailBox, IProfileDataQueryFactory queryFactory, IMailService mailService) { Id = node.Item.Id; ParentId = node.Item.ParentId; Name = node.Item.Name; Type = node.Item.Type; IsFavorite = node.Item.IsFavorite; Messages = new MessageListViewModel(node.Item.Id, node.Item.Type, mailBox, queryFactory, mailService, Activator); Synchronize = ReactiveCommand.CreateFromObservable(() => Observable .StartAsync((token) => mailService.SynchronizeMessagesAsync(node.Item.Id, token)) .TakeUntil(CancelSynchronization)); Synchronize.IsExecuting .ToPropertyEx(this, x => x.IsSynchronizing) .DisposeWith(_disposables); Synchronize.ThrownExceptions .Subscribe(ex => this.Log().Error(ex)) .DisposeWith(_disposables); CancelSynchronization = ReactiveCommand.Create(() => { }, Synchronize.IsExecuting); Move = ReactiveCommand.CreateFromTask(async() => { var result = await mailBox.PromptUserToSelectFolder( "Move a folder", "Select another folder to move to:", includeRoot: true, CanMoveTo); this.Log().Debug(result); }); node.Children.Connect() .Transform(n => new MailFolderViewModel(n, mailBox, queryFactory, mailService)) .Sort(SortExpressionComparer <MailFolderViewModel> .Ascending(f => f.Name)) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _childFolders) .DisposeMany() .Subscribe() .DisposeWith(_disposables); mailService.MessageChanges .Where(changes => changes.AffectsFolder(node.Item.Id)) .SelectMany(_ => CountMessages(queryFactory, node.Item.Id)) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { UnreadCount = x.UnreadCount; TotalCount = x.TotalCount; }) .DisposeWith(_disposables); CountMessages(queryFactory, node.Item.Id) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { UnreadCount = x.UnreadCount; TotalCount = x.TotalCount; }) .DisposeWith(_disposables); }
private ProxyService() { mCurrent = this; ProxyDomains = new SourceList <AccelerateProjectGroupDTO>(); ProxyScripts = new SourceList <ScriptDTO>(); ProxyDomains .Connect() .ObserveOn(RxApp.MainThreadScheduler) .Sort(SortExpressionComparer <AccelerateProjectGroupDTO> .Ascending(x => x.Order).ThenBy(x => x.Name)) .Bind(out _ProxyDomainsList) .Subscribe(_ => SelectGroup = ProxyDomains.Items.FirstOrDefault()); this.WhenValueChanged(x => x.ProxyStatus, false) .Subscribe(async x => { if (x) { httpProxyService.ProxyDomains = EnableProxyDomains; httpProxyService.IsEnableScript = ProxySettings.IsEnableScript.Value; httpProxyService.Scripts = EnableProxyScripts; if (IApplication.IsDesktopPlatform) { httpProxyService.IsOnlyWorkSteamBrowser = ProxySettings.IsOnlyWorkSteamBrowser.Value; httpProxyService.IsSystemProxy = ProxySettings.EnableWindowsProxy.Value; httpProxyService.IsProxyGOG = ProxySettings.IsProxyGOG.Value; } else { httpProxyService.IsSystemProxy = true; } // macOS 上目前因权限问题仅支持 0.0.0.0(IPAddress.Any) httpProxyService.ProxyIp = (!OperatingSystem2.IsMacOS && IPAddress2.TryParse(ProxySettings.SystemProxyIp.Value, out var ip)) ? ip : IPAddress.Any; httpProxyService.Socks5ProxyEnable = ProxySettings.Socks5ProxyEnable.Value; httpProxyService.Socks5ProxyPortId = ProxySettings.Socks5ProxyPortId.Value; if (!ModelValidatorProvider.IsPortId(httpProxyService.Socks5ProxyPortId)) { httpProxyService.Socks5ProxyPortId = ProxySettings.DefaultSocks5ProxyPortId; } //httpProxyService.HostProxyPortId = ProxySettings.HostProxyPortId; httpProxyService.TwoLevelAgentEnable = ProxySettings.TwoLevelAgentEnable.Value; httpProxyService.TwoLevelAgentProxyType = (ExternalProxyType)ProxySettings.TwoLevelAgentProxyType.Value; if (!httpProxyService.TwoLevelAgentProxyType.IsDefined()) { httpProxyService.TwoLevelAgentProxyType = IHttpProxyService.DefaultTwoLevelAgentProxyType; } httpProxyService.TwoLevelAgentIp = IPAddress2.TryParse(ProxySettings.TwoLevelAgentIp.Value, out var ip_t) ? ip_t.ToString() : IPAddress.Loopback.ToString(); httpProxyService.TwoLevelAgentPortId = ProxySettings.TwoLevelAgentPortId.Value; if (!ModelValidatorProvider.IsPortId(httpProxyService.TwoLevelAgentPortId)) { httpProxyService.TwoLevelAgentPortId = ProxySettings.DefaultTwoLevelAgentPortId; } httpProxyService.TwoLevelAgentUserName = ProxySettings.TwoLevelAgentUserName.Value; httpProxyService.TwoLevelAgentPassword = ProxySettings.TwoLevelAgentPassword.Value; httpProxyService.ProxyDNS = IPAddress2.TryParse(ProxySettings.ProxyMasterDns.Value, out var dns) ? dns : null; this.RaisePropertyChanged(nameof(EnableProxyDomains)); this.RaisePropertyChanged(nameof(EnableProxyScripts)); if (!httpProxyService.IsSystemProxy) { const ushort httpsPort = 443; var inUse = httpProxyService.PortInUse(httpsPort); if (inUse) { string?error_CommunityFix_StartProxyFaild443 = null; if (OperatingSystem2.IsWindows) { var p = SocketHelper.GetProcessByTcpPort(httpsPort); if (p != null) { error_CommunityFix_StartProxyFaild443 = AppResources.CommunityFix_StartProxyFaild443___.Format(httpsPort, p.ProcessName, p.Id); } } error_CommunityFix_StartProxyFaild443 ??= AppResources.CommunityFix_StartProxyFaild443_.Format(httpsPort); Toast.Show(error_CommunityFix_StartProxyFaild443); return; } } var isRun = await httpProxyService.StartProxy(); if (isRun) { if (!httpProxyService.IsSystemProxy) { if (httpProxyService.ProxyDomains.Any_Nullable()) { var localhost = IPAddress.Any.Equals(httpProxyService.ProxyIp) ? IPAddress.Loopback.ToString() : httpProxyService.ProxyIp.ToString(); var hosts = httpProxyService.ProxyDomains !.SelectMany(s => { if (s == null) { return(default !);
public InlineViewer([NotNull] InlineViewerArgs args, [NotNull] IClipboardHandler clipboardHandler, [NotNull] ISchedulerProvider schedulerProvider, [NotNull] ISelectionMonitor selectionMonitor, [NotNull] ILogger logger, [NotNull] IThemeProvider themeProvider) { if (args == null) { throw new ArgumentNullException(nameof(args)); } if (clipboardHandler == null) { throw new ArgumentNullException(nameof(clipboardHandler)); } if (schedulerProvider == null) { throw new ArgumentNullException(nameof(schedulerProvider)); } if (selectionMonitor == null) { throw new ArgumentNullException(nameof(selectionMonitor)); } if (themeProvider == null) { throw new ArgumentNullException(nameof(themeProvider)); } SelectionMonitor = selectionMonitor; CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); _isSettingScrollPosition = false; var lineProvider = args.LineProvider; var selectedChanged = args.SelectedChanged; var pageSize = this.WhenValueChanged(vm => vm.PageSize); //if use selection is null, tail the file var scrollSelected = selectedChanged .CombineLatest(lineProvider, pageSize, (proxy, lp, pge) => proxy == null ? new ScrollRequest(pge, 0) : new ScrollRequest(pge, proxy.Start)) .DistinctUntilChanged(); var horizonalScrollArgs = new ReplaySubject <TextScrollInfo>(1); HorizonalScrollChanged = hargs => { horizonalScrollArgs.OnNext(hargs); }; var scrollUser = _userScrollRequested .Where(x => !_isSettingScrollPosition) .Select(request => new ScrollRequest(ScrollReason.User, request.PageSize, request.FirstIndex)); var scroller = scrollSelected.Merge(scrollUser) .ObserveOn(schedulerProvider.Background) .DistinctUntilChanged(); var lineScroller = new LineScroller(lineProvider, scroller); Count = lineProvider.Select(lp => lp.Count).ForBinding(); MaximumChars = lineScroller.MaximumLines() .ObserveOn(schedulerProvider.MainThread) .ForBinding(); var proxyFactory = new LineProxyFactory(new TextFormatter(args.SearchMetadataCollection), new LineMatches(args.SearchMetadataCollection), horizonalScrollArgs.DistinctUntilChanged(), themeProvider); //load lines into observable collection var loader = lineScroller.Lines.Connect() .Transform(proxyFactory.Create, new ParallelisationOptions(ParallelType.Ordered, 3)) .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data) .DisposeMany() .LogErrors(logger) .Subscribe(); // track first visible index [required to set scroll extent] var firstIndexMonitor = lineScroller.Lines.Connect() .Buffer(TimeSpan.FromMilliseconds(250)).FlattenBufferResult() .ToCollection() .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1) .ObserveOn(schedulerProvider.MainThread) .Subscribe(first => { try { _isSettingScrollPosition = true; FirstIndex = first; } finally { _isSettingScrollPosition = false; } }); _cleanUp = new CompositeDisposable(lineScroller, loader, Count, firstIndexMonitor, SelectionMonitor, MaximumChars, horizonalScrollArgs.SetAsComplete(), _userScrollRequested.SetAsComplete()); }
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); }
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.UtcNow)) .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); }
protected override void OnParametersSet() { base.OnParametersSet(); ViewModel.TitlesViews.Connect().Transform(t => t.Name).Sort(SortExpressionComparer <string> .Ascending(s => s)).ObserveOn(RxApp.MainThreadScheduler).Bind(out activeTitleGroup).Subscribe(); }
public TailViewModel([NotNull] ILogger logger, [NotNull] ISchedulerProvider schedulerProvider, [NotNull] IFileWatcher fileWatcher, [NotNull] ISelectionMonitor selectionMonitor, [NotNull] IClipboardHandler clipboardHandler, [NotNull] ISearchInfoCollection searchInfoCollection, [NotNull] IInlineViewerFactory inlineViewerFactory, [NotNull] GeneralOptionBindings generalOptionBindings, [NotNull] ICombinedSearchMetadataCollection combinedSearchMetadataCollection, [NotNull] IStateBucketService stateBucketService, [NotNull] ITailViewStateRestorer restorer, [NotNull] SearchHints searchHints, [NotNull] ITailViewStateControllerFactory tailViewStateControllerFactory, [NotNull] IThemeProvider themeProvider, [NotNull] SearchCollection searchCollection, [NotNull] ITextFormatter textFormatter, [NotNull] ILineMatches lineMatches, [NotNull] IObjectProvider objectProvider, [NotNull] IDialogCoordinator dialogCoordinator) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (schedulerProvider == null) { throw new ArgumentNullException(nameof(schedulerProvider)); } if (fileWatcher == null) { throw new ArgumentNullException(nameof(fileWatcher)); } if (clipboardHandler == null) { throw new ArgumentNullException(nameof(clipboardHandler)); } if (searchInfoCollection == null) { throw new ArgumentNullException(nameof(searchInfoCollection)); } if (inlineViewerFactory == null) { throw new ArgumentNullException(nameof(inlineViewerFactory)); } if (stateBucketService == null) { throw new ArgumentNullException(nameof(stateBucketService)); } if (themeProvider == null) { throw new ArgumentNullException(nameof(themeProvider)); } if (textFormatter == null) { throw new ArgumentNullException(nameof(textFormatter)); } if (lineMatches == null) { throw new ArgumentNullException(nameof(lineMatches)); } if (objectProvider == null) { throw new ArgumentNullException(nameof(objectProvider)); } if (dialogCoordinator == null) { throw new ArgumentNullException(nameof(dialogCoordinator)); } if (combinedSearchMetadataCollection == null) { throw new ArgumentNullException(nameof(combinedSearchMetadataCollection)); } Name = fileWatcher.FullName; SelectionMonitor = selectionMonitor ?? throw new ArgumentNullException(nameof(selectionMonitor)); GeneralOptionBindings = generalOptionBindings; SearchHints = searchHints ?? throw new ArgumentNullException(nameof(searchHints)); CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); OpenFileCommand = new Command(() => Process.Start(fileWatcher.FullName)); OpenFolderCommand = new Command(() => Process.Start(fileWatcher.Folder)); CopyPathToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(fileWatcher.FullName)); UnClearCommand = new Command(fileWatcher.Reset); ClearCommand = new Command(fileWatcher.Clear); KeyAutoTail = new Command(() => { AutoTail = true; }); OpenSearchOptionsCommand = new Command(async() => { await Task.Run(() => { var content = objectProvider.Get <SearchOptionsViewModel>(new Argument <ICombinedSearchMetadataCollection>(combinedSearchMetadataCollection)); dialogCoordinator.Show(this, content, x => content.Dispose()); }); }); var closeOnDeselect = this.WhenValueChanged(vm => vm.IsSelected, false) .Where(selected => !selected) .Subscribe(_ => dialogCoordinator.Close()); SearchCollection = searchCollection ?? throw new ArgumentNullException(nameof(searchCollection)); SearchMetadataCollection = combinedSearchMetadataCollection.Local; var horizonalScrollArgs = new ReplaySubject <TextScrollInfo>(1); HorizonalScrollChanged = args => horizonalScrollArgs.OnNext(args); _tailViewStateControllerFactory = tailViewStateControllerFactory; //this deals with state when loading the system at start up and at shut-down _persister = new TailViewPersister(this, restorer); FileStatus = fileWatcher.Status.ForBinding(); //command to add the current search to the tail collection var searchInvoker = SearchHints.SearchRequested.Subscribe(request => searchInfoCollection.Add(request.Text, request.UseRegEx)); //An observable which acts as a scroll command var autoChanged = this.WhenValueChanged(vm => vm.AutoTail); var scroller = _userScrollRequested.CombineLatest(autoChanged, (user, auto) => { var mode = AutoTail ? ScrollReason.Tail : ScrollReason.User; return(new ScrollRequest(mode, user.PageSize, user.FirstIndex)); }) .Do(x => logger.Info("Scrolling to {0}/{1}", x.FirstIndex, x.PageSize)) .DistinctUntilChanged(); //User feedback to show file size FileSizeText = fileWatcher.Latest.Select(fn => fn.Size) .Select(size => size.FormatWithAbbreviation()) .DistinctUntilChanged() .ForBinding(); //tailer is the main object used to tail, scroll and filter in a file var selectedProvider = SearchCollection.Latest.ObserveOn(schedulerProvider.Background); var lineScroller = new LineScroller(selectedProvider, scroller); MaximumChars = lineScroller.MaximumLines() .ObserveOn(schedulerProvider.MainThread) .ForBinding(); var lineProxyFactory = new LineProxyFactory(textFormatter, lineMatches, horizonalScrollArgs.DistinctUntilChanged(), themeProvider); var loader = lineScroller.Lines.Connect() .LogChanges(logger, "Received") .Transform(lineProxyFactory.Create) .LogChanges(logger, "Sorting") .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data, 100) .LogChanges(logger, "Bound") .DisposeMany() .LogErrors(logger) .Subscribe(); //monitor matching lines and start index, Count = searchInfoCollection.All.Select(latest => latest.Count).ForBinding(); CountText = searchInfoCollection.All.Select(latest => $"{latest.Count:##,###} lines").ForBinding(); LatestCount = SearchCollection.Latest.Select(latest => latest.Count).ForBinding(); ////track first visible index var firstIndexMonitor = lineScroller.Lines.Connect() .Buffer(TimeSpan.FromMilliseconds(25)).FlattenBufferResult() .ToCollection() .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1) .ObserveOn(schedulerProvider.MainThread) .Subscribe(first => { FirstIndex = first; }); //Create objects required for inline viewing var isUserDefinedChanged = SearchCollection.WhenValueChanged(sc => sc.Selected) .Where(selected => selected != null) .Select(selected => selected.IsUserDefined) .DistinctUntilChanged() .Replay(1) .RefCount(); var showInline = this.WhenValueChanged(vm => vm.ShowInline); var inlineViewerVisible = isUserDefinedChanged.CombineLatest(showInline, (userDefined, showInlne) => userDefined && showInlne); CanViewInline = isUserDefinedChanged.ForBinding(); InlineViewerVisible = inlineViewerVisible.ForBinding(); //return an empty line provider unless user is viewing inline - this saves needless trips to the file var inline = searchInfoCollection.All.CombineLatest(inlineViewerVisible, (index, ud) => ud ? index : EmptyLineProvider.Instance); InlineViewer = inlineViewerFactory.Create(combinedSearchMetadataCollection, inline, this.WhenValueChanged(vm => vm.SelectedItem)); _cleanUp = new CompositeDisposable(lineScroller, loader, firstIndexMonitor, FileStatus, Count, LatestCount, FileSizeText, CanViewInline, InlineViewer, InlineViewerVisible, SearchCollection, searchInfoCollection, searchHints, combinedSearchMetadataCollection, SelectionMonitor, closeOnDeselect, Disposable.Create(dialogCoordinator.Close), searchInvoker, MaximumChars, _stateMonitor, combinedSearchMetadataCollection, horizonalScrollArgs.SetAsComplete(), _userScrollRequested.SetAsComplete()); }
public MovieListViewModel( NavigationManager navigationManager, ILocalStorageService localStorageService, ReduxStore <MovieSearchState> movieSearchStore) { _navigationManager = navigationManager; _localStorageService = localStorageService; // Set initial value SearchText = movieSearchStore.State.SearchText; var source = new SourceCache <OmdbMovieSearchDto, string>(x => x.ImdbId) .DisposeWith(CleanUp); source.Connect() .Sort(SortExpressionComparer <OmdbMovieSearchDto> .Ascending(p => p.Title), SortOptimisations.ComparesImmutableValuesOnly) .Bind(Movies) .Subscribe(_ => UpdateState()) .DisposeWith(CleanUp); source.CountChanged .StartWith(0) .Select(x => x == 0) .ToPropertyEx(this, x => x.IsSourceEmpty) .DisposeWith(CleanUp); var searchTextObservable = this.WhenAnyValue(x => x.SearchText) .Skip(1) // Use throttle to prevent over requesting data .Throttle(TimeSpan.FromMilliseconds(250)) .Publish(); searchTextObservable .Where(string.IsNullOrEmpty) .Subscribe(_ => movieSearchStore.Dispatch(new ResetMovieSearchAction())) .DisposeWith(CleanUp); searchTextObservable .Where(x => !string.IsNullOrEmpty(x)) .Subscribe(x => movieSearchStore.Dispatch(new PerformMovieSearchAction(x))) .DisposeWith(CleanUp); searchTextObservable.Connect(); movieSearchStore .Select(MovieSearchSelectors.SelectIsSearching) .ToPropertyEx(this, x => x.IsSearching) .DisposeWith(CleanUp); movieSearchStore .Select(MovieSearchSelectors.SelectMovies) .Subscribe(x => source.Edit(list => { list.Clear(); list.AddOrUpdate(x); })) .DisposeWith(CleanUp); movieSearchStore .Select(MovieSearchSelectors.SelectSearchText) .Skip(1) .SelectMany(async x => { await SaveSearchTextsAsync(x) .ConfigureAwait(false); return(Unit.Default); }) .Subscribe() .DisposeWith(CleanUp); }
public SeasonFormViewModel( Season season, SeriesFormViewModel parent, IObservable <int> maxSequenceNumber, ResourceManager?resourceManager = null, IScheduler?scheduler = null) : base(parent, maxSequenceNumber, resourceManager, scheduler) { this.Season = season; var canDeletePeriod = this.periodsSource.Connect() .Count() .Select(count => count > MinPeriodCount); this.periodsSource.Connect() .Sort(SortExpressionComparer <Period> .Ascending(period => period.StartYear) .ThenByAscending(period => period.StartMonth) .ThenByAscending(period => period.EndYear) .ThenByAscending(period => period.EndMonth)) .Transform(period => this.CreatePeriodForm(period, canDeletePeriod)) .Bind(out this.periods) .DisposeMany() .Subscribe(); this.CopyProperties(); this.ChannelRule = this.ValidationRule( vm => vm.Channel, channel => !String.IsNullOrWhiteSpace(channel), "ChannelEmpty"); this.PeriodsNonOverlapping = this.periods.ToObservableChangeSet() .AutoRefreshOnObservable(pvm => pvm.Changed) .Select(_ => this.AreAllPeriodsNonOverlapping()); this.WhenAnyValue(vm => vm.CurrentPosterIndex) .Select(index => this.Season.Periods[index].PosterUrl) .BindTo(this, vm => vm.CurrentPosterUrl); var canAddPeriod = this.Periods.ToObservableChangeSet() .AutoRefreshOnObservable(period => period.Valid) .ToCollection() .Select(periods => periods.Count < MaxPeriodCount && periods.All(period => !period.HasErrors)) .CombineLatest(this.PeriodsNonOverlapping, (a, b) => a && b); this.AddPeriod = ReactiveCommand.Create(this.OnAddPeriod, canAddPeriod); var canSwitchToNextPoster = this.WhenAnyValue(vm => vm.CurrentPosterIndex) .Merge(this.Save.Select(_ => this.CurrentPosterIndex)) .Select(index => index != this.Season.Periods.Count - 1 && this.Season.Periods.Skip(index + 1).Any(period => period.PosterUrl != null)); var canSwitchToPreviousPoster = this.WhenAnyValue(vm => vm.CurrentPosterIndex) .Merge(this.Save.Select(_ => this.CurrentPosterIndex)) .Select(index => index != 0 && this.Season.Periods.Take(index).Any(period => period.PosterUrl != null)); this.SwitchToNextPoster = ReactiveCommand.Create( () => this.SetCurrentPosterIndex(index => index + 1), canSwitchToNextPoster); this.SwitchToPreviousPoster = ReactiveCommand.Create( () => this.SetCurrentPosterIndex(index => index - 1), canSwitchToPreviousPoster); this.Save.Discard() .Merge(this.GoToSeries.Discard()) .Delay(TimeSpan.FromMilliseconds(500), this.Scheduler) .Subscribe(() => this.CurrentPosterIndex = 0); this.CanAlwaysDelete(); this.EnableChangeTracking(); }
public FileTailerViewModel(ILogger logger, ISchedulerProvider schedulerProvider, FileInfo fileInfo) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (schedulerProvider == null) { throw new ArgumentNullException(nameof(schedulerProvider)); } if (fileInfo == null) { throw new ArgumentNullException(nameof(fileInfo)); } File = fileInfo.FullName; AutoTail = true; var filterRequest = this.WhenValueChanged(vm => vm.SearchText).Throttle(TimeSpan.FromMilliseconds(125)); var autoTail = this.WhenValueChanged(vm => vm.AutoTail) .CombineLatest(_userScrollRequested, (auto, user) => auto ? new ScrollRequest(user.Rows) : new ScrollRequest(user.Rows, user.FirstIndex + 1)) .DistinctUntilChanged(); var tailer = new FileTailer(fileInfo, filterRequest, autoTail); var lineCounter = tailer .TotalLinesCount .CombineLatest(tailer.MatchedLinesCount, (total, matched) => total == matched ? $"File has {total:#,###} lines" : $"Showing {matched:#,###} of {total:#,###} lines") .Subscribe(text => LineCountText = text); // load lines into observable collection var loader = tailer.Lines.Connect() .Buffer(TimeSpan.FromMilliseconds(125)).FlattenBufferResult() .Transform(line => new LineProxy(line)) .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy.Number)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data) .Do(_ => AutoScroller.ScrollToEnd()) .Subscribe(a => logger.Info(a.Adds.ToString()), ex => logger.Error(ex, "Opps")); // monitor matching lines and start index // update local values so the virtual scroll panel can bind to them var matchedLinesMonitor = tailer.MatchedLinesCount .Subscribe(matched => MatchedLinesCount = matched); var firstIndexMonitor = tailer.Lines.Connect() .QueryWhenChanged(lines => { // use zero based index rather than line number return(lines.Count == 0 ? 0 : lines.Select(l => l.Number).Min() - 1); }).Subscribe(first => FirstRow = first - 1); _cleanup = new CompositeDisposable( tailer, lineCounter, loader, matchedLinesMonitor, firstIndexMonitor, Disposable.Create(() => _userScrollRequested.OnCompleted())); }
public ViewModel() { this.WhenAnyValue(x => x.Foo.Bar.Baz) .Subscribe(x => Console.WriteLine("Hallo " + x?.ToString())); Console.WriteLine("Example 1"); this.Foo.Bar.Baz = null; Console.WriteLine("Example 2a"); this.Foo.Bar = new BarClass(); Console.WriteLine("Example 2b"); this.Foo.Bar = new BarClass(); Console.WriteLine("Example 3"); this.Foo.Bar = new BarClass() { Baz = "Something" }; Console.WriteLine("Example 4"); this.Foo = new FooClass(); SourceList <String> sl = new SourceList <String>(); sl.Add("One"); sl.Add("Two"); sl.Add("Two"); sl.Add("Three"); sl.Connect() .Transform(x => x) .Sort(SortExpressionComparer <String> .Ascending(t => t)) .DistinctValues(x => x) .Bind(out ReadOnlyObservableCollection <String> sorted) .Subscribe(); Console.WriteLine("=== Raw List ==="); PrintList <String>(sl.Items); Console.WriteLine("=== Sorted ==="); PrintList <String>(sorted); Console.WriteLine("=== ==="); FooClass fo1 = new FooClass() { Bar = new BarClass("Hello ") }; FooClass fo2 = new FooClass() { Bar = new BarClass("World ") }; FooClass fo3 = new FooClass() { Bar = new BarClass("Out ") }; FooClass fo4 = new FooClass() { Bar = new BarClass("There ") }; FooClass fo5 = new FooClass() { Bar = new BarClass("!!!!!!") }; sl2.Add(fo1); sl2.Add(fo2); sl2.Add(fo3); sl2.Add(fo4); sl2.Connect() .AutoRefresh(x => x.Bar.Baz) .Transform(x => x.Bar.Baz, true) // .Sort(SortExpressionComparer<String>.Ascending(t => t)) // .DistinctValues(x => x) .Bind(out ReadOnlyObservableCollection <String> transformed) .Subscribe(x => { Console.WriteLine("CHANGE from Subscribe"); }); Console.WriteLine("=== Start ==="); ((INotifyCollectionChanged)transformed).CollectionChanged += new NotifyCollectionChangedEventHandler((s, e) => Console.WriteLine("CHANGE from Event Handler")); Console.WriteLine("sl2: "); PrintList <FooClass>(sl2.Items); Console.WriteLine("transformed: "); PrintList <String>(transformed); Console.WriteLine("=== Send to Space ==="); fo2.Bar.Baz = "Space"; Console.WriteLine("sl2: "); PrintList <FooClass>(sl2.Items); Console.WriteLine("transformed: "); PrintList <String>(transformed); Console.WriteLine("=== Add !!!! ==="); sl2.Add(fo5); Console.WriteLine("sl2: "); PrintList <FooClass>(sl2.Items); Console.WriteLine("transformed: "); PrintList <String>(transformed); Console.WriteLine("=== ==="); Console.WriteLine("Finish"); Console.ReadLine(); }
public InstallerVM(MainWindowVM mainWindowVM) { if (Path.GetDirectoryName(Assembly.GetEntryAssembly().Location.ToLower()) == KnownFolders.Downloads.Path.ToLower()) { MessageBox.Show( "Wabbajack is running inside your Downloads folder. This folder is often highly monitored by antivirus software and these can often " + "conflict with the operations Wabbajack needs to perform. Please move this executable outside of your Downloads folder and then restart the app.", "Cannot run inside Downloads", MessageBoxButton.OK, MessageBoxImage.Error); Environment.Exit(1); } MWVM = mainWindowVM; ModListLocation = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.On, PathType = FilePickerVM.PathTypeOptions.File, PromptTitle = "Select a modlist to install" }; // Swap to proper sub VM based on selected type _installer = this.WhenAny(x => x.TargetManager) // Delay so the initial VM swap comes in immediately, subVM comes right after .DelayInitial(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler) .Select <ModManager?, ISubInstallerVM>(type => { switch (type) { case ModManager.MO2: return(new MO2InstallerVM(this)); case ModManager.Vortex: return(new VortexInstallerVM(this)); default: return(null); } }) // Unload old VM .Pairwise() .Do(pair => { pair.Previous?.Unload(); }) .Select(p => p.Current) .ToProperty(this, nameof(Installer)); // Load settings MWVM.Settings.SaveSignal .Subscribe(_ => { MWVM.Settings.Installer.LastInstalledListLocation = ModListLocation.TargetPath; }) .DisposeWith(CompositeDisposable); _modList = this.WhenAny(x => x.ModListLocation.TargetPath) .ObserveOn(RxApp.TaskpoolScheduler) .Select(modListPath => { if (modListPath == null) { return(default(ModListVM)); } if (!File.Exists(modListPath)) { return(default(ModListVM)); } return(new ModListVM(modListPath)); }) .ObserveOnGuiThread() .StartWith(default(ModListVM)) .ToProperty(this, nameof(ModList)); _htmlReport = this.WhenAny(x => x.ModList) .Select(modList => modList?.ReportHTML) .ToProperty(this, nameof(HTMLReport)); _installing = this.WhenAny(x => x.Installer.ActiveInstallation) .Select(i => i != null) .ObserveOnGuiThread() .ToProperty(this, nameof(Installing)); _TargetManager = this.WhenAny(x => x.ModList) .Select(modList => modList?.ModManager) .ToProperty(this, nameof(TargetManager)); // Add additional error check on modlist ModListLocation.AdditionalError = this.WhenAny(x => x.ModList) .Select <ModListVM, IErrorResponse>(modList => { if (modList == null) { return(ErrorResponse.Fail("Modlist path resulted in a null object.")); } if (modList.Error != null) { return(ErrorResponse.Fail("Modlist is corrupt", modList.Error)); } return(ErrorResponse.Success); }); BackCommand = ReactiveCommand.Create( execute: () => { StartedInstallation = false; Completed = null; mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM; }, canExecute: this.WhenAny(x => x.Installing) .Select(x => !x)); _percentCompleted = this.WhenAny(x => x.Installer.ActiveInstallation) .StartWith(default(AInstaller)) .CombineLatest( this.WhenAny(x => x.Completed), (installer, completed) => { if (installer == null) { return(Observable.Return <float>(completed != null ? 1f : 0f)); } return(installer.PercentCompleted.StartWith(0f)); }) .Switch() .Debounce(TimeSpan.FromMilliseconds(25)) .ToProperty(this, nameof(PercentCompleted)); Slideshow = new SlideShow(this); // Set display items to modlist if configuring or complete, // or to the current slideshow data if installing _image = Observable.CombineLatest( this.WhenAny(x => x.ModList.Error), this.WhenAny(x => x.ModList) .Select(x => x?.ImageObservable ?? Observable.Empty <BitmapImage>()) .Switch() .StartWith(WabbajackLogo), this.WhenAny(x => x.Slideshow.Image) .StartWith(default(BitmapImage)), this.WhenAny(x => x.Installing), resultSelector: (err, modList, slideshow, installing) => { if (err != null) { return(WabbajackErrLogo); } var ret = installing ? slideshow : modList; return(ret ?? WabbajackLogo); }) .Select <BitmapImage, ImageSource>(x => x) .ToProperty(this, nameof(Image)); _titleText = Observable.CombineLatest( this.WhenAny(x => x.ModList.Name), this.WhenAny(x => x.Slideshow.TargetMod.ModName) .StartWith(default(string)), this.WhenAny(x => x.Installing), resultSelector: (modList, mod, installing) => installing ? mod : modList) .ToProperty(this, nameof(TitleText)); _authorText = Observable.CombineLatest( this.WhenAny(x => x.ModList.Author), this.WhenAny(x => x.Slideshow.TargetMod.ModAuthor) .StartWith(default(string)), this.WhenAny(x => x.Installing), resultSelector: (modList, mod, installing) => installing ? mod : modList) .ToProperty(this, nameof(AuthorText)); _description = Observable.CombineLatest( this.WhenAny(x => x.ModList.Description), this.WhenAny(x => x.Slideshow.TargetMod.ModDescription) .StartWith(default(string)), this.WhenAny(x => x.Installing), resultSelector: (modList, mod, installing) => installing ? mod : modList) .ToProperty(this, nameof(Description)); _modListName = Observable.CombineLatest( this.WhenAny(x => x.ModList.Error) .Select(x => x != null), this.WhenAny(x => x.ModList) .Select(x => x?.Name), resultSelector: (err, name) => { if (err) { return("Corrupted Modlist"); } return(name); }) .ToProperty(this, nameof(ModListName)); // Define commands ShowReportCommand = ReactiveCommand.Create(ShowReport); OpenReadmeCommand = ReactiveCommand.Create( execute: () => this.ModList?.OpenReadmeWindow(), canExecute: this.WhenAny(x => x.ModList) .Select(modList => !string.IsNullOrEmpty(modList?.Readme)) .ObserveOnGuiThread()); VisitWebsiteCommand = ReactiveCommand.Create( execute: () => Process.Start(ModList.Website), canExecute: this.WhenAny(x => x.ModList.Website) .Select(x => x?.StartsWith("https://") ?? false) .ObserveOnGuiThread()); _progressTitle = Observable.CombineLatest( this.WhenAny(x => x.Installing), this.WhenAny(x => x.StartedInstallation), resultSelector: (installing, started) => { if (!installing) { return("Configuring"); } return(started ? "Installing" : "Installed"); }) .ToProperty(this, nameof(ProgressTitle)); Dictionary <int, CPUDisplayVM> cpuDisplays = new Dictionary <int, CPUDisplayVM>(); // Compile progress updates and populate ObservableCollection this.WhenAny(x => x.Installer.ActiveInstallation) .SelectMany(c => c?.QueueStatus ?? Observable.Empty <CPUStatus>()) .ObserveOn(RxApp.TaskpoolScheduler) // Attach start times to incoming CPU items .Scan( new CPUDisplayVM(), (_, cpu) => { var ret = cpuDisplays.TryCreate(cpu.ID); ret.AbsorbStatus(cpu); return(ret); }) .ToObservableChangeSet(x => x.Status.ID) .Batch(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler) .EnsureUniqueChanges() .Filter(i => i.Status.IsWorking && i.Status.ID != WorkQueue.UnassignedCpuId) .ObserveOn(RxApp.MainThreadScheduler) .Sort(SortExpressionComparer <CPUDisplayVM> .Ascending(s => s.StartTime)) .Bind(StatusList) .Subscribe() .DisposeWith(CompositeDisposable); BeginCommand = ReactiveCommand.CreateFromTask( canExecute: this.WhenAny(x => x.Installer.CanInstall) .Switch(), execute: async() => { try { await this.Installer.Install(); Completed = ErrorResponse.Success; try { this.ModList?.OpenReadmeWindow(); } catch (Exception ex) { Utils.Error(ex); } } catch (Exception ex) { while (ex.InnerException != null) { ex = ex.InnerException; } Utils.Log(ex.StackTrace); Utils.Log(ex.ToString()); Utils.Log($"{ex.Message} - Can't continue"); Completed = ErrorResponse.Fail(ex); } }); // When sub installer begins an install, mark state variable BeginCommand.StartingExecution() .Subscribe(_ => { StartedInstallation = true; }) .DisposeWith(CompositeDisposable); // Listen for user interventions, and compile a dynamic list of all unhandled ones var activeInterventions = this.WhenAny(x => x.Installer.ActiveInstallation) .SelectMany(c => c?.LogMessages ?? Observable.Empty <IStatusMessage>()) .WhereCastable <IStatusMessage, IUserIntervention>() .ToObservableChangeSet() .AutoRefresh(i => i.Handled) .Filter(i => !i.Handled) .AsObservableList(); // Find the top intervention /w no CPU ID to be marked as "global" _ActiveGlobalUserIntervention = activeInterventions.Connect() .Filter(x => x.CpuID == WorkQueue.UnassignedCpuId) .QueryWhenChanged(query => query.FirstOrDefault()) .ObserveOnGuiThread() .ToProperty(this, nameof(ActiveGlobalUserIntervention)); CloseWhenCompleteCommand = ReactiveCommand.Create( canExecute: this.WhenAny(x => x.Completed) .Select(x => x != null), execute: () => { MWVM.ShutdownApplication(); }); GoToInstallCommand = ReactiveCommand.Create( canExecute: Observable.CombineLatest( this.WhenAny(x => x.Completed) .Select(x => x != null), this.WhenAny(x => x.Installer.SupportsAfterInstallNavigation), resultSelector: (complete, supports) => complete && supports), execute: () => { Installer.AfterInstallNavigation(); }); }
public static void Main(string[] args) { var FemaleSex = new Sex("Female", 0); var MaleSex = new Sex("Male", 0); var myList = new SourceList <Person>(); myList.Edit(people => { people.Add(new Person("Alex", 32, "Male")); people.Add(new Person("Sveta", 24, "Female")); people.Add(new Person("Yura", 63, "Male")); }); myList.Add(new Person("Luda", 56, "Female")); var people = myList .Connect() // .Filter(person => person.Age < 50) .Sort(SortExpressionComparer <Person> .Ascending(person => person.Age)) //.GroupOn(person => person.Sex) .Subscribe(changeSet => { foreach (var change in changeSet) { if (change.Type == ChangeType.Range) { foreach (var itemChange in change.Range) { if (change.Reason == ListChangeReason.AddRange) { if (itemChange.Sex == "Female") { FemaleSex.PeopleCount++; } else { MaleSex.PeopleCount++; } } } } else { if (change.Reason == ListChangeReason.Add) { if (change.Item.Current.Sex == "Female") { FemaleSex.PeopleCount++; } else { MaleSex.PeopleCount++; } } else if (change.Reason == ListChangeReason.Remove) { if (change.Item.Current.Sex == "Female") { FemaleSex.PeopleCount--; } else { MaleSex.PeopleCount--; } } } } }); // Updates myList.Add(new Person("Valera", 35, "Male")); myList.Add(new Person("Snejka", 5, "Female")); myList.Add(new Person("Diana", 23, "Female")); myList.Add(new Person("Tanya", 21, "Female")); myList.Remove(myList.Items.Where(person => person.Name == "Snejka").FirstOrDefault()); Console.WriteLine($"{FemaleSex.Description} = {FemaleSex.PeopleCount}"); Console.WriteLine($"{MaleSex.Description} = {MaleSex.PeopleCount}"); // foreach(var personGroup in people.Items) // { // Console.WriteLine($"{personGroup.GroupKey}:"); // foreach(var person in personGroup.List.Items) // Console.WriteLine($"\t{person.Name} - {person.Age}"); // } }
IObservable <Unit> SetupFilteringAnimals() { ReadOnlyObservableCollection <Animal> filteredAnimals; SourceList <Animal> animalList = Animal.CreateMeSomeAnimalsPlease(); IObservable <Func <Animal, bool> > dynamicFilter = // ReactiveUI connecting to the DepedencyProperty this.WhenAnyValue(x => x.tbFilterText.Text) // Debounce .Throttle(TimeSpan.FromMilliseconds(250)) .Select(CreatePredicate); IObservable <IComparer <Animal> > dynamicSort = this.WhenAnyValue(x => x.cbSortByName.IsChecked) .Select(x => x ?? false) .Select(isChecked => isChecked ? SortExpressionComparer <Animal> .Ascending(i => i.Name) : SortExpressionComparer <Animal> .Ascending(i => animalList.Items.IndexOf(i)) ); var returnValue = animalList .Connect() .Filter(dynamicFilter) // accepts any observable .Sort(dynamicSort) .ObserveOnDispatcher() // side effect .Bind(out filteredAnimals) .Publish(); returnValue.Connect(); // Create filtered source to watch for changes on var filteredAnimalsChanged = filteredAnimals .ToObservableChangeSet() .Publish() .RefCount(); var calculateAverage = // Watch for property Changed events filteredAnimalsChanged .WhenPropertyChanged(x => x.AnimalRating).ToUnit() // watch for list changed .Merge(filteredAnimalsChanged.ToUnit()) .Do(_ => UpdateAverage()) .ToUnit(); lvFilteredAnimals.ItemsSource = filteredAnimals; return(returnValue.ToUnit().Merge(calculateAverage)); Func <Animal, bool> CreatePredicate(string text) { if (text == null || text.Length < 3) { return(animal => true); } text = text.ToLower(); return(animal => animal.Name.ToLower().Contains(text) || animal.Type.ToLower().Contains(text) || animal.Family.ToString().ToLower().Contains(text)); } void UpdateAverage() { // There is a better way var filterBy = filteredAnimals.Where(x => x.AnimalRating > 0).ToArray(); if (!filterBy.Any()) { tbAverageRating.Text = "Unknown"; return; } tbAverageRating.Text = filterBy.Average(x => x.AnimalRating) .ToString(); } }
private IComparer <EntryModel> GetSorting(Func <EntryModel, IComparable> f) { return(SortExpressionComparer <EntryModel> .Ascending(f)); }
/// <summary> /// Creates a new <see cref="ElementsViewModel"/>. /// </summary> public ElementsViewModel() { this.NewElement = ReactiveCommand.CreateFromTask(this.CreateElementAsync); this.CreateAttackingMatchup = ReactiveCommand.CreateFromTask(this.CreateAttackingMatchupAsync); this.CreateDefendingMatchup = ReactiveCommand.CreateFromTask(this.CreateDefendingMatchupAsync); App.Metadata.WhenAnyValue(x => x.CurrentProject) .Subscribe(x => { if (x is null) { return; } SaveableObject.SaveableObjects.Connect() .WhenPropertyChanged(p => p.IsSaved) .Select(p => { return(SaveableObject.SaveableObjects.Items.All(y => { return !(y is Element || y is ElementMatchup) || y.IsSaved; })); }) .ToPropertyEx(this, x => x.AreElementsSaved); }); this.WhenAnyValue(x => x.AreElementsSaved) .Select(x => { return($"Elements{(x ? string.Empty : "*")}"); }) .ToPropertyEx(this, x => x.Header); App.Metadata.WhenAnyValue(x => x.CurrentProject) .Subscribe(x => { if (x is null) { return; } // Connect to Elements IObservable <ISortedChangeSet <Element, int> >?elements = App.Metadata.CurrentProject?.Elements.Connect() .Sort(SortExpressionComparer <Element> .Ascending(x => x.Name)); // Elements Binding elements.ObserveOn(RxApp.MainThreadScheduler).Bind(out this.elements).Subscribe(); // Connect to Element Matchups IObservable <ISortedChangeSet <ElementMatchup, int> >?elementMatchups = App.Metadata.CurrentProject?.ElementMatchups.Connect() .AutoRefresh(x => x.Multiplier) .AutoRefreshOnObservable(x => this.WhenAnyValue(x => x.SelectedElement)) .Sort(SortExpressionComparer <ElementMatchup> .Ascending(x => x.DefendingElement.Name)); // Element Matchups Binding elementMatchups.ObserveOn(RxApp.MainThreadScheduler) .Bind(out this.elementMatchups) .Subscribe(); // Attacking Matchups Binding elementMatchups.Filter(x => { return(x.AttackingElement == this.SelectedElement); }) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out this.attackingMatchups) .Subscribe(); // Defending Matchups Binding elementMatchups.Filter(x => { return(x.DefendingElement == this.SelectedElement); }) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out this.defendingMatchups) .Subscribe(); // Offensive Rating Binding elementMatchups.Select(x => this.GetOffensiveRating()) .BindTo(this, x => x.OffensiveRating); elements.Select(x => this.GetOffensiveRating()) .BindTo(this, x => x.OffensiveRating); // Defensive Rating Binding elementMatchups.Select(x => this.GetDefensiveRating()) .BindTo(this, x => x.DefensiveRating); elements.Select(x => this.GetDefensiveRating()) .BindTo(this, x => x.DefensiveRating); }); }
private ShellViewModel() { FilePath = new BehaviorSubject <string>(@"Test.mrpd"); this.WhenActivated(d => { TestCommand = ReactiveCommand.Create(() => { TestName = "Test"; }); (LoadFileCommand = ReactiveCommand.Create(LoadFile)).DisposeWith(d); (UpCommand = ReactiveCommand.Create(Up, this.WhenAnyValue(s => s.SelectedNodeIndex).Select(i => i > 0))).DisposeWith(d); (CreateNodeCommand = ReactiveCommand.Create(CreateNode)).DisposeWith(d); (_deleteNodeCommand = ReactiveCommand.Create <string>(DeleteNode)).DisposeWith(d); (_enterNodeCommand = ReactiveCommand.Create <string>(EnterNode)).DisposeWith(d); (_startRenameNodeCommand = ReactiveCommand.Create <string>(StartRenameNode)).DisposeWith(d); (_endRenameNodeCommand = ReactiveCommand.Create <(string, string)>(EndRenameNode)).DisposeWith(d); (_deleteDataCommand = ReactiveCommand.Create <string>(DeleteData)).DisposeWith(d); NodeNameList.Connect().ObserveOnDispatcher(DispatcherPriority.Background).Bind(out _nodeNames).Subscribe().DisposeWith(d); NodeItemViewModelCache.Connect().Sort(SortExpressionComparer <ItemViewModelBase> .Ascending(i => i.Name)).Concat(DataItemViewModelCache.Connect().Sort(SortExpressionComparer <ItemViewModelBase> .Ascending(i => i.Name))).Bind(out _itemViewModels).Subscribe().DisposeWith(d); this.WhenAnyValue(s => s.SelectedNodeIndex).Skip(1).Subscribe(SelectedNodeIndexChanged).DisposeWith(d); FilePath.Subscribe(FilePathChanged).DisposeWith(d); FilePath.Select(f => f != null).ToProperty(this, s => s.HasFile, out _hasFile).DisposeWith(d); (SaveCommand = ReactiveCommand.Create(async() => { await this.ShowProgressAsync("", "正在保存..."); })).DisposeWith(d); }); }
public MainWindowVM(RunMode mode, string source, MainWindow mainWindow) { this.Mode = mode; this.MainWindow = mainWindow; this._Installer = new Lazy <InstallerVM>(() => new InstallerVM(this)); this._Compiler = new Lazy <CompilerVM>(() => new CompilerVM(this, source)); // Set up logging _logSubj .ToObservableChangeSet() .Buffer(TimeSpan.FromMilliseconds(250)) .Where(l => l.Count > 0) .FlattenBufferResult() .Top(5000) .ObserveOn(RxApp.MainThreadScheduler) .Bind(this.Log) .Subscribe() .DisposeWith(this.CompositeDisposable); Utils.SetLoggerFn(s => _logSubj.OnNext(s)); Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress)); // Wire mode to drive the active pane. // Note: This is currently made into a derivative property driven by mode, // but it can be easily changed into a normal property that can be set from anywhere if needed this._ActivePane = this.WhenAny(x => x.Mode) .Select <RunMode, ViewModel>(m => { switch (m) { case RunMode.Compile: return(this._Compiler.Value); case RunMode.Install: return(this._Installer.Value); default: return(default); } }) .ToProperty(this, nameof(this.ActivePane)); this.WhenAny(x => x.ActivePane) .ObserveOn(RxApp.TaskpoolScheduler) .WhereCastable <ViewModel, InstallerVM>() .Subscribe(vm => vm.ModListPath = source) .DisposeWith(this.CompositeDisposable); // Initialize work queue WorkQueue.Init( report_function: (id, msg, progress) => this._statusSubject.OnNext(new CPUStatus() { ID = id, Msg = msg, Progress = progress }), report_queue_size: (max, current) => this.SetQueueSize(max, current)); // Compile progress updates and populate ObservableCollection this._statusSubject .ObserveOn(RxApp.TaskpoolScheduler) .ToObservableChangeSet(x => x.ID) .Batch(TimeSpan.FromMilliseconds(250)) .EnsureUniqueChanges() .ObserveOn(RxApp.MainThreadScheduler) .Sort(SortExpressionComparer <CPUStatus> .Ascending(s => s.ID), SortOptimisations.ComparesImmutableValuesOnly) .Bind(this.StatusList) .Subscribe() .DisposeWith(this.CompositeDisposable); }
public Indexer([NotNull] IObservable <FileSegmentCollection> fileSegments, int compression = 10, int tailSize = 1000000, int sizeOfFileAtWhichThereIsAbsolutelyNoPointInIndexing = 250000000, Encoding encoding = null, IScheduler scheduler = null) { if (fileSegments == null) { throw new ArgumentNullException(nameof(fileSegments)); } //TODO: When File segment has got smaller => roll-over [do something about it] scheduler = scheduler ?? Scheduler.Default; var shared = fileSegments.Replay(1).RefCount(); //1. Get information from segment info var infoSubscriber = shared.Select(segments => segments.Info) .Subscribe(info => { Info = info; if (Encoding == null || info.Name != Info.Name) { Encoding = encoding ?? info.GetEncoding(); } }); //2. create a resulting index object from the collection of index fragments Result = _indicies .Connect() .Sort(SortExpressionComparer <Index> .Ascending(si => si.Start)) .ToCollection() .Scan((IndexCollection)null, (previous, notification) => new IndexCollection(notification, previous, Info, Encoding)) .Replay(1).RefCount(); //3. Scan the tail so results can be returned quickly var tailScanner = shared.Select(segments => segments.Tail) .DistinctUntilChanged() .Scan((Index)null, (previous, current) => { if (previous == null) { var initial = Scan(current.Start, -1, 1); return(initial ?? new Index(0, 0, 0, 0, IndexType.Tail)); } var latest = Scan(previous.End, -1, 1); return(latest == null ? null : new Index(latest, previous)); }) .Where(tail => tail != null) .Replay(1).RefCount(); //4. estimate = var tailSubscriber = tailScanner.Subscribe(tail => { _indicies.Edit(innerList => { var existing = innerList.FirstOrDefault(si => si.Type == IndexType.Tail); if (existing != null) { innerList.Remove(existing); } innerList.Add(tail); }); }); //Scan the remainer of the file var headSubscriber = tailScanner.FirstAsync() .Subscribe(tail => { if (tail.Start == 0) { return; } //Need iterate one at a time through the var estimateLines = EstimateNumberOfLines(tail, Info); var estimate = new Index(0, tail.Start, compression, estimateLines, IndexType.Page); _indicies.Add(estimate); //keep it as an estimate for files over 250 meg [for now] if (tail.Start > sizeOfFileAtWhichThereIsAbsolutelyNoPointInIndexing) { return; } //todo: index first and last segment for large sized file scheduler.Schedule(() => { var actual = Scan(0, tail.Start, compression); _indicies.Edit(innerList => { innerList.Remove(estimate); innerList.Add(actual); }); }); }); _cleanUp = new CompositeDisposable(infoSubscriber, _indicies, tailSubscriber, tailSubscriber, headSubscriber); }
public void RebuildGrid() { Monik?.ApplicationVerbose("Matrix.RebuildGrid started"); MainGrid.Children.Clear(); if (Rows == null || Columns == null || Rows.Count == 0 || Columns.Count == 0) { Monik?.ApplicationVerbose("Matrix.RebuildGrid skip func"); return; } var columns = Columns.ToList(); int columnCount = Columns.Count; var rows = Rows.ToList(); int rowCount = Rows.Count; ////////////////// // 1. Fill columns ////////////////// MainGrid.ColumnDefinitions.Clear(); // rows header MainGrid.ColumnDefinitions.Add( new ColumnDefinition { Width = new GridLength(30, GridUnitType.Pixel) }); // columns for (int i = 0; i < columnCount; i++) { var it = columns[i]; Monik?.ApplicationVerbose($"Matrix.RebuildGrid add column {it.Id}::{it.Name}::{it.Order}"); var cd = new ColumnDefinition(); cd.DataContext = it; cd.Width = new GridLength(it.Size / 10.0, GridUnitType.Star); MainGrid.ColumnDefinitions.Add(cd); PropertyDescriptor pd = DependencyPropertyDescriptor.FromProperty(ColumnDefinition.WidthProperty, typeof(ColumnDefinition)); pd.AddValueChanged(cd, new EventHandler(ColumnWidthPropertyChanged)); ContentControl cc = new ContentControl(); cc.Content = it; cc.MouseMove += Head_MouseMove; cc.ContextMenu = HeadContextMenu; cc.ContentTemplate = (DataTemplate)this.Resources["DefaultHorizontalHeaderTemplate"]; MainGrid.Children.Add(cc); // Update number of Cards in Column CardsObservable .Filter(x => x.ColumnDeterminant == it.Id) .ToCollection() .Subscribe(x => it.CurNumberOfCards = x.Count()); // dont draw excess splitter if (i < columnCount - 1) { MainGrid.Children.Add(BuildVerticalSpliter(i, rowCount)); } Grid.SetColumn(cc, i + 1); Grid.SetRow(cc, 0); } /////////////// // 2. Fill rows /////////////// MainGrid.RowDefinitions.Clear(); // columns header MainGrid.RowDefinitions.Add( new RowDefinition { Height = new GridLength(30, GridUnitType.Pixel) }); // rows VerticalHeaders.Clear(); for (int i = 0; i < rowCount; i++) { var it = rows[i]; Monik?.ApplicationVerbose($"Matrix.RebuildGrid add row {it.Id}::{it.Name}::{it.Order}"); var rd = new RowDefinition(); rd.DataContext = it; rd.Height = new GridLength(it.Size / 10.0, GridUnitType.Star); MainGrid.RowDefinitions.Add(rd); PropertyDescriptor pd = DependencyPropertyDescriptor.FromProperty(RowDefinition.HeightProperty, typeof(RowDefinition)); pd.AddValueChanged(rd, new EventHandler(RowWidthPropertyChanged)); ContentControl cc = new ContentControl(); VerticalHeaders.Add(cc); cc.Content = it; cc.MouseMove += Head_MouseMove; cc.ContextMenu = HeadContextMenu; cc.ContentTemplate = (DataTemplate)this.Resources["DefaulVerticalHeaderTemplate"]; MainGrid.Children.Add(cc); // Update number of Cards in Row CardsObservable .Filter(x => x.RowDeterminant == it.Id) .ToCollection() .Subscribe(x => it.CurNumberOfCards = x.Count()); // dont draw excess splitter if (i < rowCount - 1) { MainGrid.Children.Add(BuildHorizontalSpliter(i, columnCount)); } Grid.SetColumn(cc, 0); Grid.SetRow(cc, i + 1); Canvas.SetZIndex(cc, System.Int32.MaxValue); } //////////////////////// // 3. Fill Intersections //////////////////////// for (int i = 0; i < Columns.Count; i++) { for (int j = 0; j < Rows.Count; j++) { int colDet = columns[i].Id; int rowDet = rows[j].Id; CardsObservable .Filter(x => x.ColumnDeterminant == colDet && x.RowDeterminant == rowDet) .Sort(SortExpressionComparer <ICard> .Ascending(c => c.Order)) .ObserveOnDispatcher() .Bind(out ReadOnlyObservableCollection <ICard> intersectionCards) .Subscribe(); Intersection cell = new Intersection(this) { DataContext = this, ColumnDeterminant = colDet, RowDeterminant = rowDet, SelfCards = intersectionCards }; MainGrid.Children.Add(cell); Grid.SetColumn(cell, i + 1); Grid.SetColumnSpan(cell, 1); Grid.SetRow(cell, j + 1); Grid.SetRowSpan(cell, 1); } } SwimLanePropertyChanged(this, null); Monik?.ApplicationVerbose("Matrix.RebuildGrid finished"); }
//IEnumerable<MenuItemViewModel> GetMenuItems() //{ // //yield return new MenuItemViewModel(nameof(AppResources.CommunityFix_EnableScriptService)); // yield return new MenuItemViewModel(nameof(AppResources.ScriptStore)) // { // IconKey = "JavaScriptDrawing", // Command = ScriptStoreCommand // }; // yield return new MenuItemViewModel(nameof(AppResources.Script_AllEnable)) // { // IconKey = "JavaScriptDrawing", // Command = AllEnableScriptCommand, // }; // yield return new MenuItemViewModel(); // if (OnlySteamBrowser != null) yield return OnlySteamBrowser; //} public ProxyScriptManagePageViewModel() { IconKey = nameof(ProxyScriptManagePageViewModel); if (!IApplication.IsDesktopPlatform) { return; } ScriptStoreCommand = ReactiveCommand.Create(OpenScriptStoreWindow); AllEnableScriptCommand = ReactiveCommand.Create(AllEnableScript); AddNewScriptButton_Click = ReactiveCommand.CreateFromTask(async() => { FilePicker2.FilePickerFileType?fileTypes; if (IApplication.IsDesktopPlatform) { fileTypes = new ValueTuple <string, string[]>[] { ("JavaScript Files", new[] { FileEx.JS, }), ("Text Files", new[] { FileEx.TXT, }), //("All Files", new[] { "*", }), }; } else if (OperatingSystem2.IsAndroid) { fileTypes = new[] { MediaTypeNames.TXT, MediaTypeNames.JS }; } else { fileTypes = null; } await FilePicker2.PickAsync(ProxyService.Current.AddNewScript, fileTypes); }); //EnableScriptAutoUpdateCommand = ReactiveCommand.Create(() => //{ // ScriptAutoUpdate?.CheckmarkChange(ProxySettings.IsAutoCheckScriptUpdate.Value = !ProxySettings.IsAutoCheckScriptUpdate.Value); //}); //OnlySteamBrowserCommand = ReactiveCommand.Create(() => //{ // OnlySteamBrowser?.CheckmarkChange(ProxySettings.IsOnlyWorkSteamBrowser.Value = !ProxySettings.IsOnlyWorkSteamBrowser.Value); //}); //ScriptAutoUpdate = new MenuItemViewModel(nameof(AppResources.Script_AutoUpdate)) //{ // Command = EnableScriptAutoUpdateCommand, //}; //OnlySteamBrowser = new(nameof(AppResources.CommunityFix_OnlySteamBrowser)) //{ // Command = OnlySteamBrowserCommand, //}; //MenuItems = new ObservableCollection<MenuItemViewModel>(GetMenuItems()); //ScriptAutoUpdate?.CheckmarkChange(ProxySettings.IsAutoCheckScriptUpdate.Value); //OnlySteamBrowser?.CheckmarkChange(ProxySettings.IsOnlyWorkSteamBrowser.Value); var scriptFilter = this.WhenAnyValue(x => x.SearchText).Select(ScriptFilter); ProxyService.Current.ProxyScripts .Connect() .Filter(scriptFilter) .ObserveOn(RxApp.MainThreadScheduler) .Sort(SortExpressionComparer <ScriptDTO> .Ascending(x => x.Order).ThenBy(x => x.Name)) .Bind(out _ProxyScripts) .Subscribe(_ => this.RaisePropertyChanged(nameof(IsProxyScriptsEmpty))); }
public void DoesNotThrow2() { var cache = new SourceCache <Data, int>(d => d.Id); var disposable = cache.Connect().Sort(new BehaviorSubject <IComparer <Data> >(SortExpressionComparer <Data> .Ascending(d => d.Id))).Subscribe(); disposable.Dispose(); }
protected override void Initialize() { base.Initialize(); ForceCreateUserRolesFilterCommand = ReactiveCommand .Create <string>(x => ForceCreateUserRolesFilter = x) .DisposeWith(Disposables); LockUsersCommand = ReactiveCommand .CreateFromTask <IList>(LockUsers, this.WhenAny( x => x.SelectedItemsIds, x => x.Value != null && x.Value.Count > 0)) .DisposeWith(Disposables); RolesFilterCommand = ReactiveCommand .Create <string>(filter => RolesFilter = filter) .DisposeWith(Disposables); RoleCheckedCommand = ReactiveCommand .Create <SelectedUserRoleViewModel>(RoleChecked) .DisposeWith(Disposables); var rolesChangedObservable = this.WhenAnyValue(x => x.IsChangedRoles); ApplyRolesCommand = ReactiveCommand .CreateFromTask(ApplyRoles, rolesChangedObservable) .DisposeWith(Disposables); ResetRolesCommand = ReactiveCommand .CreateFromTask(ResetRoles, rolesChangedObservable) .DisposeWith(Disposables); ForceChangePasswordCommand = ReactiveCommand .CreateFromTask(ForceResetPassword, this.WhenHaveOnlyOneSelectedItem()) .DisposeWith(Disposables); ForceChangePhoneCommand = ReactiveCommand .CreateFromTask(ForceChangePhone) .DisposeWith(Disposables); ForceChangeEmailCommand = ReactiveCommand .CreateFromTask(ForceChangeEmail) .DisposeWith(Disposables); // Permissions SubscribeToPermissions( _domain0.Model.UserPermissions, (permissionId, items) => items .Where(x => !x.RoleId.HasValue && x.Id.Value == permissionId) .Select(x => x.UserId)) .DisposeWith(Disposables); // Roles var dynamicForceCreateUserRolesFilter = this .WhenAnyValue(x => x.ForceCreateUserRolesFilter) .Select(Filters.CreateRolesPredicate); _domain0.Model.Roles.Connect() .Filter(dynamicForceCreateUserRolesFilter) .Transform(x => new ForceCreateUserRoleViewModel { Role = x }) .Sort(SortExpressionComparer <ForceCreateUserRoleViewModel> .Ascending(x => x.Role.Id)) .ObserveOnDispatcher() .Bind(out _forceCreateUserRoles) .Subscribe() .DisposeWith(Disposables); var dynamicRolesFilter = this .WhenAnyValue(x => x.RolesFilter) .Select(Filters.CreateRolesPredicate); var sourceUserRoles = _domain0.Model.UserRoles .Connect() .ToCollection(); var sourceRoles = _domain0.Model.Roles .Connect() .Filter(dynamicRolesFilter) .ToCollection(); var sourceSelected = this .WhenAnyValue(x => x.SelectedItemsIds); Observable.CombineLatest( sourceUserRoles, sourceRoles, sourceSelected, (userRoles, roles, selectedIds) => selectedIds.Count > 0 ? new { userRoles, roles, selectedIds } : null) .Throttle(TimeSpan.FromSeconds(.1)) .Synchronize() .Select(o => o?.roles .Select(r => { var roleId = r.Id.Value; var userIds = o.userRoles .Where(x => x.Id.Value == roleId) .Select(x => x.UserId) .Distinct(); var groupSelectedIds = o.selectedIds .Intersect(userIds) .ToList(); var count = groupSelectedIds.Count; var total = o.selectedIds.Count; return(new SelectedUserRoleViewModel(count, total) { Item = r, ParentIds = groupSelectedIds }); }) .OrderByDescending(x => x.Count) .ThenBy(x => x.Item.Name) .ThenBy(x => x.Id) .ToList()) .ObserveOn(RxApp.MainThreadScheduler) .Subscribe(x => { SelectedUserRoles = x; IsChangedRoles = false; }) .DisposeWith(Disposables); // Environments _domain0.Model.Environments.Connect() .Sort(SortExpressionComparer <Environment> .Ascending(x => x.Id)) .ObserveOnDispatcher() .Bind(out _environments) .Subscribe() .DisposeWith(Disposables); // Locales var dynamicLocaleFilter = this .WhenAnyValue(x => x.Environment) .Select(Filters.CreateEnvironmentPredicate); _domain0.Model.MessageTemplates.Connect() .Filter(dynamicLocaleFilter) .Group(x => x.Locale) .Transform(x => x.Key) .Sort(SortExpressionComparer <string> .Ascending(x => x)) .ObserveOnDispatcher() .Bind(out _locales) .Subscribe() .DisposeWith(Disposables); }
public InlineViewer([NotNull] InlineViewerArgs args, [NotNull] IClipboardHandler clipboardHandler, [NotNull] ISchedulerProvider schedulerProvider, [NotNull] ISelectionMonitor selectionMonitor) { if (args == null) { throw new ArgumentNullException(nameof(args)); } if (clipboardHandler == null) { throw new ArgumentNullException(nameof(clipboardHandler)); } if (schedulerProvider == null) { throw new ArgumentNullException(nameof(schedulerProvider)); } if (selectionMonitor == null) { throw new ArgumentNullException(nameof(selectionMonitor)); } SelectionMonitor = selectionMonitor; CopyToClipboardCommand = new Command(() => clipboardHandler.WriteToClipboard(selectionMonitor.GetSelectedText())); _isSettingScrollPosition = false; var lineProvider = args.LineProvider; var selectedChanged = args.SelectedChanged; var pageSize = this.WhenValueChanged(vm => vm.PageSize); var scrollSelected = selectedChanged.Where(proxy => proxy != null) .CombineLatest(lineProvider, pageSize, (proxy, lp, pge) => new ScrollRequest(pge, proxy.Start)); var scrollUser = _userScrollRequested .Where(x => !_isSettingScrollPosition) .Select(request => new ScrollRequest(ScrollReason.User, request.PageSize, request.FirstIndex)); var scroller = scrollSelected.Merge(scrollUser) .ObserveOn(schedulerProvider.Background) .DistinctUntilChanged(); var lineScroller = new LineScroller(lineProvider, scroller); Count = lineProvider.Select(lp => lp.Count).ForBinding(); //load lines into observable collection var loader = lineScroller.Lines.Connect() .Transform(args.LineProxyFactory.Create) .Sort(SortExpressionComparer <LineProxy> .Ascending(proxy => proxy)) .ObserveOn(schedulerProvider.MainThread) .Bind(out _data) .DisposeMany() .Subscribe(); // track first visible index[required to set scroll extent] var firstIndexMonitor = lineScroller.Lines.Connect() .Buffer(TimeSpan.FromMilliseconds(250)).FlattenBufferResult() .ToCollection() .Select(lines => lines.Count == 0 ? 0 : lines.Select(l => l.Index).Max() - lines.Count + 1) .ObserveOn(schedulerProvider.MainThread) .Subscribe(first => { try { _isSettingScrollPosition = true; FirstIndex = first; } finally { _isSettingScrollPosition = false; } }); _cleanUp = new CompositeDisposable(lineScroller, loader, Count, firstIndexMonitor, SelectionMonitor, Disposable.Create(() => { _userScrollRequested.OnCompleted(); })); }
public CompilerVM(MainWindowVM mainWindowVM) { MWVM = mainWindowVM; OutputLocation = new FilePickerVM() { ExistCheckOption = FilePickerVM.CheckOptions.IfPathNotEmpty, PathType = FilePickerVM.PathTypeOptions.Folder, PromptTitle = "Select the folder to place the resulting modlist.wabbajack file", }; // Load settings CompilerSettings settings = MWVM.Settings.Compiler; SelectedCompilerType = settings.LastCompiledModManager; OutputLocation.TargetPath = settings.OutputLocation; MWVM.Settings.SaveSignal .Subscribe(_ => { settings.LastCompiledModManager = SelectedCompilerType; settings.OutputLocation = OutputLocation.TargetPath; }) .DisposeWith(CompositeDisposable); // Swap to proper sub VM based on selected type _compiler = this.WhenAny(x => x.SelectedCompilerType) // Delay so the initial VM swap comes in immediately, subVM comes right after .DelayInitial(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler) .Select <ModManager, ISubCompilerVM>(type => { switch (type) { case ModManager.MO2: return(new MO2CompilerVM(this)); case ModManager.Vortex: return(new VortexCompilerVM(this)); default: return(null); } }) // Unload old VM .Pairwise() .Do(pair => { pair.Previous?.Unload(); }) .Select(p => p.Current) .ToProperty(this, nameof(Compiler)); // Let sub VM determine what settings we're displaying and when _currentModlistSettings = this.WhenAny(x => x.Compiler.ModlistSettings) .ToProperty(this, nameof(CurrentModlistSettings)); _image = this.WhenAny(x => x.CurrentModlistSettings.ImagePath.TargetPath) // Throttle so that it only loads image after any sets of swaps have completed .Throttle(TimeSpan.FromMilliseconds(50), RxApp.MainThreadScheduler) .DistinctUntilChanged() .Select(path => { if (string.IsNullOrWhiteSpace(path)) { return(UIUtils.BitmapImageFromResource("Resources/Wabba_Mouth_No_Text.png")); } if (UIUtils.TryGetBitmapImageFromFile(path, out var image)) { return(image); } return(null); }) .ToProperty(this, nameof(Image)); _compiling = this.WhenAny(x => x.Compiler.ActiveCompilation) .Select(compilation => compilation != null) .ObserveOnGuiThread() .ToProperty(this, nameof(Compiling)); BackCommand = ReactiveCommand.Create( execute: () => { mainWindowVM.ActivePane = mainWindowVM.ModeSelectionVM; StartedCompilation = false; Completed = null; }, canExecute: this.WhenAny(x => x.Compiling) .Select(x => !x)); // Compile progress updates and populate ObservableCollection Dictionary <int, CPUDisplayVM> cpuDisplays = new Dictionary <int, CPUDisplayVM>(); this.WhenAny(x => x.Compiler.ActiveCompilation) .SelectMany(c => c?.QueueStatus ?? Observable.Empty <CPUStatus>()) .ObserveOn(RxApp.TaskpoolScheduler) // Attach start times to incoming CPU items .Scan( new CPUDisplayVM(), (_, cpu) => { var ret = cpuDisplays.TryCreate(cpu.ID); ret.AbsorbStatus(cpu); return(ret); }) .ToObservableChangeSet(x => x.Status.ID) .Batch(TimeSpan.FromMilliseconds(250), RxApp.TaskpoolScheduler) .EnsureUniqueChanges() .Filter(i => i.Status.IsWorking && i.Status.ID != WorkQueue.UnassignedCpuId) .ObserveOn(RxApp.MainThreadScheduler) .Sort(SortExpressionComparer <CPUDisplayVM> .Ascending(s => s.StartTime)) .Bind(StatusList) .Subscribe() .DisposeWith(CompositeDisposable); _percentCompleted = this.WhenAny(x => x.Compiler.ActiveCompilation) .StartWith(default(ACompiler)) .CombineLatest( this.WhenAny(x => x.Completed), (compiler, completed) => { if (compiler == null) { return(Observable.Return <float>(completed != null ? 1f : 0f)); } return(compiler.PercentCompleted.StartWith(0)); }) .Switch() .Debounce(TimeSpan.FromMilliseconds(25)) .ToProperty(this, nameof(PercentCompleted)); BeginCommand = ReactiveCommand.CreateFromTask( canExecute: this.WhenAny(x => x.Compiler.CanCompile) .Switch(), execute: async() => { try { await this.Compiler.Compile(); Completed = ErrorResponse.Success; } catch (Exception ex) { Completed = ErrorResponse.Fail(ex); while (ex.InnerException != null) { ex = ex.InnerException; } Utils.Error(ex, $"Compiler error"); } }); // When sub compiler begins a compile, mark state variable BeginCommand.StartingExecution() .Subscribe(_ => { StartedCompilation = true; }) .DisposeWith(CompositeDisposable); // Listen for user interventions, and compile a dynamic list of all unhandled ones var activeInterventions = this.WhenAny(x => x.Compiler.ActiveCompilation) .SelectMany(c => c?.LogMessages ?? Observable.Empty <IStatusMessage>()) .WhereCastable <IStatusMessage, IUserIntervention>() .ToObservableChangeSet() .AutoRefresh(i => i.Handled) .Filter(i => !i.Handled) .AsObservableList(); // Find the top intervention /w no CPU ID to be marked as "global" _ActiveGlobalUserIntervention = activeInterventions.Connect() .Filter(x => x.CpuID == WorkQueue.UnassignedCpuId) .QueryWhenChanged(query => query.FirstOrDefault()) .ObserveOnGuiThread() .ToProperty(this, nameof(ActiveGlobalUserIntervention)); CloseWhenCompleteCommand = ReactiveCommand.Create( canExecute: this.WhenAny(x => x.Completed) .Select(x => x != null), execute: () => { MWVM.ShutdownApplication(); }); GoToModlistCommand = ReactiveCommand.Create( canExecute: this.WhenAny(x => x.Completed) .Select(x => x != null), execute: () => { if (string.IsNullOrWhiteSpace(OutputLocation.TargetPath)) { Process.Start("explorer.exe", Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)); } else { Process.Start("explorer.exe", OutputLocation.TargetPath); } }); }