public DatabaseModel(string name, DocumentStore documentStore) { this.name = name; this.documentStore = documentStore; Tasks = new BindableCollection<TaskModel>(x => x.Name) { new ImportTask(), new ExportTask(), new StartBackupTask(), new IndexingTask(), new SampleDataTask() }; SelectedTask = new Observable<TaskModel> { Value = Tasks.FirstOrDefault() }; Statistics = new Observable<DatabaseStatistics>(); Status = new Observable<string> { Value = "Offline" }; asyncDatabaseCommands = name.Equals(Constants.SystemDatabase, StringComparison.OrdinalIgnoreCase) ? documentStore.AsyncDatabaseCommands.ForDefaultDatabase() : documentStore.AsyncDatabaseCommands.ForDatabase(name); DocumentChanges.Select(c => Unit.Default).Merge(IndexChanges.Select(c => Unit.Default)) .SampleResponsive(TimeSpan.FromSeconds(2)) .Subscribe(_ => RefreshStatistics(), exception => ApplicationModel.Current.Server.Value.IsConnected.Value = false); RefreshStatistics(); }
public override IObservable <CharacteristicResult> WhenNotificationReceived() { this.AssertNotify(); this.notifyOb = this.notifyOb ?? Observable.Create <CharacteristicResult>(ob => { var handler = new EventHandler <GattCharacteristicEventArgs>((sender, args) => { if (this.NativeEquals(args)) { if (!args.IsSuccessful) { ob.OnError(new ArgumentException("Error subscribing to " + args.Characteristic.Uuid)); } else { this.Value = args.Characteristic.GetValue(); var result = new CharacteristicResult(this, CharacteristicEvent.Notification, this.Value); ob.OnNext(result); } } }); this.context.Callbacks.CharacteristicChanged += handler; return(() => this.context.Callbacks.CharacteristicChanged -= handler); }) .Publish() .RefCount(); return(this.notifyOb); }
private static DispatchItem CreateFromAdapterView() { // AdapterView is more complicated because there are two events - one for select and one for deselect // respond to both const string propName = "SelectedItem"; return(new DispatchItem { Type = typeof(AdapterView), Property = propName, Func = (x, ex) => { var adapterView = (AdapterView)x; var itemSelected = Observable.FromEvent <EventHandler <AdapterView.ItemSelectedEventArgs>, ObservedChange <object, object> >( eventHandler => { void Handler(object sender, AdapterView.ItemSelectedEventArgs e) => eventHandler(new ObservedChange <object, object>(adapterView, ex)); return Handler; }, h => adapterView.ItemSelected += h, h => adapterView.ItemSelected -= h); var nothingSelected = Observable.FromEvent <EventHandler <AdapterView.NothingSelectedEventArgs>, ObservedChange <object, object> >( eventHandler => { void Handler(object sender, AdapterView.NothingSelectedEventArgs e) => eventHandler(new ObservedChange <object, object>(adapterView, ex)); return Handler; }, h => adapterView.NothingSelected += h, h => adapterView.NothingSelected -= h); return Observable.Merge(itemSelected, nothingSelected); } });
public override IObservable <CharacteristicResult> Read() { this.AssertRead(); return(Observable.Create <CharacteristicResult>(ob => { var handler = new EventHandler <GattCharacteristicEventArgs>((sender, args) => { if (args.Characteristic.Equals(this.native)) { if (!args.IsSuccessful) { ob.OnError(new ArgumentException($"Failed to read characteristic - {args.Status}")); } else { this.Value = args.Characteristic.GetValue(); var result = new CharacteristicResult(this, CharacteristicEvent.Read, this.Value); ob.Respond(result); this.ReadSubject.OnNext(result); } } }); this.context.Callbacks.CharacteristicRead += handler; this.context.Gatt.ReadCharacteristic(this.native); return () => this.context.Callbacks.CharacteristicRead -= handler; })); }
public override IObservable <CharacteristicGattResult> WriteWithoutResponse(byte[] value) => this.context.Invoke(Observable.Create <CharacteristicGattResult>(ob => { this.AssertWrite(false); this.context.InvokeOnMainThread(() => { try { this.native.WriteType = GattWriteType.NoResponse; if (!this.native.SetValue(value)) { throw new BleException("Failed to write characteristic value"); } if (!this.context.Gatt.WriteCharacteristic(this.native)) { throw new BleException("Failed to write to characteristic"); } ob.Respond(new CharacteristicGattResult(this, value)); } catch (Exception ex) { throw new BleException("Error during charactersitic write", ex); } }); return(Disposable.Empty); }));
public override IObservable <CharacteristicGattResult> EnableNotifications(bool useIndicationsIfAvailable) => this.context.Invoke(Observable.FromAsync(async ct => { var descriptor = this.native.GetDescriptor(NotifyDescriptorId); if (descriptor == null) { throw new BleException("Characteristic Client Configuration Descriptor not found"); } var wrap = new GattDescriptor(this, this.context, descriptor); if (!this.context.Gatt.SetCharacteristicNotification(this.native, true)) { throw new BleException("Failed to set characteristic notification value"); } await this.context.OpPause(ct).ConfigureAwait(false); var bytes = useIndicationsIfAvailable && this.CanIndicate() ? BluetoothGattDescriptor.EnableIndicationValue.ToArray() : BluetoothGattDescriptor.EnableNotificationValue.ToArray(); await wrap .WriteInternal(bytes) .ToTask(ct) .ConfigureAwait(false); this.IsNotifying = true; return(new CharacteristicGattResult(this, null)); }));
public override IObservable <CharacteristicGattResult> Read() => this.context.Invoke(Observable.Create <CharacteristicGattResult>(ob => { this.AssertRead(); var sub = this.context .Callbacks .CharacteristicRead .Where(this.NativeEquals) .Subscribe(args => { if (args.IsSuccessful) { ob.Respond(new CharacteristicGattResult(this, args.Characteristic.GetValue())); } else { ob.OnError(new BleException($"Failed to read characteristic - {args.Status}")); } }); this.context.InvokeOnMainThread(() => { if (!this.context.Gatt.ReadCharacteristic(this.native)) { ob.OnError(new BleException("Failed to read characteristic")); } }); return(sub); }));
public override IObservable <CharacteristicGattResult> WhenNotificationReceived() { this.AssertNotify(); this.notifyOb = this.notifyOb ?? Observable.Create <CharacteristicGattResult>(ob => this.context .Callbacks .CharacteristicChanged .Where(this.NativeEquals) .Subscribe(args => { if (args.IsSuccessful) { ob.OnNext(new CharacteristicGattResult(this, args.Characteristic.GetValue())); } else { ob.OnError(new BleException($"Notification error - {args.Status}")); } }) ) .Publish() .RefCount(); return(this.notifyOb); }
public CollectionsModel() { ModelUrl = "/collections"; ApplicationModel.Current.Server.Value.RawUrl = null; Collections = new BindableCollection<CollectionModel>(model => model.Name); SelectedCollection = new Observable<CollectionModel>(); DocumentsForSelectedCollection.SetChangesObservable(d => d.IndexChanges .Where(n =>n.Name.Equals(CollectionsIndex,StringComparison.InvariantCulture)) .Select(m => Unit.Default)); DocumentsForSelectedCollection.DocumentNavigatorFactory = (id, index) => DocumentNavigator.Create(id, index, CollectionsIndex, new IndexQuery() {Query = "Tag:" + GetSelectedCollectionName()}); SelectedCollection.PropertyChanged += (sender, args) => { PutCollectionNameInTheUrl(); CollectionSource.CollectionName = GetSelectedCollectionName(); DocumentsForSelectedCollection.Context = "Collection/" + GetSelectedCollectionName(); }; SortedCollectionsList = new CollectionViewSource() { Source = Collections, SortDescriptions = { new SortDescription("Count", ListSortDirection.Descending) } }; }
public override IObservable <ReadRequest> WhenReadReceived() { return(Observable.Create <ReadRequest>(ob => { var handler = new EventHandler <CharacteristicReadEventArgs>((sender, args) => { if (!args.Characteristic.Equals(this.Native)) { return; } var device = new Device(args.Device); var request = new ReadRequest(device, args.Offset); ob.OnNext(request); lock (this.context.ServerReadWriteLock) { this.context.Server.SendResponse( args.Device, args.RequestId, request.Status.ToNative(), args.Offset, request.Value ); } }); this.context.Callbacks.CharacteristicRead += handler; return () => this.context.Callbacks.CharacteristicRead -= handler; })); }
public override IObservable <CharacteristicBroadcast> BroadcastObserve(byte[] value, params IDevice[] devices) { return(Observable.Create <CharacteristicBroadcast>(ob => { var cancel = false; this.Native.SetValue(value); if (devices == null || devices.Length == 0) { devices = this.subscribers.Values.ToArray(); } var indicate = this.Properties.HasFlag(CharacteristicProperties.Indicate); foreach (var x in devices.OfType <Device>()) { if (!cancel) { lock (this.context.ServerReadWriteLock) { if (!cancel) { var result = this.context.Server.NotifyCharacteristicChanged(x.Native, this.Native, indicate); ob.OnNext(new CharacteristicBroadcast(x, this, value, indicate, result)); } } } } ob.OnCompleted(); return () => cancel = true; })); }
// this should not be placed in a lock - let it fall to the descriptor public override IObservable <object> DisableNotifications() => Observable.FromAsync <object>(async ct => { var descriptor = this.native.GetDescriptor(NotifyDescriptorId); if (descriptor == null) { throw new ArgumentException("Characteristic Client Configuration Descriptor not found"); } var wrap = new GattDescriptor(this, this.context, descriptor); var success = this.context .Gatt .SetCharacteristicNotification(this.native, false); if (CrossBleAdapter.AndroidOperationPause != null) { await Task.Delay(CrossBleAdapter.AndroidOperationPause.Value, ct); } if (success) { await wrap.Write(BluetoothGattDescriptor.DisableNotificationValue.ToArray()); this.IsNotifying = false; } return(null); });
public override IObservable <CharacteristicResult> WhenNotificationReceived() { this.AssertNotify(); this.notifyOb = this.notifyOb ?? Observable.Create <CharacteristicResult>(ob => this.context .Callbacks .CharacteristicChanged .Where(this.NativeEquals) .Subscribe(args => { if (!args.IsSuccessful) { ob.OnError(new ArgumentException("Error subscribing to " + args.Characteristic.Uuid)); } else { this.Value = args.Characteristic.GetValue(); var result = new CharacteristicResult(this, CharacteristicEvent.Notification, this.Value); ob.OnNext(result); } }) ) .Publish() .RefCount(); return(this.notifyOb); }
public FilesPageModel() { filesSource = new FileSystemCollectionSource(); Files = new VirtualCollection<FileSystemModel>(filesSource, DefaultPageSize, DefaultCacheSize); SelectedFile = new Observable<VirtualItem<FileSystemModel>>(); CurrentFolder = new Observable<string>() { Value = "/"}; CurrentFolder.PropertyChanged += delegate { filesSource.CurrentFolder = CurrentFolder.Value; UpdateBreadCrumbs(); ApplicationModel.Current.Client.Notifications.FolderChanges( CurrentFolder.Value) .TakeUntil(Unloaded.Amb(CurrentFolder.ObserveChanged().Select(_ => Unit.Default))) .SampleResponsive(TimeSpan.FromSeconds(1)) .ObserveOn(DispatcherScheduler.Instance) .Subscribe(_ => Files.Refresh(RefreshMode.PermitStaleDataWhilstRefreshing)); }; SearchPattern = new Observable<string>() { Value=""}; SearchPattern.ObserveChanged().Throttle(TimeSpan.FromSeconds(1)).Where(SearchPatternIsValid).Subscribe(value => filesSource.SearchPattern = value); SelectedItems = new ItemSelection<VirtualItem<FileSystemModel>>(); IsSearchVisible = new Observable<bool>(); BreadcrumbTrail = new ObservableCollection<DirectoryModel>(); }
public DatabaseModel(string name, DocumentStore documentStore) { this.name = name; this.documentStore = documentStore; Statistics = new Observable<DatabaseStatistics>(); Status = new Observable<string> { Value = "Offline" }; OnPropertyChanged(() => StatusImage); asyncDatabaseCommands = name.Equals(Constants.SystemDatabase, StringComparison.OrdinalIgnoreCase) ? documentStore.AsyncDatabaseCommands.ForSystemDatabase() : documentStore.AsyncDatabaseCommands.ForDatabase(name); DocumentChanges.Select(c => Unit.Default).Merge(IndexChanges.Select(c => Unit.Default)) .SampleResponsive(TimeSpan.FromSeconds(2)) .Subscribe(_ => RefreshStatistics()); databaseChanges.ConnectionStatusChanged += (sender, args) => { ApplicationModel.Current.Server.Value.SetConnected(((IDatabaseChanges)sender).Connected); UpdateStatus(); }; RefreshStatistics(); }
public override IObservable <WriteRequest> WhenWriteReceived() => Observable.Create <WriteRequest>(ob => { var handler = new EventHandler <CharacteristicWriteEventArgs>((sender, args) => { if (!args.Characteristic.Equals(this.Native)) { return; } var device = new Device(args.Device); var request = new WriteRequest(device, args.Value, args.Offset, args.ResponseNeeded); ob.OnNext(request); if (request.IsReplyNeeded) { lock (this.context.ServerReadWriteLock) { this.context.Server.SendResponse ( args.Device, args.RequestId, request.Status.ToNative(), request.Offset, request.Value ); } } }); this.context.Callbacks.CharacteristicWrite += handler; return(() => this.context.Callbacks.CharacteristicWrite -= handler); });
public PatchModel() { Values = new ObservableCollection<PatchValue>(); InProcess = new Observable<bool>(); OriginalDoc = new EditorDocument { Language = JsonLanguage, IsReadOnly = true, }; NewDoc = new EditorDocument { Language = JsonLanguage, IsReadOnly = true, }; Script = new EditorDocument { Language = JScriptLanguage }; Script.Language.RegisterService(new PatchScriptIntelliPromptProvider(Values, recentDocuments)); Script.Language.RegisterService<IEditorDocumentTextChangeEventSink>(new AutoCompletionTrigger()); QueryDoc = new EditorDocument { Language = QueryLanguage }; ShowBeforeAndAfterPrompt = true; ShowAfterPrompt = true; AvailableObjects = new ObservableCollection<string>(); queryCollectionSource = new QueryDocumentsCollectionSource(); QueryResults = new DocumentsModel(queryCollectionSource) { Header = "Matching Documents", MinimalHeader = true, HideItemContextMenu = true}; QueryResults.ItemSelection.SelectionChanged += (sender, args) => { var firstOrDefault = QueryResults.ItemSelection.GetSelectedItems().FirstOrDefault(); if (firstOrDefault != null) { UpdateBeforeDocument(firstOrDefault.Item.Document); HasSelection = true; } else { HasSelection = false; ClearBeforeAndAfter(); } }; QueryResults.RecentDocumentsChanged += delegate { recentDocuments.Clear(); recentDocuments.AddRange(QueryResults.GetMostRecentDocuments().Where(d => d.Document != null).Take(5).Select(d => d.Document)); }; PatchScriptErrorMessage = new Observable<string>(); IsErrorVisible = new Observable<bool>(); }
public ConfigurationPageModel() { var configurationsCollectionSource = new ConfigurationsCollectionSource(); Configurations = new VirtualCollection<ConfigurationModel>(configurationsCollectionSource, 30, 10); SelectedItems = new ItemSelection<VirtualItem<ConfigurationModel>>(); IsSearchVisible = new Observable<bool>(); SearchPattern = new Observable<string>() { Value = "" }; SearchPattern.ObserveChanged().Throttle(TimeSpan.FromSeconds(1)).Subscribe(value => configurationsCollectionSource.Prefix = value); }
public void Observable_Can_Be_Disposed_Before_Subscription() { var observable = new Observable<Foo>(); var subscription = observable.SubscribeOn(Scheduler.Default).Subscribe( f=> {}); observable.Dispose(); subscription.Dispose(); }
public override IObservable <CharacteristicResult> Write(byte[] value) { this.AssertWrite(false); return(Observable.Create <CharacteristicResult>(async ob => { CancellationTokenSource cancelSrc = null; var handler = new EventHandler <GattCharacteristicEventArgs>((sender, args) => { if (this.NativeEquals(args)) { if (cancelSrc != null) { this.context.Semaphore.Release(); } Log.Write("Incoming Characteristic Write Event - " + args.Characteristic.Uuid); if (!args.IsSuccessful) { ob.OnError(new ArgumentException($"Failed to write characteristic - {args.Status}")); } else { this.Value = value; var result = new CharacteristicResult(this, CharacteristicEvent.Write, this.Value); ob.Respond(result); this.WriteSubject.OnNext(result); } } }); if (this.Properties.HasFlag(CharacteristicProperties.Write)) { cancelSrc = new CancellationTokenSource(); Log.Write("Hooking for write response - " + this.Uuid); await this.context.Semaphore.WaitAsync(cancelSrc.Token); this.context.Callbacks.CharacteristicWrite += handler; this.RawWriteWithResponse(value); } else { Log.Write("Write with No Response - " + this.Uuid); this.RawWriteNoResponse(ob, value); } return () => { cancelSrc?.Dispose(); this.context.Callbacks.CharacteristicWrite -= handler; }; })); }
public IObservable <AppState> WhenStateChanged() => Observable.Create <AppState>(ob => { var handler = new EventHandler((sender, args) => { var state = this.appState.IsActive ? AppState.Foreground : AppState.Background; ob.OnNext(state); }); this.appState.StatusChanged += handler; return(() => this.appState.StatusChanged -= handler); });
public override IObservable <IGattDescriptor> DiscoverDescriptors() => this.descriptorOb ??= Observable.Create <IGattDescriptor>(ob => { foreach (var nd in this.native.Descriptors) { var wrap = new GattDescriptor(this, this.context, nd); ob.OnNext(wrap); } return(Disposable.Empty); }) .Replay() .RefCount();
public SearchPageModel() { resultsSource = new SearchResultsCollectionSource(); resultsSource.SearchError += HandleSearchError; Results = new VirtualCollection<FileSystemModel>(resultsSource, 50, 10); Query = new Observable<string>(); SelectedFile = new Observable<VirtualItem<FileSystemModel>>(); SelectedItems = new ItemSelection<VirtualItem<FileSystemModel>>(); SearchErrorMessage = new Observable<string>(); IsErrorVisible = new Observable<bool>(); }
public override IObservable <DeviceSubscriptionEvent> WhenDeviceSubscriptionChanged() { this.subscriptionOb = this.subscriptionOb ?? Observable.Create <DeviceSubscriptionEvent>(ob => { var handler = new EventHandler <DescriptorWriteEventArgs>((sender, args) => { if (args.Descriptor.Equals(this.NotificationDescriptor)) { if (args.Value.SequenceEqual(NotifyEnabledBytes) || args.Value.SequenceEqual(IndicateEnableBytes)) { var device = this.GetOrAdd(args.Device); ob.OnNext(new DeviceSubscriptionEvent(device, true)); } else { var device = this.Remove(args.Device); if (device != null) { ob.OnNext(new DeviceSubscriptionEvent(device, false)); } } } }); var dhandler = new EventHandler <ConnectionStateChangeEventArgs>((sender, args) => { if (args.NewState != ProfileState.Disconnected) { return; } var device = this.Remove(args.Device); if (device != null) { ob.OnNext(new DeviceSubscriptionEvent(device, false)); } }); this.context.Callbacks.ConnectionStateChanged += dhandler; this.context.Callbacks.DescriptorWrite += handler; return(() => { this.context.Callbacks.DescriptorWrite -= handler; this.context.Callbacks.ConnectionStateChanged -= dhandler; }); }) .Publish() .RefCount(); return(this.subscriptionOb); }
public DatabasesListModel() { ModelUrl = "/databases"; ApplicationModel.Current.Server.Value.RawUrl = "databases"; GoToDatabaseName = new Observable<string>(); changeDatabase = new ChangeDatabaseCommand(); DatabasesWithEditableBundles = new List<string>(); Databases = new BindableCollection<DatabaseListItemModel>(m => m.Name); ApplicationModel.Current.Server.Value.SelectedDatabase.PropertyChanged += (sender, args) => { OnPropertyChanged(() => SelectedDatabase); OnPropertyChanged(() => ShowEditBundles); }; }
public CreateSampleDataCommand(Action<string> output) { this.output = output; database = ApplicationModel.Current.Server.Value.SelectedDatabase; databaseChanged = database .ObservePropertyChanged() .Select(e => Unit.Default); databaseChanged .SubscribeWeakly(this, (target, d) => target.HandleDatabaseChanged(target.database.Value)); SubscribeToStatisticsChanged(database.Value); }
public ScriptedIndexSettingsSectionModel() { DocumentToSample = new Observable<RavenJObject>(); AvailableIndexes = new BindableCollection<string>(x => x); SectionName = "Scripted Index"; ScriptedIndexes = new Dictionary<string, ScriptedIndexResults>(); IndexItem = new List<string>(); IndexScript = new EditorDocument { Language = IndexLanguage }; DeleteScript = new EditorDocument { Language = DeleteLanguage }; UpdateAvailableIndexes(); LoadScriptForIndex(); IndexScript.Language.RegisterService(new ScriptIndexIntelliPromptProvider(DocumentToSample)); DeleteScript.Language.RegisterService(new ScriptIndexIntelliPromptProvider(DocumentToSample, false)); }
public IObservable <Unit> WhenEnteringForeground() => Observable.Create <Unit>(ob => { var handler = new EventHandler((sender, args) => { if (this.appState.IsActive) { Debug.WriteLine("Firing WhenEnteringForeground Observable"); ob.OnNext(Unit.Default); } }); this.appState.StatusChanged += handler; return(() => this.appState.StatusChanged -= handler); });
public override IObservable <CharacteristicResult> Read() { this.AssertRead(); return(Observable.Create <CharacteristicResult>(async ob => { var cancelSrc = new CancellationTokenSource(); var handler = new EventHandler <GattCharacteristicEventArgs>((sender, args) => { if (this.NativeEquals(args)) { this.context.Semaphore.Release(); if (!args.IsSuccessful) { ob.OnError(new ArgumentException($"Failed to read characteristic - {args.Status}")); } else { this.Value = args.Characteristic.GetValue(); var result = new CharacteristicResult(this, CharacteristicEvent.Read, this.Value); ob.Respond(result); this.ReadSubject.OnNext(result); } } }); this.context.Callbacks.CharacteristicRead += handler; await this.context.Semaphore.WaitAsync(cancelSrc.Token); this.context.Marshall(() => { try { this.context.Gatt.ReadCharacteristic(this.native); } catch (Exception ex) { ob.OnError(ex); } }); return () => this.context.Callbacks.CharacteristicRead -= handler; })); }
public override IObservable <IGattCharacteristic?> GetKnownCharacteristic(string characteristicUuid, bool throwIfNotFound = false) => Observable.Create <IGattCharacteristic?>(ob => { var uuid = UUID.FromString(characteristicUuid); var cs = this.native.GetCharacteristic(uuid); if (cs == null) { ob.Respond(null); } else { var characteristic = new GattCharacteristic(this, this.context, cs); ob.Respond(characteristic); } return(Disposable.Empty); }) .Assert(this.Uuid, characteristicUuid, throwIfNotFound);
public override IObservable <HttpTransfer> WhenUpdated() { // TODO: cancel/error, should remove from db var query = new QueryFilter().ToNative(); this.httpObs = this.httpObs ?? Observable .Create <HttpTransfer>(ob => { var lastRun = DateTime.UtcNow; var disposer = new CompositeDisposable(); HttpTransferBroadcastReceiver .HttpEvents .Subscribe(ob.OnNext) .DisposedBy(disposer); Observable .Interval(TimeSpan.FromSeconds(2)) .Subscribe(_ => { using (var cursor = this.context.GetManager().InvokeQuery(query)) { while (cursor.MoveToNext()) { var lastModEpoch = cursor.GetLong(cursor.GetColumnIndex(Native.ColumnLastModifiedTimestamp)); var epoch = DateTimeOffset.FromUnixTimeMilliseconds(lastModEpoch); if (epoch > lastRun) { var transfer = cursor.ToLib(); ob.OnNext(transfer); } } } lastRun = DateTime.UtcNow; }) .DisposedBy(disposer); return(disposer); }) .Publish() .RefCount(); return(this.httpObs.Merge(base.WhenUpdated())); }
public IObservable <object> WhenEnteringBackground() { return(Observable.Create <object>(ob => { var handler = new EventHandler((sender, args) => { Debug.WriteLine("Firing 1 WhenEnteringBackground Observable"); if (!this.appState.IsActive) { Debug.WriteLine("Firing WhenEnteringBackground Observable"); ob.OnNext(null); } }); this.appState.StatusChanged += handler; return () => this.appState.StatusChanged -= handler; })); }
public void UpdateDatabaseDocument() { if (ApplicationModel.Current != null) ApplicationModel.Current.Server.Value.DocumentStore .AsyncDatabaseCommands .ForDefaultDatabase() .GetAsync("Raven/Databases/" + Name) .ContinueOnSuccessInTheUIThread(doc => { if (doc == null) return; DatabaseDocument = new Observable<DatabaseDocument> { Value = ApplicationModel.Current.Server.Value.DocumentStore.Conventions.CreateSerializer().Deserialize <DatabaseDocument>(new RavenJTokenReader(doc.DataAsJson)) }; OnPropertyChanged(() => HasReplication); }); }
public ReportingModel() { PageTitle = "Reporting"; ModelUrl = "/reporting"; AvailableIndexes = new BindableCollection<string>(x => x); IndexFields = new BindableCollection<string>(x => x); Results = new ObservableCollection<ReportRow>(); GroupByField = new Observable<string>(); ValueCalculations = new ObservableCollection<ValueCalculation>(); ExecutionElapsedTime = new Observable<TimeSpan>(); IsFilterVisible = new Observable<bool>(); QueryErrorMessage = new Observable<string>(); IsErrorVisible = new Observable<bool>(); FilterDoc = new EditorDocument { Language = QueryLanguage }; }
static DispatchTuple createFromWidget <TView, TEventArgs>(Expression <Func <TView, object> > property, Action <TView, EventHandler <TEventArgs> > addHandler, Action <TView, EventHandler <TEventArgs> > removeHandler) where TView : View where TEventArgs : EventArgs { // ExpressionToPropertyNames is used here as it handles boxing expressions that might // occur due to our use of object var propName = property.Body.GetMemberInfo().Name; return(new DispatchTuple { Type = typeof(TView), Property = propName, Func = (x, ex) => { var v = (TView)x; return Observable.FromEventPattern <TEventArgs>(h => addHandler(v, h), h => removeHandler(v, h)) .Select(_ => new ObservedChange <object, object>(v, ex)); } }); }
public IObservable <ScanResult> Scan(ScanConfig config) => Observable.Create <ScanResult>(ob => { this.devices.Clear(); this.callbacks = new LollipopScanCallback( sr => { var scanResult = this.ToScanResult(sr.Device, sr.Rssi, new AdvertisementData(sr)); ob.OnNext(scanResult); }, errorCode => ob.OnError(new BleException("Error during scan: " + errorCode.ToString())) ); var builder = new ScanSettings.Builder(); var scanMode = this.ToNative(config.ScanType); builder.SetScanMode(scanMode); var scanFilters = new List <ScanFilter>(); if (config.ServiceUuids != null && config.ServiceUuids.Count > 0) { foreach (var uuid in config.ServiceUuids) { var parcel = new ParcelUuid(UUID.FromString(uuid)); scanFilters.Add(new ScanFilter.Builder() .SetServiceUuid(parcel) .Build() ); } } if (config.AndroidUseScanBatching && this.Manager.Adapter.IsOffloadedScanBatchingSupported) { builder.SetReportDelay(100); } this.Manager.Adapter.BluetoothLeScanner.StartScan( scanFilters, builder.Build(), this.callbacks ); return(() => this.Manager.Adapter.BluetoothLeScanner?.StopScan(this.callbacks)); });
public DatabaseModel(string name, DocumentStore documentStore) { this.name = name; this.documentStore = documentStore; Tasks = new BindableCollection<TaskModel>(x => x.Name) { new ImportTask(), new ExportTask(), new StartBackupTask(), new IndexingTask(), new SampleDataTask(), new CsvImportTask() }; if (name == null || name == Constants.SystemDatabase) Tasks.Insert(3, new StartRestoreTask()); SelectedTask = new Observable<TaskModel> { Value = Tasks.FirstOrDefault() }; Statistics = new Observable<DatabaseStatistics>(); Status = new Observable<string> { Value = "Offline" }; OnPropertyChanged(() => StatusImage); asyncDatabaseCommands = name.Equals(Constants.SystemDatabase, StringComparison.OrdinalIgnoreCase) ? documentStore.AsyncDatabaseCommands.ForDefaultDatabase() : documentStore.AsyncDatabaseCommands.ForDatabase(name); DocumentChanges.Select(c => Unit.Default).Merge(IndexChanges.Select(c => Unit.Default)) .SampleResponsive(TimeSpan.FromSeconds(2)) .Subscribe(_ => RefreshStatistics()); databaseChanges.ConnectionStatusChanged += (sender, args) => { ApplicationModel.Current.Server.Value.SetConnected(((IDatabaseChanges)sender).Connected); UpdateStatus(); }; RefreshStatistics(); }
public IObservable <Unit> EnableIdleTimer(bool enabled) { var mgr = (PowerManager)Application.Context.GetSystemService(Context.PowerService); if (enabled) { if (this.wakeLock == null) { this.wakeLock = mgr.NewWakeLock(WakeLockFlags.Partial, this.GetType().FullName); this.wakeLock.Acquire(); } } else { this.wakeLock?.Release(); this.wakeLock = null; } return(Observable.Return(Unit.Default)); }
public override IObservable <object> Write(byte[] value) { this.AssertWrite(false); return(Observable.Create <object>(ob => { var handler = new EventHandler <GattCharacteristicEventArgs>((sender, args) => { if (args.Characteristic.Uuid.Equals(this.native.Uuid)) { if (!args.IsSuccessful) { ob.OnError(new ArgumentException($"Failed to write characteristic - {args.Status}")); } else { this.Value = value; ob.Respond(this.Value); this.WriteSubject.OnNext(this.Value); } } }); this.context.Callbacks.CharacteristicWrite += handler; this.native.SetValue(value); if (this.Properties.HasFlag(CharacteristicProperties.Write)) { this.native.WriteType = GattWriteType.Default; this.context.Gatt.WriteCharacteristic(this.native); } else { this.native.WriteType = GattWriteType.NoResponse; this.context.Gatt.WriteCharacteristic(this.native); this.Value = value; ob.Respond(this.Value); this.WriteSubject.OnNext(this.Value); } return () => this.context.Callbacks.CharacteristicWrite -= handler; })); }
public override IObservable <bool> SetNotificationValue(CharacteristicConfigDescriptorValue value) => Observable.FromAsync(async ct => { var enable = value != CharacteristicConfigDescriptorValue.None; var descriptor = this.native.GetDescriptor(NotifyDescriptorId); if (descriptor == null) { throw new ArgumentException("Characteristic Client Configuration Descriptor not found"); } var wrap = new GattDescriptor(this, this.context, descriptor); var success = this.context.Gatt.SetCharacteristicNotification(this.native, enable); await Task.Delay(250, ct); if (success) { await wrap.Write(GetDescriptionConfigBytes(value)); this.IsNotifying = enable; } return(success); });
public override IObservable <CharacteristicResult> Write(byte[] value) { this.AssertWrite(false); return(Observable.Create <CharacteristicResult>(ob => { var handler = new EventHandler <GattCharacteristicEventArgs>((sender, args) => { WriteLine($"Incoming Characteristic Write Event - " + args.Characteristic.Uuid); if (args.Characteristic.Equals(this.native)) { if (!args.IsSuccessful) { ob.OnError(new ArgumentException($"Failed to write characteristic - {args.Status}")); } else { this.Value = value; var result = new CharacteristicResult(this, CharacteristicEvent.Write, this.Value); ob.Respond(result); this.WriteSubject.OnNext(result); } } }); if (this.Properties.HasFlag(CharacteristicProperties.Write)) { WriteLine("Hooking for write response - " + this.Uuid); this.context.Callbacks.CharacteristicWrite += handler; this.RawWriteWithResponse(value); } else { WriteLine("Write with No Response - " + this.Uuid); this.RawWriteNoResponse(ob, value); } return () => this.context.Callbacks.CharacteristicWrite -= handler; })); }
private static DispatchTuple CreateFromAdapterView() { // AdapterView is more complicated because there are two events - one for select and one for deselect // respond to both const string propName = "SelectedItem"; return(new DispatchTuple { Type = typeof(AdapterView), Property = propName, Func = (x, ex) => { var v = (AdapterView)x; return Observable.Merge( Observable.FromEventPattern <AdapterView.ItemSelectedEventArgs>(h => v.ItemSelected += h, h => v.ItemSelected -= h) .Select(_ => new ObservedChange <object, object>(v, ex)), Observable.FromEventPattern <AdapterView.NothingSelectedEventArgs>(h => v.NothingSelected += h, h => v.NothingSelected -= h) .Select(_ => new ObservedChange <object, object>(v, ex))); } }); }
public override IObservable <CharacteristicGattResult> Write(byte[] value) => this.context.Invoke(Observable.Create <CharacteristicGattResult>(ob => { this.AssertWrite(false); var sub = this.context .Callbacks .CharacteristicWrite .Where(this.NativeEquals) .Subscribe(args => { Log.Debug(BleLogCategory.Characteristic, "write event - " + args.Characteristic.Uuid); if (args.IsSuccessful) { ob.Respond(new CharacteristicGattResult(this, value)); } else { ob.OnError(new BleException($"Failed to write characteristic - {args.Status}")); } }); Log.Debug(BleLogCategory.Characteristic, "Hooking for write response - " + this.Uuid); this.context.InvokeOnMainThread(() => { this.native.WriteType = GattWriteType.Default; this.native.SetValue(value); //if (!this.native.SetValue(value)) //ob.OnError(new BleException("Failed to set characteristic value")); //else if (!this.context.Gatt.WriteCharacteristic(this.native)) if (!this.context.Gatt.WriteCharacteristic(this.native)) { ob.OnError(new BleException("Failed to write to characteristic")); } }); return(sub); }));
public CollectionsModel() { ModelUrl = "/collections"; Collections = new BindableCollection<CollectionModel>(model => model.Name); SelectedCollection = new Observable<CollectionModel>(); DocumentsForSelectedCollection.SetChangesObservable(d => d.IndexChanges .Where(n =>n.Name.Equals(CollectionsIndex,StringComparison.InvariantCulture)) .Select(m => Unit.Default)); DocumentsForSelectedCollection.DocumentNavigatorFactory = (id, index) => DocumentNavigator.Create(id, index, CollectionsIndex, new IndexQuery() {Query = "Tag:" + GetSelectedCollectionName()}); SelectedCollection.PropertyChanged += (sender, args) => { PutCollectionNameInTheUrl(); CollectionSource.CollectionName = GetSelectedCollectionName(); DocumentsForSelectedCollection.Context = "Collection/" + GetSelectedCollectionName(); }; }
public override IObservable <CharacteristicGattResult> DisableNotifications() => this.context.Invoke(Observable.FromAsync(async ct => { var descriptor = this.native.GetDescriptor(NotifyDescriptorId); if (descriptor == null) { throw new BleException("Characteristic Client Configuration Descriptor not found"); } var wrap = new GattDescriptor(this, this.context, descriptor); if (!this.context.Gatt.SetCharacteristicNotification(this.native, false)) { throw new BleException("Could not set characteristic notification value"); } await this.context.OpPause(ct).ConfigureAwait(false); await wrap .WriteInternal(BluetoothGattDescriptor.DisableNotificationValue.ToArray()) .ToTask(ct) .ConfigureAwait(false); this.IsNotifying = false; return(new CharacteristicGattResult(this, null)); }));
public QueryModel() { ModelUrl = "/query"; ApplicationModel.Current.Server.Value.RawUrl = null; SelectedTransformer = new Observable<string> { Value = "None" }; SelectedTransformer.PropertyChanged += (sender, args) => Requery(); ApplicationModel.DatabaseCommands.GetTransformersAsync(0, 256).ContinueOnSuccessInTheUIThread(transformers => { Transformers = new List<string>{"None"}; Transformers.AddRange(transformers.Select(definition => definition.Name)); OnPropertyChanged(() => Transformers); }); queryDocument = new EditorDocument { Language = SyntaxEditorHelper.LoadLanguageDefinitionFromResourceStream("RavenQuery.langdef") }; ExceptionLine = -1; ExceptionColumn = -1; CollectionSource = new QueryDocumentsCollectionSource(); Observable.FromEventPattern<QueryStatisticsUpdatedEventArgs>(h => CollectionSource.QueryStatisticsUpdated += h, h => CollectionSource.QueryStatisticsUpdated -= h) .SampleResponsive(TimeSpan.FromSeconds(0.5)) .TakeUntil(Unloaded) .ObserveOnDispatcher() .Subscribe(e => { QueryTime = e.EventArgs.QueryTime; Results = e.EventArgs.Statistics; }); Observable.FromEventPattern<QueryErrorEventArgs>(h => CollectionSource.QueryError += h, h => CollectionSource.QueryError -= h) .ObserveOnDispatcher() .Subscribe(e => HandleQueryError(e.EventArgs.Exception)); DocumentsResult = new DocumentsModel(CollectionSource) { Header = "Results", DocumentNavigatorFactory = (id, index) => DocumentNavigator.Create(id, index, IndexName, CollectionSource.TemplateQuery), }; QueryErrorMessage = new Observable<string>(); IsErrorVisible = new Observable<bool>(); SortBy = new BindableCollection<StringRef>(x => x.Value); SortBy.CollectionChanged += HandleSortByChanged; SortByOptions = new BindableCollection<string>(x => x); Suggestions = new BindableCollection<FieldAndTerm>(x => x.Field); DynamicOptions = new BindableCollection<string>(x => x) {"AllDocs"}; AvailableIndexes = new BindableCollection<string>(x => x); SpatialQuery = new SpatialQueryModel {IndexName = indexName}; }
public EditableDocumentModel() { ModelUrl = "/edit"; ApplicationModel.Current.Server.Value.RawUrl = null; dataSection = new DocumentSection{ Name = "Data", Document = new EditorDocument { Language = JsonLanguage, TabSize = 2 } }; metaDataSection = new DocumentSection{ Name = "Metadata", Document = new EditorDocument { Language = JsonLanguage, TabSize = 2 } }; DocumentSections = new List<DocumentSection> { dataSection, metaDataSection }; EnableExpiration = new Observable<bool>(); ExpireAt = new Observable<DateTime>(); ExpireAt.PropertyChanged += (sender, args) => TimeChanged = true; CurrentSection = dataSection; var databaseName = ApplicationModel.Current.Server.Value.SelectedDatabase.Value.Name; ApplicationModel.Current.Server.Value.DocumentStore .AsyncDatabaseCommands .ForSystemDatabase() .CreateRequest("/admin/databases/" + databaseName, "GET") .ReadResponseJsonAsync() .ContinueOnSuccessInTheUIThread(doc => { if (doc == null) return; var databaseDocument = ApplicationModel.Current.Server.Value.DocumentStore.Conventions .CreateSerializer() .Deserialize<DatabaseDocument>(new RavenJTokenReader(doc)); string activeBundles; databaseDocument.Settings.TryGetValue("Raven/ActiveBundles", out activeBundles); if (activeBundles == null) return; if (activeBundles.Contains("Expiration")) { hasExpiration = true; OnPropertyChanged(() => HasExpiration); } }); References = new BindableCollection<LinkModel>(model => model.Title); Related = new BindableCollection<LinkModel>(model => model.Title); Recent = new BindableCollection<LinkModel>(model => model.Title); foreach (var recentDocument in ApplicationModel.Current.Server.Value.SelectedDatabase.Value.RecentDocuments) { Recent.Add(new LinkModel(recentDocument)); } DocumentErrors = new ObservableCollection<DocumentError>(); SearchEnabled = false; document = new Observable<JsonDocument>(); document.PropertyChanged += (sender, args) => UpdateFromDocument(); documentIdManager = JsonDataDocument.Properties.GetOrCreateSingleton(() => new DocumentReferencedIdManager()); InitializeDocument(); ParentPathSegments = new ObservableCollection<PathSegment> { new PathSegment { Name = "Documents", Url = "/documents" } }; currentDatabase = Database.Value.Name; dataSection.Document.ObserveTextChanged() .Merge(metaDataSection.Document.ObserveTextChanged()) .Do(_ => HasUnsavedChanges = true) .Throttle(TimeSpan.FromSeconds(1)) .ObserveOnDispatcher() .Subscribe(e => HandleDocumentChanged()); }
public PatchModel() { selectedItem = new Observable<string>(); OriginalDoc = new EditorDocument() { Language = JsonLanguage, IsReadOnly = true, }; NewDoc = new EditorDocument() { Language = JsonLanguage, IsReadOnly = true, }; Script = new EditorDocument() { Language = JScriptLanguage }; QueryDoc = new EditorDocument() { Language = QueryLanguage }; ShowBeforeAndAfterPrompt = true; ShowAfterPrompt = true; AvailableObjects = new ObservableCollection<string>(); Values = new ObservableCollection<PatchValue>(); queryCollectionSource = new QueryDocumentsCollectionSource(); QueryResults = new DocumentsModel(queryCollectionSource) { Header = "Matching Documents", MinimalHeader = true, HideItemContextMenu = true}; QueryResults.ItemSelection.SelectionChanged += (sender, args) => { var firstOrDefault = QueryResults.ItemSelection.GetSelectedItems().FirstOrDefault(); if (firstOrDefault != null) { OriginalDoc.SetText(firstOrDefault.Item.Document.ToJson().ToString()); ShowBeforeAndAfterPrompt = false; HasSelection = true; OnPropertyChanged(() => HasSelection); } else { HasSelection = false; OnPropertyChanged(() => HasSelection); ClearBeforeAndAfter(); } }; selectedItem.PropertyChanged += (sender, args) => { if (PatchOn == PatchOnOptions.Document && string.IsNullOrWhiteSpace(SelectedItem) == false) ApplicationModel.Database.Value.AsyncDatabaseCommands.GetAsync(SelectedItem). ContinueOnSuccessInTheUIThread(doc => { if (doc == null) { ClearBeforeAndAfter(); } else { OriginalDoc.SetText(doc.ToJson().ToString()); ShowBeforeAndAfterPrompt = false; } }); }; }
public QueryModel() { ModelUrl = "/query"; ApplicationModel.Current.Server.Value.RawUrl = null; queryDocument = new EditorDocument() { Language = SyntaxEditorHelper.LoadLanguageDefinitionFromResourceStream("RavenQuery.langdef") }; ExceptionLine = -1; ExceptionColumn = -1; CollectionSource = new QueryDocumentsCollectionSource(); Observable.FromEventPattern<QueryStatisticsUpdatedEventArgs>(h => CollectionSource.QueryStatisticsUpdated += h, h => CollectionSource.QueryStatisticsUpdated -= h) .SampleResponsive(TimeSpan.FromSeconds(0.5)) .TakeUntil(Unloaded) .ObserveOnDispatcher() .Subscribe(e => { QueryTime = e.EventArgs.QueryTime; Results = e.EventArgs.Statistics; }); Observable.FromEventPattern<QueryErrorEventArgs>(h => CollectionSource.QueryError += h, h => CollectionSource.QueryError -= h) .ObserveOnDispatcher() .Subscribe(e => HandleQueryError(e.EventArgs.Exception)); DocumentsResult = new DocumentsModel(CollectionSource) { Header = "Results", DocumentNavigatorFactory = (id, index) => DocumentNavigator.Create(id, index, IndexName, CollectionSource.TemplateQuery), }; QueryErrorMessage = new Observable<string>(); IsErrorVisible = new Observable<bool>(); SortBy = new BindableCollection<StringRef>(x => x.Value); SortBy.CollectionChanged += HandleSortByChanged; SortByOptions = new BindableCollection<string>(x => x); Suggestions = new BindableCollection<FieldAndTerm>(x => x.Field); DynamicOptions = new BindableCollection<string>(x => x) {"AllDocs"}; }
public DocumentsPageModel() { ModelUrl = "/documents"; ApplicationModel.Current.Server.Value.RawUrl = null; SelectedCollectionSortingMode = new Observable<string> { Value = Settings.Instance.CollectionSortingMode }; collectionSource = new CollectionDocumentsCollectionSource(); collectionDocumentsModel = new DocumentsModel(collectionSource) { DocumentNavigatorFactory = (id, index) => DocumentNavigator.Create(id, index, CollectionsIndex, new IndexQuery { Query = "Tag:" + GetSelectedCollectionName() }) }; collectionDocumentsModel.SetChangesObservable(d => d.IndexChanges .Where(n => n.Name.Equals(CollectionsIndex, StringComparison.InvariantCulture)) .Select(m => Unit.Default)); allDocumentsDocumentsModel = new DocumentsModel(new DocumentsCollectionSource()) { DocumentNavigatorFactory = (id, index) => DocumentNavigator.Create(id, index), Context = "AllDocuments", }; allDocumentsDocumentsModel.SetChangesObservable(d => d.DocumentChanges.Select(s => Unit.Default)); ravenDocumentsDocumentsModel = new DocumentsModel(new CollectionDocumentsCollectionSource()); ravenDocumentsDocumentsModel.SetChangesObservable(d => d.DocumentChanges.Select(s => Unit.Default)); Collections = new BindableCollection<CollectionModel>(model => model.Name) { new AllDocumentsCollectionModel(), new RavenDocumentsCollectionModel() }; SelectedCollection = new Observable<CollectionModel>(); SelectedCollection.PropertyChanged += (sender, args) => { PutCollectionNameInTheUrl(); var selectedCollectionName = GetSelectedCollectionName(); if (selectedCollectionName == "") { DocumentsModel = allDocumentsDocumentsModel; } else if (selectedCollectionName == "Raven Documents") { DocumentsModel = ravenDocumentsDocumentsModel; } else { collectionSource.CollectionName = selectedCollectionName; collectionDocumentsModel.Context = "Collection/" + GetSelectedCollectionName(); DocumentsModel = collectionDocumentsModel; } }; SortedCollectionsList = new CollectionViewSource { Source = Collections, SortDescriptions = { GetSortDescription() } }; SelectedCollectionSortingMode.PropertyChanged += (sender, args) => { using (SortedCollectionsList.DeferRefresh()) { SortedCollectionsList.SortDescriptions.Clear(); SortedCollectionsList.SortDescriptions.Add(GetSortDescription()); } Settings.Instance.CollectionSortingMode = SelectedCollectionSortingMode.Value; }; CollectionsListWidth = DefaultCollectionsListWidth; }
public EditableDocumentModel() { ModelUrl = "/edit"; dataSection = new DocumentSection() { Name = "Data", Document = new EditorDocument() { Language = JsonLanguage, TabSize = 2 } }; metaDataSection = new DocumentSection() { Name = "Metadata", Document = new EditorDocument() { Language = JsonLanguage, TabSize = 2 } }; DocumentSections = new List<DocumentSection>() { dataSection, metaDataSection }; CurrentSection = dataSection; References = new BindableCollection<LinkModel>(model => model.Title); Related = new BindableCollection<LinkModel>(model => model.Title); DocumentErrors = new ObservableCollection<DocumentError>(); SearchEnabled = false; document = new Observable<JsonDocument>(); document.PropertyChanged += (sender, args) => UpdateFromDocument(); documentIdManager = JsonDataDocument.Properties.GetOrCreateSingleton(() => new DocumentReferencedIdManager()); InitialiseDocument(); ParentPathSegments = new ObservableCollection<PathSegment>() { new PathSegment() { Name="Documents", Url = "/documents"} }; currentDatabase = Database.Value.Name; dataSection.Document.ObserveTextChanged() .Merge(metaDataSection.Document.ObserveTextChanged()) .Do(_ => HasUnsavedChanges = true) .Throttle(TimeSpan.FromSeconds(1)) .ObserveOnDispatcher() .Subscribe(e => HandleDocumentChanged()); }
public EditableDocumentModel() { ModelUrl = "/edit"; ApplicationModel.Current.Server.Value.RawUrl = null; dataSection = new DocumentSection{ Name = "Data", Document = new EditorDocument { Language = JsonLanguage, TabSize = 2 } }; metaDataSection = new DocumentSection{ Name = "Metadata", Document = new EditorDocument { Language = JsonLanguage, TabSize = 2 } }; DocumentSections = new List<DocumentSection> { dataSection, metaDataSection }; EnableExpiration = new Observable<bool>(); ExpireAt = new Observable<DateTime>(); ExpireAt.PropertyChanged += (sender, args) => TimeChanged = true; CurrentSection = dataSection; References = new BindableCollection<LinkModel>(model => model.Title); Related = new BindableCollection<LinkModel>(model => model.Title); Recent = new BindableCollection<LinkModel>(model => model.Title); foreach (var recentDocument in ApplicationModel.Current.Server.Value.SelectedDatabase.Value.RecentDocuments) { Recent.Add(new LinkModel(recentDocument)); } DocumentErrors = new ObservableCollection<DocumentError>(); SearchEnabled = false; document = new Observable<JsonDocument>(); document.PropertyChanged += (sender, args) => UpdateFromDocument(); documentIdManager = JsonDataDocument.Properties.GetOrCreateSingleton(() => new DocumentReferencedIdManager()); InitializeDocument(); ParentPathSegments = new ObservableCollection<PathSegment> { new PathSegment { Name = "Documents", Url = "/documents" } }; currentDatabase = Database.Value.Name; dataSection.Document.ObserveTextChanged() .Merge(metaDataSection.Document.ObserveTextChanged()) .Do(_ => HasUnsavedChanges = true) .Throttle(TimeSpan.FromSeconds(1)) .ObserveOnDispatcher() .Subscribe(e => HandleDocumentChanged()); }