public override IntPtr AddNotificationCallback(IntPtr managedCollectionHandle, NotificationCallbackDelegate callback) { NativeException nativeException; var result = NativeMethods.add_notification_callback(this, managedCollectionHandle, callback, out nativeException); nativeException.ThrowIfNecessary(); return result; }
public void WhenSynchronizationContextExists_ShouldAutoRefresh() { AsyncContext.Run(async() => { var tcs = new TaskCompletionSource <ChangeSet>(); var query = _realm.All <Person>(); NotificationCallbackDelegate <Person> cb = (s, c, e) => { if (e != null) { tcs.TrySetException(e); } else if (c != null) { tcs.TrySetResult(c); } }; using (query.SubscribeForNotifications(cb)) { _realm.Write(() => _realm.Add(new Person())); var changes = await tcs.Task.Timeout(2000); Assert.That(changes, Is.Not.Null); Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 })); } }); }
/// <summary> /// Initializes a new instance of the <see cref="AudioEngine"/> class. /// </summary> /// <param name="creationFlags">The creation flags.</param> /// <param name="settings">Settings for this audio engine</param> public AudioEngine(CreationFlags creationFlags, AudioEngineSettings settings) { bool debug = (creationFlags == CreationFlags.DebugMode); bool audition = (creationFlags == CreationFlags.AuditionMode); var debugRegistryKey = Registry.LocalMachine.OpenSubKey(DebugEngineRegistryKey); // If neither the debug nor audition flags are set, see if the debug registry key is set if (!debug && !audition && debugRegistryKey != null) { var value = debugRegistryKey.GetValue(DebugEngineRegistryValue); if (value is Int32 && ((int)value) != 0) { debug = true; } debugRegistryKey.Close(); } var selectedEngineCLSID = (debug) ? DebugEngineGuid : (audition) ? AuditionEngineGuid : EngineGuid; Utilities.CreateComInstance(selectedEngineCLSID, Utilities.CLSCTX.ClsctxInprocServer, Utilities.GetGuidFromType(typeof(AudioEngine)), this); unsafe { unmanagedDelegate = new NotificationCallbackDelegate(NotificationCallbackDelegateImpl); unmanagedDelegatePointer = Marshal.GetFunctionPointerForDelegate(unmanagedDelegate); } // Initialize the engine PreInitialize(settings); Initialize(settings); }
public override IntPtr AddNotificationCallback(IntPtr managedObjectHandle, NotificationCallbackDelegate callback) { var result = NativeMethods.add_notification_callback(this, managedObjectHandle, callback, out var nativeException); nativeException.ThrowIfNecessary(); return(result); }
private void UnsubscribeFromNotifications(NotificationCallbackDelegate <T> callback) { if (_callbacks.Remove(callback) && _callbacks.Count == 0) { UnsubscribeFromNotifications(); } }
internal void RemoveCallback(NotificationCallbackDelegate callback) { if (_callbacks.Remove(callback) && _callbacks.Count == 0) { UnsubscribeFromNotifications(); } }
public IntPtr AddNotificationCallback(IntPtr managedResultsHandle, NotificationCallbackDelegate callback) { NativeException nativeException; var result = NativeMethods.add_notification_callback(this, managedResultsHandle, callback, out nativeException); nativeException.ThrowIfNecessary(); return(result); }
public IDisposable SubscribeForNotifications(NotificationCallbackDelegate <T> callback) { if (_callbacks.Count == 0) { SubscribeForNotifications(); } _callbacks.Add(callback); return(new NotificationToken(this, callback)); }
public void ResultsShouldSendNotifications() { var query = _realm.All <Person>(); ChangeSet changes = null; NotificationCallbackDelegate <Person> cb = (s, c, e) => changes = c; using (query.SubscribeForNotifications(cb)) { _realm.Write(() => _realm.Add(new Person())); _realm.Refresh(); Assert.That(changes, Is.Not.Null); Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 })); } }
public IDisposable SubscribeForNotifications(NotificationCallbackDelegate <T> callback) { if (_callbacks.Count == 0) { SubscribeForNotifications(); } else if (_deliveredInitialNotification) { callback(this, null, null); } _callbacks.Add(callback); return(new NotificationToken(this, callback)); }
public void ListShouldSendNotifications() { var container = new OrderedContainer(); _realm.Write(() => _realm.Add(container)); ChangeSet changes = null; NotificationCallbackDelegate <OrderedObject> cb = (s, c, e) => changes = c; using (container.Items.SubscribeForNotifications(cb)) { _realm.Write(() => container.Items.Add(new OrderedObject())); _realm.Refresh(); Assert.That(changes, Is.Not.Null); Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 })); } }
public IDisposable SubscribeForNotifications(NotificationCallbackDelegate <T> callback) { Argument.NotNull(callback, nameof(callback)); if (_callbacks.Count == 0) { SubscribeForNotifications(); } else if (_deliveredInitialNotification) { callback(this, null, null); } _callbacks.Add(callback); return(NotificationToken.Create(callback, UnsubscribeFromNotifications)); }
public void ResultsShouldSendNotifications() { AsyncContext.Run(async delegate { var query = _realm.All <Person>(); ChangeSet changes = null; NotificationCallbackDelegate <Person> cb = (s, c, e) => changes = c; using (query.SubscribeForNotifications(cb)) { _realm.Write(() => _realm.Add(new Person())); await Task.Delay(MillisecondsToWaitForCollectionNotification); Assert.That(changes, Is.Not.Null); Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 })); } }); }
public void ListShouldSendNotifications() { AsyncContext.Run(async delegate { var container = new OrderedContainer(); _realm.Write(() => _realm.Add(container)); ChangeSet changes = null; NotificationCallbackDelegate <OrderedObject> cb = (s, c, e) => changes = c; using (container.Items.SubscribeForNotifications(cb)) { _realm.Write(() => container.Items.Add(new OrderedObject())); await Task.Delay(MillisecondsToWaitForCollectionNotification); Assert.That(changes, Is.Not.Null); Assert.That(changes.InsertedIndices, Is.EquivalentTo(new int[] { 0 })); } }); }
/// <summary> /// Register a callback to be invoked each time this <see cref="T:Realms.IRealmCollection`1" /> changes. /// </summary> /// <remarks> /// <para> /// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>. /// </para> /// <para> /// The first callback will be invoked with the initial <see cref="T:Realms.IRealmCollection`1" /> after the asynchronous query completes, /// and then called again after each write transaction which changes either any of the objects in the collection, or /// which objects are in the collection. The <c>changes</c> parameter will /// be <c>null</c> the first time the callback is invoked with the initial results. For each call after that, /// it will contain information about which rows in the results were added, removed or modified. /// </para> /// <para> /// If a write transaction did not modify any objects in this <see cref="T:Realms.IRealmCollection`1" />, the callback is not invoked at all. /// If an error occurs the callback will be invoked with <c>null</c> for the <c>sender</c> parameter and a non-<c>null</c> <c>error</c>. /// Currently the only errors that can occur are when opening the <see cref="T:Realms.Realm" /> on the background worker thread. /// </para> /// <para> /// At the time when the block is called, the <see cref="T:Realms.IRealmCollection`1" /> object will be fully evaluated /// and up-to-date, and as long as you do not perform a write transaction on the same thread /// or explicitly call <see cref="M:Realms.Realm.Refresh" />, accessing it will never perform blocking work. /// </para> /// <para> /// Notifications are delivered via the standard event loop, and so can't be delivered while the event loop is blocked by other activity. /// When notifications can't be delivered instantly, multiple notifications may be coalesced into a single notification. /// This can include the notification with the initial collection. /// </para> /// </remarks> /// <param name="collection">The <see cref="IRealmCollection{T}"/> to observe for changes.</param> /// <param name="callback">The callback to be invoked with the updated <see cref="T:Realms.IRealmCollection`1" />.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="M:System.IDisposable.Dispose" />. /// /// May be null in the case the provided collection is not managed. /// </returns> /// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0})" /> /// <seealso cref="M:Realms.CollectionExtensions.SubscribeForNotifications``1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0})" /> public static IDisposable?QueryAsyncWithNotifications <T>(this IRealmCollection <T> collection, NotificationCallbackDelegate <T> callback) where T : RealmObjectBase { if (!RealmAccess.CurrentThreadSubscriptionsAllowed) { throw new InvalidOperationException($"Make sure to call {nameof(RealmAccess)}.{nameof(RealmAccess.RegisterForNotifications)}"); } return(collection.SubscribeForNotifications(callback)); }
public static extern IntPtr add_notification_callback(ResultsHandle results, IntPtr managedResultsHandle, NotificationCallbackDelegate callback, out NativeException ex);
public static extern IntPtr add_notification_callback(DictionaryHandle handle, IntPtr managedDictionaryHandle, NotificationCallbackDelegate callback, out NativeException ex);
public static extern IntPtr add_notification_callback(ListHandle listHandle, IntPtr managedListHandle, NotificationCallbackDelegate callback, out NativeException ex);
public abstract NotificationTokenHandle AddNotificationCallback(IntPtr managedObjectHandle, NotificationCallbackDelegate callback);
/// <summary> /// A convenience method that casts <see cref="IList{T}" /> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <param name="list">The <see cref="IList{T}" /> to observe for changes.</param> /// <typeparam name="T">Type of the objects in the list.</typeparam> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />. /// </returns> public static IDisposable SubscribeForNotifications <T>(this IList <T> list, NotificationCallbackDelegate <T> callback) { RealmPCLHelpers.ThrowProxyShouldNeverBeUsed(); return(null); }
/// <summary> /// A convenience method that casts <see cref="IQueryable{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <param name="results">The <see cref="IQueryable{T}" /> to observe for changes.</param> /// <typeparam name="T">Type of the <see cref="RealmObject"/> in the results.</typeparam> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />. /// </returns> public static IDisposable SubscribeForNotifications <T>(this IQueryable <T> results, NotificationCallbackDelegate <T> callback) where T : RealmObject { RealmPCLHelpers.ThrowProxyShouldNeverBeUsed(); return(null); }
/// <summary> /// A convenience method that casts <see cref="IList{T}" /> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <param name="list">The <see cref="IList{T}" /> to observe for changes.</param> /// <typeparam name="T">Type of the objects in the list.</typeparam> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />. /// </returns> public static IDisposable SubscribeForNotifications <T>(this IList <T> list, NotificationCallbackDelegate <T> callback) { return(list.AsRealmCollection().SubscribeForNotifications(callback)); }
/// <summary> /// A convenience method that casts <see cref="IQueryable{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <param name="results">The <see cref="IQueryable{T}" /> to observe for changes.</param> /// <typeparam name="T">Type of the <see cref="RealmObject"/> in the results.</typeparam> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}" />.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose" />. /// </returns> public static IDisposable SubscribeForNotifications <T>(this IQueryable <T> results, NotificationCallbackDelegate <T> callback) where T : RealmObject { return(results.AsRealmCollection().SubscribeForNotifications(callback)); }
public static extern IntPtr add_notification_callback(ResultsHandle results, IntPtr managedResultsHandle, NotificationCallbackDelegate callback, out NativeException ex);
/// <summary> /// A convenience method that casts <see cref="ISet{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <param name="set">The <see cref="ISet{T}"/> to observe for changes.</param> /// <typeparam name="T">Type of the elements in the set.</typeparam> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>. /// </returns> public static IDisposable SubscribeForNotifications <T>(this ISet <T> set, NotificationCallbackDelegate <T> callback) => set.AsRealmCollection().SubscribeForNotifications(callback);
/// <summary> /// Initializes a new instance of the <see cref="AudioEngine"/> class. /// </summary> /// <param name="creationFlags">The creation flags.</param> /// <param name="settings">Settings for this audio engine</param> public AudioEngine(CreationFlags creationFlags, AudioEngineSettings settings) { bool debug = (creationFlags == CreationFlags.DebugMode); bool audition = (creationFlags == CreationFlags.AuditionMode); var debugRegistryKey = Registry.LocalMachine.OpenSubKey(DebugEngineRegistryKey); // If neither the debug nor audition flags are set, see if the debug registry key is set if (!debug && !audition && debugRegistryKey != null) { var value = debugRegistryKey.GetValue(DebugEngineRegistryValue); if (value is Int32 && ((int)value) != 0) debug = true; debugRegistryKey.Close(); } var selectedEngineCLSID = (debug) ? DebugEngineGuid : (audition) ? AuditionEngineGuid : EngineGuid; Utilities.CreateComInstance(selectedEngineCLSID, Utilities.CLSCTX.ClsctxInprocServer, Utilities.GetGuidFromType(typeof(AudioEngine)), this); unsafe { unmanagedDelegate = new NotificationCallbackDelegate(NotificationCallbackDelegateImpl); unmanagedDelegatePointer = Marshal.GetFunctionPointerForDelegate(unmanagedDelegate); } // Initialize the engine PreInitialize(settings); Initialize(settings); }
public void Dispose() { _collection.UnsubscribeFromNotifications(_callback); _callback = null; _collection = null; }
/// <summary> /// A convenience method that casts <see cref="IQueryable{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <param name="dictionary">The <see cref="IDictionary{String, T}"/> to observe for changes.</param> /// <typeparam name="T">Type of the elements in the dictionary.</typeparam> /// <seealso cref="IRealmCollection{TValue}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>. /// </returns> public static IDisposable SubscribeForNotifications <T>(this IDictionary <string, T> dictionary, NotificationCallbackDelegate <KeyValuePair <string, T> > callback) { return(dictionary.AsRealmCollection().SubscribeForNotifications(callback)); }
public static IDisposable?QueryAsyncWithNotifications <T>(this IRealmCollection <T> collection, NotificationCallbackDelegate <T> callback) where T : RealmObjectBase { // Subscriptions can only work on the main thread. if (!ThreadSafety.IsUpdateThread) { throw new InvalidOperationException("Cannot subscribe for realm notifications from a non-update thread."); } return(collection.SubscribeForNotifications(callback)); }
internal NotificationToken(RealmCollectionBase <T> collection, NotificationCallbackDelegate <T> callback) { _collection = collection; _callback = callback; }
/// <summary> /// A convenience method that casts <see cref="IList{T}"/> to <see cref="IRealmCollection{T}"/> and subscribes for change notifications. /// </summary> /// <remarks> /// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>. /// </remarks> /// <param name="list">The <see cref="IList{T}"/> to observe for changes.</param> /// <typeparam name="T">Type of the elements in the list.</typeparam> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>. /// /// May be null in the case the provided collection is not managed. /// </returns> public static IDisposable?QueryAsyncWithNotifications <T>(this IList <T> list, NotificationCallbackDelegate <T> callback) where T : RealmObjectBase { // Subscribing to non-managed instances doesn't work. // In this usage, the instance may be non-managed in tests. if (!(list is IRealmCollection <T> realmCollection)) { return(null); } return(QueryAsyncWithNotifications(realmCollection, callback)); }
public IDisposable RegisterForNotifications <T>(Func <Realm, IQueryable <T> > query, NotificationCallbackDelegate <T> callback) where T : RealmObjectBase { if (!ThreadSafety.IsUpdateThread) { throw new InvalidOperationException(@$ "{nameof(RegisterForNotifications)} must be called from the update thread."); } lock (realmLock) { Func <Realm, IDisposable?> action = realm => query(realm).QueryAsyncWithNotifications(callback); // Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing. notificationsResetMap.Add(action, () => callback(new EmptyRealmSet <T>(), null, null)); return(RegisterCustomSubscription(action)); } }
/// <summary> /// Subscribe to a realm collection and begin watching for asynchronous changes. /// </summary> /// <remarks> /// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>. /// /// In addition to the documented realm behaviour, we have the additional requirement of handling subscriptions over potential realm instance recycle. /// When this happens, callback events will be automatically fired: /// - On recycle start, a callback with an empty collection and <c>null</c> <see cref="ChangeSet"/> will be invoked. /// - On recycle end, a standard initial realm callback will arrive, with <c>null</c> <see cref="ChangeSet"/> and an up-to-date collection. /// </remarks> /// <param name="query">The <see cref="IQueryable{T}"/> to observe for changes.</param> /// <typeparam name="T">Type of the elements in the list.</typeparam> /// <param name="callback">The callback to be invoked with the updated <see cref="IRealmCollection{T}"/>.</param> /// <returns> /// A subscription token. It must be kept alive for as long as you want to receive change notifications. /// To stop receiving notifications, call <see cref="IDisposable.Dispose"/>. /// </returns> /// <seealso cref="IRealmCollection{T}.SubscribeForNotifications"/> public IDisposable RegisterForNotifications <T>(Func <Realm, IQueryable <T> > query, NotificationCallbackDelegate <T> callback) where T : RealmObjectBase { lock (realmLock) { Func <Realm, IDisposable?> action = realm => query(realm).QueryAsyncWithNotifications(callback); // Store an action which is used when blocking to ensure consumers don't use results of a stale changeset firing. notificationsResetMap.Add(action, () => callback(new EmptyRealmSet <T>(), null, null)); return(RegisterCustomSubscription(action)); } }
public static extern IntPtr add_notification_callback(ListHandle listHandle, IntPtr managedListHandle, NotificationCallbackDelegate callback, out NativeException ex);
public abstract IntPtr AddNotificationCallback(IntPtr managedCollectionHandle, NotificationCallbackDelegate callback);