From 99cad379538737a65594d51f740c281959af062f Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 13 Apr 2026 20:01:35 -0700 Subject: [PATCH 01/22] docs: overhaul XML comments for ObservableListEx extension methods Add event behavior tables using list-specific change reasons (Add, AddRange, Replace, Remove, RemoveRange, Moved, Refresh, Clear, OnError, OnCompleted), seealso cross-references, inheritdoc for secondary overloads, and Worth noting sections across all ObservableListEx operators (~124 overloads, ~60 unique). Key improvements: - 29 event behavior tables with list-specific change reason handling - 157 seealso cross-references linking related operators - 49 inheritdoc tags for secondary overloads with delta remarks - 19 Worth noting sections for non-obvious behavior - Multi-source operators have separate parent/child tables - All old-style generic param descriptions replaced --- src/DynamicData/List/ObservableListEx.cs | 2315 +++++++++++++--------- 1 file changed, 1417 insertions(+), 898 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 2f871bf4c..19c7fe57a 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. +// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. @@ -24,17 +24,29 @@ namespace DynamicData; public static class ObservableListEx { /// - /// Injects a side effect into a change set observable. + /// Injects a side effect into a changeset stream via an . + /// The adaptor's Adapt method is called for each changeset under a synchronized lock, then the changeset is forwarded downstream. /// - /// The type of the item. - /// The source. - /// The adaptor. - /// An observable which emits the change set. - /// - /// source - /// or - /// adaptor. - /// + /// The type of items in the list. + /// The source list changeset stream. + /// The adaptor whose Adapt method is invoked for each changeset. + /// A list changeset stream identical to the source, with the adaptor side effect applied. + /// or is null. + /// + /// + /// This operator synchronizes access with a lock, then calls adaptor.Adapt(changes) before forwarding the changeset. + /// It is the primary extension point for custom UI binding adaptors (e.g., + /// delegates to this operator). + /// + /// + /// EventBehavior + /// Add/AddRange/Replace/Remove/RemoveRange/Moved/Refresh/ClearThe adaptor's Adapt method is called with the full changeset, then it is forwarded downstream unchanged. + /// OnErrorForwarded to the downstream observer. If the adaptor throws, the exception propagates as OnError. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// + /// public static IObservable> Adapt(this IObservable> source, IChangeSetAdaptor adaptor) where T : notnull { @@ -55,16 +67,20 @@ public static IObservable> Adapt(this IObservable } /// - /// Adds a key to the change set result which enables all observable cache features of dynamic data. + /// Adds a key to each item in a list changeset, converting it to a cache changeset that supports all keyed DynamicData operators. /// + /// The type of items in the list. + /// The type of the key. + /// The source list changeset stream. + /// A function to extract a unique key from each item. + /// A cache changeset stream (IObservable<IChangeSet<TObject, TKey>>) with keyed items. /// - /// All indexed changes are dropped i.e. sorting is not supported by this function. + /// + /// All index information is dropped during conversion because cache changesets are unordered by default. + /// Use this when you need to transition from list-based pipelines to cache-based operators (Filter by key, Join, Group, etc.). + /// /// - /// The type of object. - /// The type of key. - /// The source. - /// The key selector. - /// An observable which emits the change set. + /// public static IObservable> AddKey(this IObservable> source, Func keySelector) where TObject : notnull where TKey : notnull @@ -76,13 +92,33 @@ public static IObservable> AddKey(this } /// - /// Apply a logical And operator between the collections. - /// Items which are in all of the sources are included in the result. + /// Applies a logical AND (intersection) between multiple list changeset streams. + /// Only items present in ALL sources appear in the result. /// - /// The type of the item. - /// The source. - /// The others. - /// An observable which emits the change set. + /// The type of items in the lists. + /// The primary source list changeset stream. + /// Additional changeset streams to intersect with. + /// A list changeset stream containing items that exist in every source. + /// + /// + /// Uses reference counting per item across all sources. An item appears downstream only when + /// its reference count is non-zero in ALL sources. Item identity is determined by the default equality comparer. + /// + /// + /// EventBehavior + /// Add/AddRangeThe item's reference count is incremented in its source tracker. If the item is now present in all sources, an Add is emitted. + /// ReplaceThe old item is removed from the tracker and the new item is added. Membership is recalculated for both. + /// Remove/RemoveRange/ClearThe item's reference count is decremented. If it was in the result and is no longer in all sources, a Remove is emitted. + /// RefreshForwarded as Refresh if the item is currently in the result. + /// MovedIgnored (set operations are position-independent). + /// OnErrorForwarded from any source. + /// OnCompletedForwarded when all sources complete. + /// + /// Worth noting: Item identity uses object equality, not position. Duplicate items in a single source are reference-counted independently. + /// + /// + /// + /// public static IObservable> And(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -91,53 +127,37 @@ public static IObservable> And(this IObservable> return source.Combine(CombineOperator.And, others); } - /// - /// Apply a logical And operator between the collections. - /// Items which are in all of the sources are included in the result. - /// - /// The type of the item. - /// The sources. - /// An observable which emits the change set. + /// + /// A fixed collection of changeset streams to intersect. + /// This overload accepts a pre-built collection of sources instead of params array. public static IObservable> And(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.And); - /// - /// Dynamically apply a logical And operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. - /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// + /// An observable list of changeset streams. Sources can be added or removed dynamically. + /// This overload supports dynamic source management: adding or removing changeset streams from the observable list triggers re-evaluation. public static IObservable> And(this IObservableList>> sources) where T : notnull => sources.Combine(CombineOperator.And); - /// - /// Dynamically apply a logical And operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. - /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// + /// An observable list of observable lists. Each inner list's changes are connected automatically. + /// This overload accepts instances directly, calling Connect() internally. public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); - /// - /// Dynamically apply a logical And operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. - /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// + /// An observable list of source lists. Each inner list's changes are connected automatically. + /// This overload accepts instances directly, calling Connect() internally. public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); /// - /// Converts the source list to an read only observable list. + /// Wraps a as a read-only , hiding mutation methods. /// - /// The type of the item. - /// The source. - /// An observable list. - /// source. + /// The type of items in the list. + /// The mutable source list to wrap. + /// A read-only observable list that mirrors the source. + /// is null. public static IObservableList AsObservableList(this ISourceList source) where T : notnull { @@ -147,12 +167,14 @@ public static IObservableList AsObservableList(this ISourceList source) } /// - /// Converts the source observable to an read only observable list. + /// Materializes a changeset stream into a read-only . + /// The list is kept in sync with the source stream for the lifetime of the subscription. /// - /// The type of the item. - /// The source. - /// An observable list. - /// source. + /// The type of items in the list. + /// The source changeset stream. + /// A read-only observable list reflecting the current state of the stream. + /// is null. + /// public static IObservableList AsObservableList(this IObservable> source) where T : notnull { @@ -162,14 +184,36 @@ public static IObservableList AsObservableList(this IObservable - /// Automatically refresh downstream operators when any property changes. + /// Monitors all properties on each item (via ) and emits Refresh + /// changes when any property changes, causing downstream operators to re-evaluate. /// - /// The type of object. - /// The source observable. - /// Batch up changes by specifying the buffer. This greatly increases performance when many elements have successive property changes. - /// When observing on multiple property changes, apply a throttle to prevent excessive refresh invocations. - /// The scheduler. - /// An observable change set with additional refresh changes. + /// The type of items, which must implement . + /// The source list changeset stream. + /// Optional buffer duration to batch multiple refresh signals into a single changeset. + /// Optional throttle applied to each item's property change notifications. + /// The scheduler for throttle and buffer timing. Defaults to . + /// A list changeset stream with additional Refresh changes injected when properties change. + /// + /// + /// Wraps using WhenAnyPropertyChanged() as the re-evaluator. + /// Pair with or + /// to get reactive re-evaluation on property changes. + /// + /// + /// EventBehavior + /// Add/AddRangeSubscribes to PropertyChanged on each new item. The original change is forwarded. + /// ReplaceUnsubscribes from the old item, subscribes to the new. The original change is forwarded. + /// Remove/RemoveRange/ClearUnsubscribes from removed items. The original change is forwarded. + /// Moved/RefreshForwarded unchanged. + /// Property changesA Refresh change is emitted for the item whose property changed. + /// OnErrorForwarded from the source or from the property change observable. + /// OnCompletedForwarded when the source completes. + /// + /// Worth noting: Each item generates a subscription. For large lists with frequent property changes, use and to reduce churn. + /// + /// + /// + /// public static IObservable> AutoRefresh(this IObservable> source, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged { @@ -189,17 +233,14 @@ public static IObservable> AutoRefresh(this IObserv scheduler); } - /// - /// Automatically refresh downstream operators when properties change. - /// - /// The type of object. - /// The type of property. - /// The source observable. - /// Specify a property to observe changes. When it changes a Refresh is invoked. - /// Batch up changes by specifying the buffer. This greatly increases performance when many elements have successive property changes. - /// When observing on multiple property changes, apply a throttle to prevent excessive refresh invocations. - /// The scheduler. - /// An observable change set with additional refresh changes. + /// + /// The type of the monitored property. + /// The source list changeset stream. + /// An expression selecting the specific property to monitor. + /// Optional buffer duration to batch refresh signals. + /// Optional throttle per item's property change notifications. + /// The scheduler for throttle and buffer timing. + /// This overload monitors a single property instead of all properties. More efficient when only one property affects downstream operators. public static IObservable> AutoRefresh(this IObservable> source, Expression> propertyAccessor, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged { @@ -221,15 +262,35 @@ public static IObservable> AutoRefresh(t } /// - /// Automatically refresh downstream operator. The refresh is triggered when the observable receives a notification. + /// Monitors each item with a custom observable and emits Refresh changes whenever that observable fires, + /// causing downstream operators (Filter, Sort, Group) to re-evaluate. /// - /// The type of object. - /// A ignored type used for specifying what to auto refresh on. - /// The source observable change set. - /// An observable which acts on items within the collection and produces a value when the item should be refreshed. - /// Batch up changes by specifying the buffer. This greatly increases performance when many elements require a refresh. - /// The scheduler. - /// An observable change set with additional refresh changes. + /// The type of items in the list. + /// The type emitted by the re-evaluator observable (value is ignored). + /// The source list changeset stream. + /// A factory that, given an item, returns an observable whose emissions trigger a Refresh for that item. + /// Optional buffer duration to batch refresh signals into a single changeset. + /// The scheduler for buffering. + /// A list changeset stream with additional Refresh changes injected when per-item observables fire. + /// + /// + /// This is the general-purpose refresh mechanism. + /// is a convenience wrapper that uses WhenAnyPropertyChanged() as the re-evaluator. + /// + /// + /// EventBehavior + /// Add/AddRangeSubscribes to the re-evaluator observable for each new item via MergeMany. The original change is forwarded. + /// ReplaceUnsubscribes from the old item's observable, subscribes to the new. The original change is forwarded. + /// Remove/RemoveRange/ClearUnsubscribes from removed items. The original change is forwarded. + /// Moved/RefreshForwarded unchanged. + /// Re-evaluator firesThe item's current index is looked up and a Refresh change is emitted. + /// OnErrorForwarded from source or from any re-evaluator observable. + /// OnCompletedForwarded when the source completes. + /// + /// Worth noting: The internal index lookup (to find where each item is for the Refresh change) requires maintaining a cloned list, adding memory overhead proportional to list size. + /// + /// + /// public static IObservable> AutoRefreshOnObservable(this IObservable> source, Func> reevaluator, TimeSpan? changeSetBuffer = null, IScheduler? scheduler = null) where TObject : notnull { @@ -240,18 +301,37 @@ public static IObservable> AutoRefreshOnObservable - /// Binds a clone of the observable change set to the target observable collection. + /// Applies changeset mutations to a target for UI data binding. /// - /// The type of the item. - /// The source. - /// The target collection. - /// The reset threshold. - /// An observable which emits the change set. - /// - /// source - /// or - /// targetCollection. - /// + /// The type of items in the list. + /// The source list changeset stream. + /// The target collection to keep in sync. + /// When a changeset exceeds this many changes, the collection is reset instead of applying individual changes. + /// A continuation of the source changeset stream (allows further chaining). + /// or is null. + /// + /// + /// Delegates to with an ObservableCollectionAdaptor. + /// Each changeset is applied to the target collection on the calling thread. For UI binding, ensure the source is + /// observed on the UI thread (e.g., via ObserveOn). + /// + /// + /// EventBehavior + /// AddItem inserted at the specified index in the target collection. + /// AddRangeItems inserted as a range. If the count exceeds , the collection is cleared and repopulated. + /// ReplaceItem at the specified index is replaced. + /// RemoveItem at the specified index is removed. + /// RemoveRange/ClearItems removed from the collection. + /// MovedItem is moved between positions in the collection. + /// RefreshDepends on the adaptor implementation. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// + /// + /// + /// public static IObservable> Bind(this IObservable> source, IObservableCollection targetCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -269,19 +349,11 @@ public static IObservable> Bind(this IObservable> return source.Bind(targetCollection, options); } - /// - /// Binds a clone of the observable change set to the target observable collection. - /// - /// The type of the item. - /// The source. - /// The target collection. - /// The binding options. - /// An observable which emits the change set. - /// - /// source - /// or - /// targetCollection. - /// + /// + /// The source list changeset stream. + /// The target collection to keep in sync. + /// Binding options controlling reset threshold and other behaviors. + /// This overload accepts a struct for fine-grained control over binding behavior. public static IObservable> Bind(this IObservable> source, IObservableCollection targetCollection, BindingOptions options) where T : notnull { @@ -292,14 +364,11 @@ public static IObservable> Bind(this IObservable> return source.Adapt(adaptor); } - /// - /// Creates a binding to a readonly observable collection which is specified as an 'out' parameter. - /// - /// The type of the item. - /// The source. - /// The resulting read only observable collection. - /// The reset threshold. - /// A continuation of the source stream. + /// + /// The source list changeset stream. + /// Output parameter receiving the created . + /// When a changeset exceeds this many changes, the collection is reset. + /// This overload creates a via an out parameter, backed by an internal ObservableCollectionExtended. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -315,14 +384,11 @@ public static IObservable> Bind(this IObservable> return source.Bind(out readOnlyObservableCollection, options); } - /// - /// Creates a binding to a readonly observable collection which is specified as an 'out' parameter. - /// - /// The type of the item. - /// The source. - /// The resulting read only observable collection. - /// The binding options. - /// A continuation of the source stream. + /// + /// The source list changeset stream. + /// Output parameter receiving the created . + /// Binding options controlling reset threshold and other behaviors. + /// This overload creates a with for fine-grained control. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, BindingOptions options) where T : notnull { @@ -337,19 +403,11 @@ public static IObservable> Bind(this IObservable> #if SUPPORTS_BINDINGLIST - /// - /// Binds a clone of the observable change set to the target observable collection. - /// - /// The type of the item. - /// The source. - /// The target binding list. - /// The reset threshold. - /// - /// source - /// or - /// targetCollection. - /// - /// An observable which emits the change set. + /// + /// The source list changeset stream. + /// The target to keep in sync. + /// When a changeset exceeds this many changes, the list is reset. + /// This overload binds to a (WinForms binding). Uses a BindingListAdaptor internally. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this IObservable> source, BindingList bindingList, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -361,30 +419,13 @@ public static IObservable> Bind(this IObservable> #endif - /// - /// Batches the underlying updates if a pause signal (i.e when the buffer selector return true) has been received. - /// When a resume signal has been received the batched updates will be fired. - /// - /// The type of the object. - /// The source. - /// When true, observable begins to buffer and when false, window closes and buffered result if notified. - /// The scheduler. - /// An observable which emits the change set. - /// source. + /// + /// This overload starts unpaused and has no timeout. public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, IScheduler? scheduler = null) where T : notnull => BufferIf(source, pauseIfTrueSelector, false, scheduler); - /// - /// Batches the underlying updates if a pause signal (i.e when the buffer selector return true) has been received. - /// When a resume signal has been received the batched updates will be fired. - /// - /// The type of the object. - /// The source. - /// When true, observable begins to buffer and when false, window closes and buffered result if notified. - /// if set to true [initial pause state]. - /// The scheduler. - /// An observable which emits the change set. - /// source. + /// + /// This overload allows setting the initial pause state but has no timeout. public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, bool initialPauseState, IScheduler? scheduler = null) where T : notnull { @@ -394,32 +435,39 @@ public static IObservable> BufferIf(this IObservable - /// Batches the underlying updates if a pause signal (i.e when the buffer selector return true) has been received. - /// When a resume signal has been received the batched updates will be fired. - /// - /// The type of the object. - /// The source. - /// When true, observable begins to buffer and when false, window closes and buffered result if notified. - /// Specify a time to ensure the buffer window does not stay open for too long. - /// The scheduler. - /// An observable which emits the change set. - /// source. + /// + /// This overload starts unpaused and accepts a timeout but not an explicit initial pause state. public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, TimeSpan? timeOut, IScheduler? scheduler = null) where T : notnull => BufferIf(source, pauseIfTrueSelector, false, timeOut, scheduler); /// - /// Batches the underlying updates if a pause signal (i.e when the buffer selector return true) has been received. - /// When a resume signal has been received the batched updates will be fired. + /// Buffers changeset notifications while a pause signal is active, then flushes all buffered changes when resumed. /// - /// The type of the object. - /// The source. - /// When true, observable begins to buffer and when false, window closes and buffered result if notified. - /// if set to true [initial pause state]. - /// Specify a time to ensure the buffer window does not stay open for too long. - /// The scheduler. - /// An observable which emits the change set. - /// source. + /// The type of items in the list. + /// The source list changeset stream. + /// An observable that controls buffering: true pauses (buffers), false resumes (flushes). + /// The initial pause state. When true, buffering starts immediately. + /// Optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. + /// The scheduler for timeout scheduling. + /// A list changeset stream that buffers during pause and emits combined changesets on resume. + /// or is null. + /// + /// + /// All changeset events are buffered at the changeset level (not individual changes) while paused. + /// On resume, all buffered changesets are emitted as a single combined changeset. If the buffer is empty on resume, + /// no emission occurs. + /// + /// + /// EventBehavior + /// Any (while paused)Accumulated in an internal buffer. Not emitted downstream. + /// Any (while active)Passed through immediately. + /// Pause selector emits falseAll buffered changesets are flushed downstream as one combined changeset. + /// Timeout firesAutomatically resumes and flushes the buffer. + /// OnErrorForwarded immediately (not buffered). + /// OnCompletedForwarded immediately. + /// + /// Worth noting: Each pause/resume cycle re-arms the timeout. Rapid toggling can create many small buffer windows. + /// public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, bool initialPauseState, TimeSpan? timeOut, IScheduler? scheduler = null) where T : notnull { @@ -430,13 +478,21 @@ public static IObservable> BufferIf(this IObservable - /// Buffers changes for an initial period only. After the period has elapsed, not further buffering occurs. + /// Buffers changesets during an initial time window, then emits a single combined changeset and passes through subsequent changes. /// - /// The type of object. - /// The source change set. - /// The period to buffer, measure from the time that the first item arrives. - /// The scheduler to buffer on. - /// An observable which emits the change set. + /// The type of items in the list. + /// The source list changeset stream. + /// The time period (measured from first emission) during which changes are buffered. + /// The scheduler for timing the buffer window. + /// A list changeset stream where the initial burst is combined into one changeset. + /// + /// + /// Composed from , Buffer, and . + /// After the initial buffer period, all subsequent changesets pass through immediately. + /// + /// + /// + /// public static IObservable> BufferInitial(this IObservable> source, TimeSpan initialBuffer, IScheduler? scheduler = null) where TObject : notnull => source.DeferUntilLoaded().Publish( shared => @@ -447,11 +503,13 @@ public static IObservable> BufferInitial(this IObse }); /// - /// Cast the changes to another form. + /// Casts each item in the changeset from object to using a direct cast. /// - /// The type of the destination. - /// The source. - /// An observable which emits the change set. + /// The target type to cast to. + /// The source list changeset stream of object items. + /// A list changeset stream of cast items. + /// + /// public static IObservable> Cast(this IObservable> source) where TDestination : notnull { @@ -461,14 +519,16 @@ public static IObservable> Cast(this IObs } /// - /// Cast the changes to another form. - /// Alas, I had to add the converter due to type inference issues. The converter can be avoided by CastToObject() first. + /// Transforms each item in the changeset using a conversion function. /// - /// The type of the object. - /// The type of the destination. - /// The source. - /// The conversion factory. - /// An observable which emits the change set. + /// The source item type. + /// The destination item type. + /// The source list changeset stream. + /// A function to convert each item from to . + /// A list changeset stream of converted items. + /// Use this overload when type inference requires explicit specification of both source and destination types. Alternatively, call first, then the single-type-parameter overload. + /// + /// public static IObservable> Cast(this IObservable> source, Func conversionFactory) where TSource : notnull where TDestination : notnull @@ -481,22 +541,28 @@ public static IObservable> Cast( } /// - /// Cast the underlying type of an object. Use before a Cast function. + /// Casts each item in the changeset to object. Typically used before to work around type inference limitations. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// The source item type (must be a reference type). + /// The source list changeset stream. + /// A list changeset stream of object items. + /// public static IObservable> CastToObject(this IObservable> source) where T : class => source.Select(changes => changes.Transform(t => (object)t)); /// - /// Clones the target list as a side effect of the stream. + /// Applies each changeset to the target list as a side effect, keeping it synchronized with the source. /// - /// The type of the item. - /// The source. - /// The target of the clone. - /// An observable which emits the change set. - /// source. + /// The type of items in the list. + /// The source list changeset stream. + /// The target list to clone changes into. + /// A continuation of the source changeset stream. + /// is null. + /// + /// Lower-level than . Uses IList<T>.Clone() to apply all changeset operations directly. + /// + /// + /// public static IObservable> Clone(this IObservable> source, IList target) where T : notnull { @@ -511,7 +577,7 @@ public static IObservable> Clone(this IObservable /// /// The type of the object. /// The type of the destination. - /// The source. + /// The source changeset stream. /// The conversion factory. /// An observable which emits the change set. [Obsolete("Prefer Cast as it is does the same thing but is semantically correct")] @@ -527,11 +593,27 @@ public static IObservable> Convert - /// Defer the subscription until the stream has been inflated with data. + /// Defers downstream delivery until the source emits its first changeset, then forwards all subsequent changesets. /// /// The type of the object. - /// The source. - /// An observable which emits the change set. + /// The source list changeset stream. + /// A list changeset stream that begins emitting only after the source has produced its first changeset. + /// is null. + /// + /// + /// Subscribes to the source immediately but buffers internally until the first changeset arrives, at which point it emits + /// the initial data and all subsequent changesets. This is useful when downstream consumers should not receive an empty initial state. + /// + /// + /// EventBehavior + /// First changesetDelivered downstream, unlocking the stream for all future emissions. + /// Subsequent changesetsForwarded immediately. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// + /// public static IObservable> DeferUntilLoaded(this IObservable> source) where T : notnull { @@ -540,12 +622,10 @@ public static IObservable> DeferUntilLoaded(this IObservable(source).Run(); } - /// - /// Defer the subscription until the cache has been inflated with data. - /// - /// The type of the object. - /// The source. - /// An observable which emits the change set. + /// + /// + /// Convenience overload that calls source.Connect().DeferUntilLoaded(). + /// public static IObservable> DeferUntilLoaded(this IObservableList source) where T : notnull { @@ -555,16 +635,31 @@ public static IObservable> DeferUntilLoaded(this IObservableLis } /// - /// Disposes each item when no longer required. - /// - /// Individual items are disposed after removal or replacement changes have been sent downstream. - /// All items previously-published on the stream are disposed after the stream finalizes. - /// + /// Disposes items that implement when they are removed, replaced, or cleared from the stream. + /// All remaining tracked items are disposed when the stream finalizes (OnCompleted, OnError, or subscription disposal). /// /// The type of the object. - /// The source. - /// A continuation of the original stream. - /// source. + /// The source list changeset stream. + /// A continuation of the source changeset stream with disposal side effects applied. + /// is null. + /// + /// + /// Items are cast to and disposed after the changeset has been forwarded downstream. + /// Items that do not implement are silently ignored. + /// + /// + /// EventBehavior + /// Add/AddRangeItems are tracked for future disposal. Changeset forwarded. + /// ReplaceThe previous (replaced) item is disposed after the changeset is forwarded. The new item is tracked. + /// Remove/RemoveRangeRemoved items are disposed after the changeset is forwarded. + /// ClearAll tracked items are disposed after the changeset is forwarded. + /// Moved/RefreshForwarded. No disposal occurs. + /// OnError/OnCompleted/DisposalAll remaining tracked items are disposed during finalization. + /// + /// Worth noting: Disposal happens after the changeset is delivered downstream, so subscribers see the change before items are disposed. + /// + /// + /// public static IObservable> DisposeMany(this IObservable> source) where T : notnull { @@ -574,18 +669,32 @@ public static IObservable> DisposeMany(this IObservable - /// Selects distinct values from the source, using the specified value selector. + /// Extracts distinct values from source items using , with reference counting to track when values enter and leave the result set. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform factory. - /// An observable which emits the change set. - /// - /// source - /// or - /// valueSelector. - /// + /// The type of items in the source list. + /// The type of distinct values produced. + /// The source list changeset stream. + /// A function that extracts the value to track from each source item. + /// A list changeset stream of distinct values. + /// or is null. + /// + /// + /// Maintains an internal reference count per distinct value. A value is included when its count first exceeds zero + /// and removed when its count drops back to zero. + /// + /// + /// EventBehavior + /// Add/AddRangeValue extracted. If first occurrence, an Add is emitted. Otherwise the reference count is incremented silently. + /// ReplaceOld value's reference count decremented (removed if zero), new value's count incremented (added if first). If the value did not change, no emission. + /// Remove/RemoveRangeReference count decremented. If the count reaches zero, a Remove is emitted for that distinct value. + /// RefreshValue is re-extracted. If changed, old value decremented and new value incremented (same as Replace logic). + /// ClearAll reference counts cleared. Remove emitted for every tracked distinct value. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// + /// public static IObservable> DistinctValues(this IObservable> source, Func valueSelector) where TObject : notnull where TValue : notnull @@ -598,13 +707,36 @@ public static IObservable> DistinctValues(th } /// - /// Apply a logical Except operator between the collections. - /// Items which are in the source and not in the others are included in the result. + /// Applies a logical set-difference (Except) between the source and other streams. + /// Items present in the first source but not in any of the are included in the result. /// /// The type of the item. - /// The source. - /// The others. - /// An observable which emits the change set. + /// The primary source list changeset stream. + /// The other list changeset streams to exclude from the result. + /// A list changeset stream containing items from that are not in any of . + /// is null. + /// + /// + /// Uses reference-counted equality comparison across all sources. Items are compared by equality (not index position). + /// The first source has a special role: only items from it can appear in the result, and only if they do not exist in any other source. + /// + /// + /// EventBehavior + /// Add/AddRange (first source)If the item does not exist in any other source, an Add is emitted. + /// Add/AddRange (other source)If the item was in the result (from first source), a Remove is emitted. + /// Remove/RemoveRange/Clear (first source)If the item was in the result, a Remove is emitted. + /// Remove/RemoveRange/Clear (other source)If the item exists in the first source and no longer in any other, an Add is emitted. + /// ReplaceTreated as a Remove of the old item plus an Add of the new item, with set logic re-evaluated. + /// MovedIgnored by the set logic (no positional semantics). + /// RefreshForwarded if the item is currently in the result set. + /// OnErrorForwarded from any source. + /// OnCompletedForwarded when all sources have completed. + /// + /// Worth noting: Unlike , the first source is asymmetric: only its items can appear in the result. + /// + /// + /// + /// public static IObservable> Except(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -613,52 +745,57 @@ public static IObservable> Except(this IObservable - /// Apply a logical Except operator between the collections. - /// Items which are in the source and not in the others are included in the result. - /// - /// The type of the item. - /// The sources. - /// An observable which emits the change set. + /// + /// + /// Static overload accepting a pre-built collection of sources. The first item in the collection is the primary source. + /// public static IObservable> Except(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.Except); - /// - /// Dynamically apply a logical Except operator. Items from the first observable list are included when an equivalent item does not exist in the other sources. - /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// + /// + /// Dynamic overload: sources can be added or removed from the at runtime. The first source in the list acts as the primary. + /// public static IObservable> Except(this IObservableList>> sources) where T : notnull => sources.Combine(CombineOperator.Except); - /// - /// Dynamically apply a logical Except operator. Items from the first observable list are included when an equivalent item does not exist in the other sources. - /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// + /// + /// Dynamic overload accepting of . Each inner list's Connect() is used as a source. + /// public static IObservable> Except(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.Except); - /// - /// Dynamically apply a logical Except operator. Items from the first observable list are included when an equivalent item does not exist in the other sources. - /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// + /// + /// Dynamic overload accepting of . Each inner list's Connect() is used as a source. + /// public static IObservable> Except(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.Except); /// - /// Removes items from the cache according to the value specified by the time selector function. + /// Automatically removes items from the list after the duration returned by . + /// Returns an observable of the items that were expired and removed. /// /// The type of the item. - /// The source. - /// Selector returning when to expire the item. Return null for non-expiring item. - /// Enter the polling interval to optimise expiry timers, if omitted 1 timer is created for each unique expiry time. - /// The scheduler. - /// An observable which emits the enumerable of items. + /// The source list to monitor and remove expired items from. + /// A function returning the time-to-live for each item. Return null for items that should never expire. + /// Optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. + /// The scheduler for scheduling expiry timers. Defaults to . + /// An observable that emits collections of items each time expired items are removed from the source list. + /// + /// + /// This operator acts directly on an , not on a changeset stream. It monitors items as they are added, + /// schedules their removal, and physically removes them from the source list when their time expires. + /// + /// + /// When is specified, all items due for removal are batched into a single removal at each polling tick, + /// which can improve performance when many items expire around the same time. + /// + /// Worth noting: The returned observable emits the expired items (not changesets). Subscribe to this observable to trigger the expiry mechanism; if not subscribed, no items will be removed. + /// + /// + /// public static IObservable> ExpireAfter( this ISourceList source, Func timeSelector, @@ -672,14 +809,33 @@ public static IObservable> ExpireAfter( scheduler: scheduler); /// - /// Filters items, statically, in a list stream, based on a given predicate. + /// Filters items from the source list changeset stream using a static predicate. + /// Only items satisfying are included downstream. /// /// The type of items in the list. - /// The list stream whose items are to be filtered. - /// A static predicate to be used to determine which items should be included or excluded by the filter. - /// A list stream, containing only the items matched by . - /// Throws for and . - /// Note that, unlike some other overloads of this operator, ordering of items is preserved. + /// The source list changeset stream to filter. + /// A predicate that determines which items are included. Items returning true appear downstream; items returning false are excluded. + /// A list changeset stream containing only items that satisfy . + /// Thrown when or is null. + /// + /// Use this overload when the predicate is fixed for the lifetime of the subscription. Item ordering is preserved. + /// + /// EventBehavior + /// AddThe predicate is evaluated. If the item passes, an Add is emitted at the calculated downstream index. Otherwise dropped. + /// AddRangeEach item in the range is evaluated. Matching items are emitted as an AddRange. + /// ReplaceThe predicate is re-evaluated. Four outcomes: both pass produces Replace; new passes but old didn't produces Add; old passed but new doesn't produces Remove; neither passes is dropped. + /// RemoveIf the item was included downstream, a Remove is emitted. Otherwise dropped. + /// RemoveRangeIncluded items in the range are emitted as individual Remove changes. + /// RefreshThe predicate is re-evaluated. If the item now passes but previously did not, an Add is emitted. If it previously passed but no longer does, a Remove is emitted. If still passes, the Refresh is forwarded. If still fails, dropped. + /// ClearAll downstream items are cleared. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// Worth noting: Refresh events trigger re-evaluation, which can promote or demote items (turning a Refresh into an Add or Remove). Pair with for property-change-driven filtering. + /// + /// + /// + /// public static IObservable> Filter( this IObservable> source, Func predicate) @@ -690,16 +846,36 @@ public static IObservable> Filter( suppressEmptyChangesets: true); /// - /// Filters source using the specified filter observable predicate. + /// Filters items using a dynamically changing predicate. + /// When emits a new function, all items are re-evaluated. /// /// The type of the item. - /// The source. - /// The predicate which indicates which items should be included. - /// Should the filter clear and replace, or calculate a diff-set. - /// An observable which emits the change set. - /// source - /// or - /// filterController. + /// The source list changeset stream. + /// An observable that emits new predicate functions. Each emission triggers a full re-evaluation of all items. + /// Controls re-filtering behavior: CalculateDiff (default) computes the minimal diff between old and new results; ClearAndReplace clears and repopulates entirely. + /// A list changeset stream containing only items that satisfy the most recent predicate. + /// + /// + /// Each time emits, every item is re-evaluated. The controls + /// whether this produces a minimal diff (Add/Remove for items that changed status) or a full Clear+AddRange. + /// + /// + /// EventBehavior + /// AddThe current predicate is evaluated. If the item passes, an Add is emitted. Otherwise dropped. + /// AddRangeEach item is evaluated. Matching items are emitted as AddRange. + /// ReplaceRe-evaluated. Same four-outcome logic as the static overload (Replace, Add, Remove, or dropped). + /// RemoveIf the item was downstream, a Remove is emitted. Otherwise dropped. + /// RefreshRe-evaluated. If inclusion status changed, an Add or Remove is emitted. If unchanged, Refresh forwarded or dropped. + /// ClearAll downstream items are cleared. + /// Predicate changedAll items re-evaluated against the new predicate. With CalculateDiff, only items that changed status emit Add/Remove. With ClearAndReplace, a Clear is emitted followed by AddRange of all matching items. + /// OnErrorForwarded from the source or from . + /// OnCompletedForwarded when the source completes. Independent completion of does not terminate the filter. + /// + /// Worth noting: No items are included until emits its first function. CalculateDiff is generally preferred for performance; ClearAndReplace is useful when downstream consumers (like UI bindings) handle full resets more efficiently than individual changes. + /// + /// or is null. + /// + /// public static IObservable> Filter(this IObservable> source, IObservable> predicate, ListFilterPolicy filterPolicy = ListFilterPolicy.CalculateDiff) where T : notnull { @@ -711,20 +887,38 @@ public static IObservable> Filter(this IObservable - /// Creates a filtered stream which can be dynamically filtered, based on state values passed through to a static filtering predicate. + /// Filters items using a predicate that receives external state. When emits a new state value, + /// all items are re-evaluated against using the updated state. /// /// The type of the item. /// The type of state value required by . - /// The source. + /// The source list changeset stream. /// A stream of state values to be passed to . - /// A static predicate to be used to determine which items should be included or excluded by the filter. - /// The policy that the operator should use when performing re-filtering operations. - /// By default empty changeset notifications are suppressed for performance reasons. Set to false to publish empty changesets. Doing so can be useful for monitoring loading status. - /// An observable which emits change sets. - /// Throws for , , and . + /// A predicate receiving the current state and an item, returning true to include or false to exclude. + /// Controls re-filtering behavior: CalculateDiff (default) computes minimal diff; ClearAndReplace clears and repopulates. + /// When true (default), empty changesets are suppressed. Set to false to publish empty changesets (useful for monitoring loading status). + /// A list changeset stream containing only items satisfying with the current state. + /// , , or is null. /// - /// Usually, should emit an initial value, immediately upon subscription. This is because cannot be invoked until the first state value is received, and accordingly, the operator will treat all items as excluded until then. Each value emitted by will trigger a full re-filtering of the entire collection, according to . + /// + /// The predicate cannot be invoked until the first state value is received. Until then, all items are treated as excluded. + /// Each subsequent state emission triggers a full re-evaluation of all items according to . + /// + /// + /// EventBehavior + /// Add/AddRangeEvaluated using current state. Matching items emitted as Add/AddRange. + /// ReplaceRe-evaluated. Same four-outcome logic as the static filter (Replace, Add, Remove, or dropped). + /// Remove/RemoveRangeIf the item was downstream, a Remove is emitted. + /// RefreshRe-evaluated against current state. Inclusion status may change. + /// ClearAll downstream items are cleared. + /// State changedAll items re-evaluated with new state value. CalculateDiff emits minimal Add/Remove; ClearAndReplace emits Clear then AddRange. + /// OnErrorForwarded from the source or from . + /// OnCompletedForwarded when the source completes. + /// + /// Worth noting: should emit an initial value immediately upon subscription. No items are included until the first state value arrives. /// + /// + /// public static IObservable> Filter( this IObservable> source, IObservable predicateState, @@ -740,15 +934,39 @@ public static IObservable> Filter( suppressEmptyChangeSets: suppressEmptyChangeSets); /// - /// Filters source on the specified observable property using the specified predicate. - /// The filter will automatically reapply when a property changes. + /// Filters each item using a per-item of that dynamically controls inclusion. + /// When an item's observable emits true the item enters the result; when it emits false the item is removed. /// /// The type of the object. - /// The source. - /// The filter property selector. When the observable changes the filter will be re-evaluated. - /// The property changed throttle. - /// The scheduler used when throttling. - /// An observable which emits the change set. + /// The source list changeset stream. + /// A function that returns an observable of for each item, controlling its inclusion. + /// Optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. + /// The scheduler used when throttling. Defaults to the system default scheduler. + /// A list changeset stream containing only items whose per-item observable most recently emitted true. + /// or is null. + /// + /// + /// Each item in the source gets its own subscription to the observable returned by . + /// The item's inclusion is determined by the most recent boolean value emitted by that observable. + /// + /// + /// Source changeset eventBehavior + /// Add/AddRangeSubscribes to the per-item observable. Item is included when it first emits true. + /// ReplaceOld subscription disposed, new subscription created for the replacement item. + /// Remove/RemoveRange/ClearSubscription disposed. If the item was downstream, a Remove is emitted. + /// RefreshForwarded if the item is currently included. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// Per-item observable eventBehavior + /// Emits trueIf not already included, an Add is emitted downstream. + /// Emits falseIf currently included, a Remove is emitted downstream. + /// + /// + /// + /// + /// public static IObservable> FilterOnObservable(this IObservable> source, Func> objectFilterObservable, TimeSpan? propertyChangedThrottle = null, IScheduler? scheduler = null) where TObject : notnull { @@ -758,17 +976,21 @@ public static IObservable> FilterOnObservable(this } /// - /// Filters source on the specified property using the specified predicate. - /// The filter will automatically reapply when a property changes. + /// Filters items based on a property value, automatically re-evaluating when the specified property changes on any item. /// - /// The type of the object. + /// The type of the object. Must implement . /// The type of the property. - /// The source. - /// The property selector. When the property changes the filter specified will be re-evaluated. - /// A predicate based on the object which contains the changed property. - /// The property changed throttle. + /// The source list changeset stream. + /// Expression selecting the property to monitor for changes. + /// A predicate evaluated against the item to determine inclusion. + /// Optional throttle duration for property change notifications. /// The scheduler used when throttling. - /// An observable which emits the change set. + /// A list changeset stream of items satisfying the predicate, re-evaluated on property changes. + /// + /// Deprecated. Use followed by instead. + /// + /// + /// [Obsolete("Use AutoRefresh(), followed by Filter() instead")] public static IObservable> FilterOnProperty(this IObservable> source, Expression> propertySelector, Func predicate, TimeSpan? propertyChangedThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged @@ -783,21 +1005,35 @@ public static IObservable> FilterOnProperty - /// Convert the result of a buffer operation to a change set. + /// Flattens a buffered list of changesets (from Rx's Buffer operator) back into a single changeset stream. + /// Empty buffers are dropped. /// /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// The buffered source of changeset lists. + /// A list changeset stream with all buffered changes concatenated into single changesets. + /// + /// Use this after applying Observable.Buffer() to a changeset stream to re-merge the batched changesets into a single stream. + /// + /// + /// public static IObservable> FlattenBufferResult(this IObservable>> source) where T : notnull => source.Where(x => x.Count != 0).Select(updates => new ChangeSet(updates.SelectMany(u => u))); /// - /// Provides a call back for each item change. + /// Invokes for every in each changeset, including range changes as-is. + /// The changeset is forwarded downstream unchanged. /// /// The type of the object. - /// The source. - /// The action. - /// An observable which emits the change set. + /// The source list changeset stream. + /// The action invoked for each . Range changes (AddRange, RemoveRange, Clear) are received as a single with a populated Range property. + /// A continuation of the source changeset stream. + /// or is null. + /// + /// This is a side-effect operator. It does not modify the changeset. If you need each individual item from range operations flattened out, use instead. + /// + /// + /// + /// public static IObservable> ForEachChange(this IObservable> source, Action> action) where TObject : notnull { @@ -809,13 +1045,21 @@ public static IObservable> ForEachChange(this IObse } /// - /// Provides a call back for each item change. - /// Range changes are flattened, so there is only need to check for Add, Replace, Remove and Clear. + /// Invokes for every individual in each changeset. + /// Range changes are flattened into individual item changes first, so the callback only receives Add, Replace, Remove, and Refresh. /// /// The type of the object. - /// The source. - /// The action. - /// An observable which emits the change set. + /// The source list changeset stream. + /// The action invoked for each individual item change. + /// A continuation of the source changeset stream. + /// or is null. + /// + /// + /// Unlike , this operator flattens + /// AddRange, RemoveRange, and Clear into individual entries before invoking the callback. + /// + /// + /// public static IObservable> ForEachItemChange(this IObservable> source, Action> action) where TObject : notnull { @@ -827,20 +1071,35 @@ public static IObservable> ForEachItemChange(this I } /// - /// Groups the source on the value returned by group selector factory. The groupings contains an inner observable list. + /// Groups source items by the value returned by . Each group is an + /// containing an inner observable list of its members. /// /// The type of the object. - /// The type of the group. - /// The source. - /// The group selector. - /// Force the grouping function to recalculate the group value. - /// For example if you have a time based grouping with values like `Last Minute', 'Last Hour', 'Today' etc regrouper is used to refresh these groupings. - /// An observable which emits the change set. - /// - /// source - /// or - /// groupSelector. - /// + /// The type of the group key. + /// The source list changeset stream. + /// A function that returns the group key for each item. + /// Optional observable that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). + /// A list changeset stream of objects, each containing the items belonging to that group. + /// or is null. + /// + /// + /// Groups are created lazily and removed when empty. Each group exposes an inner observable list that receives incremental updates. + /// + /// + /// EventBehavior + /// Add/AddRangeGroup key evaluated. Item added to its group. If the group is new, an Add of the group is emitted. + /// ReplaceGroup key re-evaluated. If the group changed, the item is removed from the old group and added to the new one. Empty old groups are removed. + /// Remove/RemoveRange/ClearItem removed from its group. Empty groups are removed from the result. + /// RefreshGroup key re-evaluated. If changed, the item moves between groups. + /// MovedNot handled by group logic. + /// Regrouper firesAll items re-evaluated. Items that changed group key are moved between groups. Empty groups removed, new groups added. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// + /// + /// public static IObservable>> GroupOn(this IObservable> source, Func groupSelector, IObservable? regrouper = null) where TObject : notnull where TGroup : notnull @@ -853,17 +1112,26 @@ public static IObservable>> GroupOn - /// Groups the source using the property specified by the property selector. The resulting groupings contains an inner observable list. - /// Groups are re-applied when the property value changed. - /// When there are likely to be a large number of group property changes specify a throttle to improve performance. + /// Groups items by a property value, automatically re-grouping when the specified property changes on any item. + /// Each group contains an inner observable list. /// - /// The type of the object. - /// The type of the group. - /// The source. - /// The property selector used to group the items. - /// The property changed throttle. - /// The scheduler. - /// An observable which emits the change set. + /// The type of the object. Must implement . + /// The type of the group key. + /// The source list changeset stream. + /// Expression selecting the property whose value determines the group key. + /// Optional throttle duration for property change notifications. + /// The scheduler used when throttling. + /// A list changeset stream of objects. + /// or is null. + /// + /// + /// Convenience operator equivalent to .AutoRefresh(propertySelector).GroupOn(item => property). + /// Property changes trigger re-evaluation of the group key, potentially moving items between groups. + /// + /// + /// + /// + /// public static IObservable>> GroupOnProperty(this IObservable> source, Expression> propertySelector, TimeSpan? propertyChangedThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged where TGroup : notnull @@ -876,17 +1144,27 @@ public static IObservable>> GroupOnProperty - /// Groups the source using the property specified by the property selector. The resulting groupings are immutable. - /// Groups are re-applied when the property value changed. - /// When there are likely to be a large number of group property changes specify a throttle to improve performance. + /// Groups items by a property value, automatically re-grouping when the specified property changes. + /// Each group emits immutable snapshots (not live observable lists). /// - /// The type of the object. - /// The type of the group. - /// The source. - /// The property selector used to group the items. - /// The property changed throttle. - /// The scheduler. - /// An observable which emits the change set. + /// The type of the object. Must implement . + /// The type of the group key. + /// The source list changeset stream. + /// Expression selecting the property whose value determines the group key. + /// Optional throttle duration for property change notifications. + /// The scheduler used when throttling. + /// A list changeset stream of immutable group snapshots. + /// or is null. + /// + /// + /// Combines + /// with . + /// Unlike , + /// this produces immutable snapshots per group rather than live inner observable lists. + /// + /// + /// + /// public static IObservable>> GroupOnPropertyWithImmutableState(this IObservable> source, Expression> propertySelector, TimeSpan? propertyChangedThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged where TGroup : notnull @@ -899,20 +1177,25 @@ public static IObservable>> GroupOnProperty - /// Groups the source on the value returned by group selector factory. Each update produces immutable grouping. + /// Groups source items by the value returned by . Each update produces immutable grouping snapshots + /// rather than live inner observable lists. /// /// The type of the object. /// The type of the group key. - /// The source. - /// The group selector key. - /// Force the grouping function to recalculate the group value. - /// For example if you have a time based grouping with values like `Last Minute', 'Last Hour', 'Today' etc regrouper is used to refresh these groupings. - /// An observable which emits the change set. - /// - /// source - /// or - /// groupSelectorKey. - /// + /// The source list changeset stream. + /// A function that returns the group key for each item. + /// Optional observable that forces all items to be re-evaluated when it fires. + /// A list changeset stream of immutable snapshots. + /// or is null. + /// + /// + /// Works like + /// but each affected group emits a new immutable snapshot on every change rather than updating a live inner list. + /// This is useful when consumers need thread-safe, point-in-time snapshots of each group. + /// + /// + /// + /// public static IObservable>> GroupWithImmutableState(this IObservable> source, Func groupSelectorKey, IObservable? regrouper = null) where TObject : notnull where TGroupKey : notnull @@ -925,16 +1208,26 @@ public static IObservable>> GroupOnProperty - /// Limits the size of the source cache to the specified limit. - /// Notifies which items have been removed from the source list. + /// Limits the source list to a maximum number of items using FIFO eviction. + /// When the list exceeds , the oldest items are removed. + /// Returns an observable of the items that were removed. /// /// The type of the item. - /// The source. - /// The size limit. - /// The scheduler. - /// An observable which emits a enumerable of items. - /// source. - /// sizeLimit cannot be zero. + /// The source list to monitor and evict items from. + /// The maximum number of items allowed. Must be greater than zero. + /// The scheduler for scheduling size checks. Defaults to . + /// An observable that emits collections of items each time excess items are removed from the source list. + /// is null. + /// is zero or negative. + /// + /// + /// This operator acts directly on an . It subscribes to the source's changes, + /// tracks insertion order using an internal Transform, and removes the oldest items when the size limit is exceeded. + /// + /// Worth noting: The returned observable emits the removed items (not changesets). Subscribe to this observable to activate the size-limiting mechanism. Removal is performed synchronously under a lock shared with the change tracking. + /// + /// + /// public static IObservable> LimitSizeTo(this ISourceList source, int sizeLimit, IScheduler? scheduler = null) where T : notnull { @@ -952,17 +1245,33 @@ public static IObservable> LimitSizeTo(this ISourceList sou } /// - /// Dynamically merges the observable which is selected from each item in the stream, and un-merges the item - /// when it is no longer part of the stream. + /// Subscribes to a per-item observable for each item in the source and merges all emissions into a single stream. + /// This is NOT a changeset operator: it returns a flat observable of values. /// - /// The type of the object. - /// The type of the destination. - /// The source. - /// The observable selector. - /// An observable which emits the destination value. - /// source - /// or - /// observableSelector. + /// The type of items in the source list. + /// The type of values emitted by per-item observables. + /// The source list changeset stream. + /// A function that returns an observable for each source item. + /// An observable that emits values from all per-item observables, merged together. + /// or is null. + /// + /// + /// Internally uses to manage per-item subscriptions. + /// When an item is added, a new subscription is created via . When removed or replaced, the old subscription is disposed. + /// + /// + /// Source changeset eventSubscription behavior + /// Add/AddRangeSubscribes to the per-item observable. Emissions are merged into the output. + /// ReplaceOld subscription disposed, new subscription created for the replacement item. + /// Remove/RemoveRange/ClearSubscription disposed. + /// Refresh/MovedNo effect on subscriptions. + /// OnCompleted (source)Completes only after the source and all active inner observables have completed. + /// OnErrorForwarded from the source or from any per-item observable. + /// + /// + /// + /// + /// public static IObservable MergeMany(this IObservable> source, Func> observableSelector) where T : notnull { @@ -974,13 +1283,35 @@ public static IObservable MergeMany(this IObserva } /// - /// Operator similiar to Merge except it is ChangeSet aware. All of the observable changesets are merged together into a single stream of ChangeSet events. + /// Merges multiple list changeset streams from an observable-of-observables into a single unified changeset stream. + /// Unlike cache MergeChangeSets, list merging performs no key-based deduplication. /// /// The type of the object. - /// The Source Observable ChangeSet. - /// instance to determine if two elements are the same. - /// The result from merging the changesets together. - /// Parameter was null. + /// An observable that emits list changeset observables to be merged. + /// Optional used by the merge tracker to compare items. + /// A single list changeset stream containing all changes from all inner streams. + /// is null. + /// + /// + /// Uses ChangeSetMergeTracker internally. All changes from inner streams are forwarded to the output. + /// Replace changes are decomposed into a Remove of the old item followed by an Add of the new item. + /// Moved changes from inner streams are ignored. + /// + /// + /// EventBehavior + /// Add/AddRangeForwarded to the merged output. + /// ReplaceDecomposed into Remove (old) + Add (new). + /// Remove/RemoveRange/ClearForwarded to the merged output. + /// RefreshForwarded to the merged output. + /// MovedIgnored. + /// OnErrorForwarded from any inner source. + /// OnCompletedForwarded when all inner sources have completed. + /// + /// Worth noting: There is no key-based deduplication. If the same item appears in multiple inner streams, it will appear multiple times in the merged output. + /// + /// + /// + /// public static IObservable> MergeChangeSets(this IObservable>> source, IEqualityComparer? equalityComparer = null) where TObject : notnull { @@ -989,17 +1320,15 @@ public static IObservable> MergeChangeSets(this IOb return new MergeChangeSets(source, equalityComparer).Run(); } + /// /// - /// Operator similiar to Merge except it is ChangeSet aware. Merges both observable changesets into a single stream of ChangeSet events. + /// Merges two list changeset streams into a single unified stream. /// - /// The type of the object. - /// The Source Observable ChangeSet. - /// The Other Observable ChangeSet. - /// instance to determine if two elements are the same. - /// (Optional) instance to use when enumerating the collection. - /// Whether or not the result Observable should complete if all the changesets complete. - /// The result from merging the changesets together. - /// Parameter was null. + /// The first list changeset stream. + /// The second list changeset stream to merge with. + /// Optional used to compare items. + /// Optional for scheduling enumeration. + /// When true (default), the result completes when all sources complete. public static IObservable> MergeChangeSets(this IObservable> source, IObservable> other, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull { @@ -1009,17 +1338,15 @@ public static IObservable> MergeChangeSets(this IOb return new[] { source, other }.MergeChangeSets(equalityComparer, scheduler, completable); } + /// /// - /// Operator similiar to Merge except it is ChangeSet aware. Merges the source changeset and the collection of other changesets together into a single stream of ChangeSet events. + /// Merges the source list changeset stream with additional changeset streams into a single unified stream. /// - /// The type of the object. - /// The Source Observable ChangeSet. - /// The Other Observable ChangeSets. - /// instance to determine if two elements are the same. - /// (Optional) instance to use when enumerating the collection. - /// Whether or not the result Observable should complete if all the changesets complete. - /// The result from merging the changesets together. - /// Parameter was null. + /// The primary list changeset stream. + /// Additional list changeset streams to merge with. + /// Optional used to compare items. + /// Optional for scheduling enumeration. + /// When true (default), the result completes when all sources complete. public static IObservable> MergeChangeSets(this IObservable> source, IEnumerable>> others, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull { @@ -1030,15 +1357,24 @@ public static IObservable> MergeChangeSets(this IOb } /// - /// Operator similiar to Merge except it is ChangeSet aware. All of the observable changesets are merged together into a single stream of ChangeSet events. + /// Merges a collection of list changeset streams into a single unified changeset stream. + /// This is the primary overload that all other list MergeChangeSets overloads delegate to. /// /// The type of the object. - /// The Source Observable ChangeSet. - /// instance to determine if two elements are the same. - /// (Optional) instance to use when enumerating the collection. - /// Whether or not the result Observable should complete if all the changesets complete. - /// The result from merging the changesets together. - /// Parameter was null. + /// The collection of list changeset streams to merge. + /// Optional used by the merge tracker to compare items. + /// Optional for scheduling enumeration. + /// When true (default), the result completes when all sources complete. + /// A single list changeset stream containing all changes from all sources. + /// is null. + /// + /// + /// Uses ChangeSetMergeTracker internally. Replace is decomposed into Remove + Add. Moved is ignored. + /// There is no key-based deduplication (unlike cache MergeChangeSets). + /// + /// + /// + /// public static IObservable> MergeChangeSets(this IEnumerable>> source, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull { @@ -1047,14 +1383,10 @@ public static IObservable> MergeChangeSets(this IEn return new MergeChangeSets(source, equalityComparer, completable, scheduler).Run(); } + /// /// - /// Merges all of the Cache Observable ChangeSets into a single ChangeSets that correctly handles removal of the parent items. + /// Merges list changeset streams from an into a single stream. Sources can be added or removed dynamically. /// - /// The type of the object. - /// The SourceList of Observable Cache ChangeSets. - /// Optional instance to determine if two elements are the same. - /// The result from merging the child changesets together. - /// Parameter was null. public static IObservable> MergeChangeSets(this IObservableList>> source, IEqualityComparer? equalityComparer = null) where TObject : notnull { @@ -1063,14 +1395,11 @@ public static IObservable> MergeChangeSets(this IOb return source.Connect().MergeChangeSets(equalityComparer); } + /// /// - /// Merges each Observable ChangeSet in the ObservableList into a single stream of ChangeSets that correctly handles removal of the parent items. + /// Merges list changeset streams from a list-of-list-changeset-observables into a single stream. + /// Each inner list changeset observable in the source list is merged, and parent item removal triggers child cleanup. /// - /// The type of the object. - /// The List Observable ChangeSet of Cache Observable ChangeSets. - /// Optional instance to determine if two elements are the same. - /// The result from merging the child changesets together. - /// Parameter was null. public static IObservable> MergeChangeSets(this IObservable>>> source, IEqualityComparer? equalityComparer = null) where TObject : notnull { @@ -1080,14 +1409,20 @@ public static IObservable> MergeChangeSets(this IOb } /// - /// Merges each Observable ChangeSet in the ObservableList into a single stream of ChangeSets that correctly handles multiple Keys and removal of the parent items. + /// Merges cache changeset streams from an into a single cache changeset stream. + /// Uses to resolve conflicts when the same key appears in multiple child streams. /// /// The type of the object. /// The type of the object key. - /// The SourceList of Observable Cache ChangeSets. - /// instance to determine which element to emit if the same key is emitted from multiple child changesets. - /// The result from merging the child changesets together. - /// Parameter was null. + /// The observable list of cache changeset observables. + /// to resolve which value wins when the same key appears in multiple sources. + /// A single cache changeset stream with key-based deduplication. + /// is null. + /// + /// Sources can be added or removed dynamically from the observable list. Parent item removal triggers cleanup of all child items from that source. + /// + /// + /// public static IObservable> MergeChangeSets(this IObservableList>> source, IComparer comparer) where TObject : notnull where TKey : notnull @@ -1097,16 +1432,13 @@ public static IObservable> MergeChangeSets /// - /// Merges all of the Cache Observable ChangeSets into a single ChangeSets while correctly handling multiple Keys and removal of the parent items. + /// Merges cache changeset streams from an into a single cache changeset stream, with optional equality and ordering comparers. /// - /// The type of the object. - /// The type of the object key. - /// The SourceList of Observable Cache ChangeSets. - /// Optional instance to determine if two elements are the same. - /// Optional instance to determine which element to emit if the same key is emitted from multiple child changesets. - /// The result from merging the child changesets together. - /// Parameter was null. + /// The observable list of cache changeset observables. + /// Optional to determine if two elements are the same. + /// Optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservableList>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) where TObject : notnull where TKey : notnull @@ -1116,15 +1448,12 @@ public static IObservable> MergeChangeSets /// - /// Merges all of the Cache Observable ChangeSets into a single ChangeSets while correctly handling multiple Keys and removal of the parent items. + /// Merges cache changeset streams from a list changeset of cache changeset observables, using a comparer for conflict resolution. /// - /// The type of the object. - /// The type of the object key. - /// The List Observable ChangeSet of Cache Observable ChangeSets. - /// instance to determine which element to emit if the same key is emitted from multiple child changesets. - /// The result from merging the child changesets together. - /// Parameter was null. + /// The list changeset stream whose items are cache changeset observables. + /// to resolve which value wins when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IComparer comparer) where TObject : notnull where TKey : notnull @@ -1134,16 +1463,13 @@ public static IObservable> MergeChangeSets /// - /// Merges each Observable ChangeSet in the ObservableList into a single stream of ChangeSets that correctly handles multiple Keys and removal of the parent items. + /// Merges cache changeset streams from a list changeset of cache changeset observables, with optional equality and ordering comparers. /// - /// The type of the object. - /// The type of the object key. - /// The List Observable ChangeSet of Cache Observable ChangeSets. - /// Optional instance to determine if two elements are the same. - /// Optional instance to determine which element to emit if the same key is emitted from multiple child changesets. - /// The result from merging the child changesets together. - /// Parameter was null. + /// The list changeset stream whose items are cache changeset observables. + /// Optional to determine if two elements are the same. + /// Optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) where TObject : notnull where TKey : notnull @@ -1154,15 +1480,33 @@ public static IObservable> MergeChangeSets - /// Operator similiar to MergeMany except it is List ChangeSet aware. It uses to transform each item in the source into a child and merges the result children together into a single stream of ChangeSets that correctly handles removal of the parent items and other changes to the source list. + /// Transforms each source item into a child list changeset stream using , + /// then merges all child streams into a single flat list changeset stream. Parent item removal cleans up all associated children. /// - /// The type of the object. - /// The type of the destination. - /// The Source Observable ChangeSet. - /// Factory Function used to create child changesets. - /// Optional instance to determine if two elements are the same. - /// The result from merging the children list changesets together. - /// Parameter was null. + /// The type of items in the source list. + /// The type of items in the child changeset streams. + /// The source list changeset stream. + /// A function that returns a child list changeset stream for each source item. + /// Optional used to compare child items. + /// A single list changeset stream containing all items from all child streams. + /// or is null. + /// + /// + /// Internally subscribes to each child stream when a source item is added and disposes the subscription when it is removed. + /// All child items from a removed parent are removed from the merged output. + /// + /// + /// Source changeset eventBehavior + /// Add/AddRangeSubscribes to the child stream. Child emissions are merged into the output. + /// ReplaceOld child subscription disposed (and its items removed from output). New child subscription created. + /// Remove/RemoveRange/ClearChild subscription disposed. All child items from that parent are removed. + /// OnErrorForwarded from the source or any child stream. + /// OnCompletedForwarded when the source completes. + /// + /// + /// + /// + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TDestination : notnull @@ -1181,16 +1525,21 @@ public static IObservable> MergeManyChangeSets - /// Operator similiar to MergeMany except it is Cache ChangeSet aware. It uses to transform each item in the source into a child and merges the result children together into a single stream of ChangeSets that correctly handles multiple Keys and removal of the parent items. + /// Transforms each source item into a child cache changeset stream and merges all children into a single cache changeset stream. + /// Uses to resolve key conflicts when the same key appears in multiple child streams. /// - /// The type of the object. - /// The type of the destination. - /// The type of the destination key. - /// The Source Observable ChangeSet. - /// Factory Function used to create child changesets. - /// instance to determine which element to emit if the same key is emitted from multiple child changesets. - /// The result from merging the child changesets together. - /// Parameter was null. + /// The type of items in the source list. + /// The type of items in the child cache changeset streams. + /// The type of the key in the child cache changesets. + /// The source list changeset stream. + /// A function that returns a child cache changeset stream for each source item. + /// to resolve which value wins when the same key appears from multiple children. + /// A single cache changeset stream with key-based deduplication. + /// , , or is null. + /// + /// Delegates to with a null equality comparer. + /// + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IComparer comparer) where TObject : notnull where TDestination : notnull @@ -1204,17 +1553,27 @@ public static IObservable> MergeManyCh } /// - /// Operator similiar to MergeMany except it is Cache ChangeSet aware. It uses to transform each item in the source into a child and merges the result children together into a single stream of ChangeSets that correctly handles multiple Keys and removal of the parent items. + /// Transforms each source item into a child cache changeset stream and merges all children into a single cache changeset stream. + /// This is the primary list-to-cache MergeManyChangeSets overload. /// - /// The type of the object. - /// The type of the destination. - /// The type of the destination key. - /// The Source Observable ChangeSet. - /// Factory Function used to create child changesets. - /// Optional instance to determine if two elements are the same. - /// Optional instance to determine which element to emit if the same key is emitted from multiple child changesets. - /// The result from merging the child changesets together. - /// Parameter was null. + /// The type of items in the source list. + /// The type of items in the child cache changeset streams. + /// The type of the key in the child cache changesets. + /// The source list changeset stream. + /// A function that returns a child cache changeset stream for each source item. + /// Optional to determine if two elements are the same. + /// Optional to resolve conflicts when the same key appears from multiple children. + /// A single cache changeset stream with key-based deduplication. + /// or is null. + /// + /// + /// Each source item produces a keyed child stream via . All child items are tracked by key. + /// When a parent item is removed, all its child items are removed from the merged output. + /// When the same key appears from multiple children, determines which value wins. + /// + /// + /// + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) where TObject : notnull where TDestination : notnull @@ -1227,12 +1586,14 @@ public static IObservable> MergeManyCh } /// - /// Prevents an empty notification. + /// Suppresses empty changesets from the stream. Only changesets with at least one change are forwarded. /// /// The type of the item. - /// The source. - /// An observable which emits the change set. - /// source. + /// The source list changeset stream. + /// A list changeset stream with empty changesets filtered out. + /// is null. + /// + /// public static IObservable> NotEmpty(this IObservable> source) where T : notnull { @@ -1242,14 +1603,30 @@ public static IObservable> NotEmpty(this IObservable - /// Invokes a given action for every item added to the source list stream. + /// Invokes for every item added to the source list stream. + /// Triggers on , , and the new item of . /// /// The type of items in the list. - /// The list stream whose items are to be passed to . - /// The action to invoke upon each added item. - /// A list stream, containing all items in , with changes published after has been invoked. - /// Throws for and . - /// Note that "added" items includes items from , , and changes. + /// The source list changeset stream. + /// The action to invoke for each added item. + /// A continuation of the source changeset stream, with the side effect applied before forwarding. + /// or is null. + /// + /// The action fires before the changeset is forwarded downstream. + /// + /// EventBehavior + /// AddCallback invoked with the added item. Changeset forwarded. + /// AddRangeCallback invoked for each item in the range. Changeset forwarded. + /// ReplaceCallback invoked for the new (replacement) item. Changeset forwarded. + /// Remove/RemoveRange/ClearNo callback. Changeset forwarded. + /// Moved/RefreshNo callback. Changeset forwarded. + /// OnErrorForwarded. If callback throws, propagates as OnError. + /// OnCompletedForwarded. + /// + /// + /// + /// + /// public static IObservable> OnItemAdded( this IObservable> source, Action addAction) @@ -1259,14 +1636,16 @@ public static IObservable> OnItemAdded( addAction: addAction); /// - /// Invokes a given action for every item refreshed within the source list stream. + /// Invokes for every item with a change in the source stream. /// /// The type of items in the list. - /// The list stream whose items are to be passed to . - /// The action to invoke upon each refreshed item. - /// A list stream, containing all items in , with changes published after has been invoked. - /// Throws for and . - /// Note that "refreshed" items refers to items from changes. + /// The source list changeset stream. + /// The action to invoke for each refreshed item. + /// A continuation of the source changeset stream, with the side effect applied before forwarding. + /// or is null. + /// + /// + /// public static IObservable> OnItemRefreshed( this IObservable> source, Action refreshAction) @@ -1276,15 +1655,35 @@ public static IObservable> OnItemRefreshed( refreshAction: refreshAction); /// - /// Invokes a given action for every item removed from the source list stream. + /// Invokes for every item removed from the source list stream. + /// Triggers on , , , and the old item of . /// /// The type of items in the list. - /// The list stream whose items are to be passed to . - /// The action to invoke upon each removed item. - /// A flag indicating whether should be invoked upon teardown of the stream. This includes disposal of subscriptions, completion notifications, and error notifications. - /// A list stream, containing all items in , with changes published after has been invoked. - /// Throws for and . - /// Note that "removed" items includes items from , , , and changes. + /// The source list changeset stream. + /// The action to invoke for each removed item. + /// When true (default), is also invoked for all remaining tracked items upon stream disposal, completion, or error. + /// A continuation of the source changeset stream, with the side effect applied before forwarding. + /// or is null. + /// + /// + /// When is true, the operator tracks all items that have been added but not yet removed, + /// and fires for each of them during finalization. This is useful for resource cleanup patterns. + /// + /// + /// EventBehavior + /// Add/AddRangeTracked internally (when is true). No callback invoked. Changeset forwarded. + /// ReplaceCallback invoked for the previous (replaced) item. New item tracked. Changeset forwarded. + /// RemoveCallback invoked for the removed item. Changeset forwarded. + /// RemoveRange/ClearCallback invoked for each removed item. Changeset forwarded. + /// Moved/RefreshNo callback. Changeset forwarded. + /// OnErrorIf is true, callback is invoked for all tracked items before the error propagates. + /// OnCompletedIf is true, callback is invoked for all tracked items before completion propagates. + /// + /// Worth noting: When is true (the default), disposing the subscription also invokes the callback for every item still in the list, not just items that were explicitly removed during the subscription. Exceptions in are not caught. + /// + /// + /// + /// public static IObservable> OnItemRemoved( this IObservable> source, Action removeAction, @@ -1295,24 +1694,42 @@ public static IObservable> OnItemRemoved( removeAction: removeAction, invokeOnUnsubscribe: invokeOnUnsubscribe); + /// /// - /// Apply a logical Or operator between the collections. - /// Items which are in any of the sources are included in the result. + /// Applies a logical OR (union) between a pre-built collection of list changeset sources. Items present in any source are included. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Or(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.Or); /// - /// Apply a logical Or operator between the collections. - /// Items which are in any of the sources are included in the result. + /// Applies a logical OR (union) between the source and other list changeset streams. + /// Items present in any of the sources are included in the result, using reference-counted equality. /// /// The type of the item. - /// The source. - /// The others. - /// An observable which emits the change set. + /// The primary source list changeset stream. + /// The other list changeset streams to combine with. + /// A list changeset stream containing items that exist in at least one source. + /// is null. + /// + /// + /// Uses reference-counted equality comparison. An item is included when it first appears in any source and removed when it no longer exists in any source. + /// Moved changes are ignored by the set logic. + /// + /// + /// EventBehavior + /// Add/AddRange (any source)If the item is new to the result, an Add is emitted. Otherwise the reference count is incremented. + /// Remove/RemoveRange/Clear (any source)Reference count decremented. If count reaches zero, a Remove is emitted. + /// ReplaceOld item reference count decremented, new item reference count incremented. Add/Remove emitted as needed. + /// RefreshForwarded if the item is in the result set. + /// MovedIgnored. + /// OnErrorForwarded from any source. + /// OnCompletedForwarded when all sources have completed. + /// + /// + /// + /// + /// + /// public static IObservable> Or(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -1321,43 +1738,46 @@ public static IObservable> Or(this IObservable> s return source.Combine(CombineOperator.Or, others); } + /// /// - /// Dynamically apply a logical Or operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. + /// Dynamic OR: sources can be added or removed from the at runtime. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Or(this IObservableList>> sources) where T : notnull => sources.Combine(CombineOperator.Or); + /// /// - /// Dynamically apply a logical Or operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. + /// Dynamic OR accepting of . Each inner list's Connect() is used as a source. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Or(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.Or); + /// /// - /// Dynamically apply a logical Or operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. + /// Dynamic OR accepting of . Each inner list's Connect() is used as a source. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Or(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.Or); /// - /// Applies paging to the data source. + /// Applies page-based windowing to the source list. Only items within the current page (determined by page number and page size from ) are included downstream. /// /// The type of the item. - /// The source. - /// Observable to control page requests. - /// An observable which emits the change set. + /// The source list changeset stream. + /// An observable of controlling which page to display (page number and page size). + /// An stream containing only items within the current page window. + /// or is null. + /// + /// + /// Maintains the full source list internally and calculates the page window on each change or page request. + /// Items entering the page window produce Add; items leaving produce Remove. A new page request triggers + /// a full recalculation of the page contents. + /// + /// Worth noting: The source should ideally be sorted before paging, as list order determines page contents. Duplicate items are removed from the result via Distinct(). + /// + /// + /// + /// public static IObservable> Page(this IObservable> source, IObservable requests) where T : notnull { @@ -1368,17 +1788,18 @@ public static IObservable> Page(this IObservable - /// list. + /// Subscribes to the source changeset stream and pipes all changes into the . /// /// The type of the object. - /// The source. - /// The destination. - /// An observable which emits the change set. - /// - /// source - /// or - /// destination. - /// + /// The source list changeset stream. + /// The target source list to receive all changes. + /// An representing the subscription. Dispose to stop piping changes. + /// or is null. + /// + /// Each changeset is applied to the destination using Clone() inside an Edit() call, producing a single batch update per changeset. + /// + /// + /// public static IDisposable PopulateInto(this IObservable> source, ISourceList destination) where T : notnull { @@ -1389,18 +1810,20 @@ public static IDisposable PopulateInto(this IObservable> source } /// - /// The latest copy of the cache is exposed for querying after each modification to the underlying data. + /// Emits a projected value from the current list snapshot after every changeset. + /// The receives an representing the current state. /// - /// The type of the object. - /// The type of the destination. - /// The source. - /// The result selector. - /// An observable which emits the destination value. - /// - /// source - /// or - /// resultSelector. - /// + /// The type of items in the list. + /// The type of the projected result. + /// The source list changeset stream. + /// A function projecting the current list snapshot to a result value. + /// An observable emitting the projected value after each changeset. + /// or is null. + /// + /// Delegates to and applies via Select. + /// + /// + /// public static IObservable QueryWhenChanged(this IObservable> source, Func, TDestination> resultSelector) where TObject : notnull { @@ -1411,12 +1834,19 @@ public static IObservable QueryWhenChanged( } /// - /// The latest copy of the cache is exposed for querying i) after each modification to the underlying data ii) upon subscription. + /// Emits an snapshot of the current list state after every changeset. + /// Maintains an internal list updated by cloning each changeset. /// - /// The type of the object. - /// The source. - /// An observable which emits the read only collection. - /// source. + /// The type of items in the list. + /// The source list changeset stream. + /// An observable emitting the full list snapshot as after each change. + /// is null. + /// + /// This is a non-changeset operator. It emits the entire collection state on each change, not incremental diffs. + /// + /// + /// + /// public static IObservable> QueryWhenChanged(this IObservable> source) where T : notnull { @@ -1426,11 +1856,17 @@ public static IObservable> QueryWhenChanged(this IObse } /// - /// List equivalent to Publish().RefCount(). The source is cached so long as there is at least 1 subscriber. + /// Reference-counted materialization of the source changeset stream into an . + /// The shared list is created on the first subscriber and disposed when the last subscriber unsubscribes. /// /// The type of the item. - /// The source. - /// An observable which emits the change set. + /// The source list changeset stream. + /// A list changeset stream backed by a shared, reference-counted . + /// is null. + /// + /// Equivalent to Publish().RefCount() for changeset streams. The underlying list is created lazily on first subscription. + /// + /// public static IObservable> RefCount(this IObservable> source) where T : notnull { @@ -1440,12 +1876,15 @@ public static IObservable> RefCount(this IObservable - /// Removes the index from all changes. - /// NB: This operator has been introduced as a temporary fix for creating an Or operator using merge many. + /// Strips index information from all changes in the stream using YieldWithoutIndex. /// /// The type of the object. - /// The source. - /// An observable which emits the change set. + /// The source list changeset stream. + /// A list changeset stream with all index values removed from changes. + /// is null. + /// + /// This is a workaround operator introduced for internal use (e.g., creating Or operators via MergeMany). Most consumers should not need this. + /// public static IObservable> RemoveIndex(this IObservable> source) where T : notnull { @@ -1455,16 +1894,16 @@ public static IObservable> RemoveIndex(this IObservable - /// Reverse sort of the change set. + /// Reverses the order of items in the changeset stream by transforming all indices: new_index = length - old_index - 1. /// /// The type of the item. - /// The source. - /// An observable which emits the change set. - /// - /// source - /// or - /// comparer. - /// + /// The source list changeset stream. + /// A list changeset stream with all index positions reversed. + /// is null. + /// + /// This is a pure index transformation. The items themselves are unchanged; only their positional indices are inverted. + /// + /// public static IObservable> Reverse(this IObservable> source) where T : notnull { @@ -1475,12 +1914,15 @@ public static IObservable> Reverse(this IObservable - /// Defer the subscription until loaded and skip initial change set. + /// Skips the initial changeset (the snapshot emitted on subscription) and forwards all subsequent changesets. + /// Internally defers until loaded, then skips the first emission. /// /// The type of the object. - /// The source. - /// An observable which emits the change set. - /// source. + /// The source list changeset stream. + /// A list changeset stream that omits the initial snapshot. + /// is null. + /// + /// public static IObservable> SkipInitial(this IObservable> source) where T : notnull { @@ -1490,19 +1932,38 @@ public static IObservable> SkipInitial(this IObservable - /// Sorts the sequence using the specified comparer. + /// Sorts the list using the specified comparer, maintaining a sorted output that incrementally updates as items change. /// /// The type of the item. - /// The source. + /// The source list changeset stream. /// The comparer used for sorting. - /// For improved performance, specify SortOptions.UseBinarySearch. This can only be used when the values which are sorted on are immutable. - /// OnNext of this observable causes data to resort. This is required when the value which is sorted on mutable. - /// An observable comparer used to change the comparer on which the sorted list i. - /// Since sorting can be slow for large record sets, the reset threshold is used to force the list re-ordered. - /// An observable which emits the change set. - /// source - /// or - /// comparer. + /// Sort options. Use for improved performance when sorted values are immutable. + /// Optional observable that forces a full re-sort when it fires. Required when sorted property values are mutable. + /// Optional observable that replaces the comparer, triggering a full re-sort. + /// When the number of changes exceeds this threshold, a full reset is performed instead of incremental updates. Default is 50. + /// A list changeset stream with items in sorted order. + /// or is null. + /// + /// + /// Maintains an internal sorted ChangeAwareList. Each incoming change is applied incrementally: adds are inserted at the correct sorted position, + /// removes are removed by index, and refreshes re-evaluate position (emitting Moved if changed). + /// + /// + /// EventBehavior + /// Add/AddRangeInserted at the correct sorted position. May trigger a full reset if the count exceeds . + /// ReplaceOld item removed, new item inserted at sorted position. + /// Remove/RemoveRange/ClearRemoved from sorted list. + /// RefreshSort position re-evaluated. If position changed, a Moved is emitted. + /// Comparer changedFull re-sort of all items. + /// Resort signalFull re-sort using the current comparer. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// Worth noting: is faster but requires that the values being sorted on never mutate. If they do, use the signal or . + /// + /// + /// + /// public static IObservable> Sort(this IObservable> source, IComparer comparer, SortOptions options = SortOptions.None, IObservable? resort = null, IObservable>? comparerChanged = null, int resetThreshold = 50) where T : notnull { @@ -1512,19 +1973,15 @@ public static IObservable> Sort(this IObservable> return new Sort(source, comparer, options, resort, comparerChanged, resetThreshold).Run(); } + /// /// - /// Sorts the sequence using the specified observable comparer. + /// Sorts the list using an observable comparer. The initial comparer is taken from the first emission; subsequent emissions trigger a full re-sort. /// - /// The type of the item. - /// The source. - /// An observable comparer used to change the comparer on which the sorted list i. - /// For improved performance, specify SortOptions.UseBinarySearch. This can only be used when the values which are sorted on are immutable. - /// OnNext of this observable causes data to resort. This is required when the value which is sorted on mutable. - /// Since sorting can be slow for large record sets, the reset threshold is used to force the list re-ordered. - /// An observable which emits the change set. - /// source - /// or - /// comparer. + /// The source list changeset stream. + /// An observable that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. + /// Sort options. + /// Optional observable to force a re-sort with the current comparer. + /// Threshold for triggering a full reset instead of incremental updates. public static IObservable> Sort(this IObservable> source, IObservable> comparerChanged, SortOptions options = SortOptions.None, IObservable? resort = null, int resetThreshold = 50) where T : notnull { @@ -1535,27 +1992,39 @@ public static IObservable> Sort(this IObservable> } /// - /// Prepends an empty change set to the source. + /// Prepends an empty changeset to the source stream. Useful for initializing downstream consumers that expect an initial emission. /// /// The type of item. - /// The source observable of change set values. - /// An observable which emits a change set. + /// The source list changeset stream. + /// A list changeset stream that begins with an empty changeset. + /// + /// public static IObservable> StartWithEmpty(this IObservable> source) where T : notnull => source.StartWith(ChangeSet.Empty); /// - /// Subscribes to each item when it is added to the stream and unsubscribes when it is removed. All items will be unsubscribed when the stream is disposed. + /// Creates an subscription for each item via when it is added. + /// The subscription is disposed when the item is removed or replaced. All subscriptions are disposed when the stream terminates. + /// The changeset is forwarded downstream unmodified. /// /// The type of the object. - /// The source. - /// The subscription function. - /// An observable which emits the change set. - /// source - /// or - /// subscriptionFactory. + /// The source list changeset stream. + /// A function that creates an for each item. + /// A continuation of the source changeset stream with per-item subscriptions managed as a side effect. + /// or is null. /// - /// Subscribes to each item when it is added or updates and unsubscribes when it is removed. + /// + /// EventBehavior + /// Add/AddRangeSubscription created for each item via the factory. Changeset forwarded. + /// ReplaceOld item's subscription disposed, new subscription created. Changeset forwarded. + /// Remove/RemoveRange/ClearSubscriptions for removed items are disposed. Changeset forwarded. + /// Moved/RefreshForwarded. No subscription changes. + /// OnError/OnCompleted/DisposalAll active subscriptions are disposed. + /// /// + /// + /// + /// public static IObservable> SubscribeMany(this IObservable> source, Func subscriptionFactory) where T : notnull { @@ -1566,26 +2035,27 @@ public static IObservable> SubscribeMany(this IObservable - /// Suppress refresh notifications. + /// Suppresses all changes from the stream. All other change reasons pass through. /// /// The type of the object. - /// The source observable change set. - /// An observable which emits the change set. + /// The source list changeset stream. + /// A list changeset stream with Refresh changes removed. + /// + /// public static IObservable> SuppressRefresh(this IObservable> source) where T : notnull => source.WhereReasonsAreNot(ListChangeReason.Refresh); /// - /// Transforms an observable sequence of observable lists into a single sequence - /// producing values only from the most recent observable sequence. - /// Each time a new inner observable sequence is received, unsubscribe from the - /// previous inner observable sequence and clear the existing result set. + /// Subscribes to the latest inner , switching to each new source and clearing the result when switching. /// /// The type of the object. - /// The source. - /// - /// The observable sequence that at any point in time produces the elements of the most recent inner observable sequence that has been received. - /// - /// is null. + /// An observable that emits instances. Each emission triggers a switch to the new list. + /// A list changeset stream reflecting the most recently received inner list. + /// is null. + /// + /// Convenience overload that calls Connect() on each inner list, then delegates to . + /// + /// public static IObservable> Switch(this IObservable> sources) where T : notnull { @@ -1595,17 +2065,20 @@ public static IObservable> Switch(this IObservable - /// Transforms an observable sequence of observable changes sets into an observable sequence - /// producing values only from the most recent observable sequence. - /// Each time a new inner observable sequence is received, unsubscribe from the - /// previous inner observable sequence and clear the existing result set. + /// Subscribes to the latest inner changeset stream, switching to each new source and clearing the destination when switching. + /// Previous subscriptions are disposed and the result set is emptied before subscribing to the new inner stream. /// /// The type of the object. - /// The source. - /// - /// The observable sequence that at any point in time produces the elements of the most recent inner observable sequence that has been received. - /// - /// is null. + /// An observable that emits changeset observables. Each emission triggers a switch to the new stream. + /// A list changeset stream reflecting the most recently received inner changeset stream. + /// is null. + /// + /// + /// On each new inner stream, the operator clears the destination, disposes the previous subscription, and subscribes to the new stream. + /// This is the changeset-aware equivalent of Rx's Switch(). + /// + /// + /// public static IObservable> Switch(this IObservable>> sources) where T : notnull { @@ -1615,23 +2088,35 @@ public static IObservable> Switch(this IObservable - /// Converts the change set into a fully formed collection. Each change in the source results in a new collection. + /// Emits the full collection as an after every changeset. Equivalent to QueryWhenChanged(items => items). /// /// The type of the object. - /// The source. - /// An observable which emits the read only collection. + /// The source list changeset stream. + /// An observable emitting the full collection snapshot after each change. + /// + /// public static IObservable> ToCollection(this IObservable> source) where TObject : notnull => source.QueryWhenChanged(items => items); /// - /// Converts the observable to an observable change set. - /// Change set observes observable change events. + /// Bridges an into the DynamicData world by converting each emitted item into a list changeset. + /// Each emission becomes an Add operation in the resulting changeset stream. /// /// The type of the object. - /// The source. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of individual items. + /// Optional scheduler for time-based operations (expiry, size limiting). + /// A list changeset stream where each source emission is an Add. + /// is null. + /// + /// + /// This is the primary bridge from standard Rx into DynamicData's list changeset model. Each item emitted by + /// is added to an internal list and an Add changeset is emitted. The list grows unboundedly unless size or time limits + /// are specified via other overloads. + /// + /// Worth noting: Source completion and errors are propagated. The internal list is disposed on unsubscribe. + /// + /// + /// public static IObservable> ToObservableChangeSet( this IObservable source, IScheduler? scheduler = null) @@ -1642,16 +2127,14 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: -1, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set, allowing time expiry to be specified. - /// Change set observes observable change events. + /// Bridges an into a list changeset stream with per-item time-based expiry. + /// Expired items are automatically removed. /// - /// The type of the object. - /// The source. - /// Specify on a per object level the maximum time before an object expires from a cache. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of individual items. + /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// Optional scheduler for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable source, Func expireAfter, @@ -1663,16 +2146,14 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: -1, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set, with a specified limit of how large the list can be. - /// Change set observes observable change events. + /// Bridges an into a list changeset stream with FIFO size limiting. + /// When the list exceeds , the oldest items are removed. /// - /// The type of the object. - /// The source. - /// Remove the oldest items when the size has reached this limit. Supply -1 to disable size limiting. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of individual items. + /// Maximum list size. Supply -1 to disable size limiting. + /// Optional scheduler for scheduling removals. public static IObservable> ToObservableChangeSet( this IObservable source, int limitSizeTo, @@ -1684,17 +2165,14 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: limitSizeTo, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set, allowing size and time limit to be specified. - /// Change set observes observable change events. + /// Bridges an into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The type of the object. - /// The source. - /// Specify on a per object level the maximum time before an object expires from a cache. - /// Remove the oldest items when the size has reached this limit. Supply -1 to disable size limiting. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of individual items. + /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// Maximum list size. Supply -1 to disable size limiting. + /// Optional scheduler for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( this IObservable source, Func? expireAfter, @@ -1707,15 +2185,13 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: limitSizeTo, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set. - /// Change set observes observable change events. + /// Bridges an of batches into a list changeset stream. + /// Each emitted batch becomes an AddRange. /// - /// The type of the object. - /// The source. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of item batches. + /// Optional scheduler for time-based operations. public static IObservable> ToObservableChangeSet( this IObservable> source, IScheduler? scheduler = null) @@ -1726,16 +2202,13 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: -1, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set, allowing size and time limit to be specified. - /// Change set observes observable change events. + /// Bridges an of batches into a list changeset stream with FIFO size limiting. /// - /// The type of the object. - /// The source. - /// Remove the oldest items when the size has reached this limit. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of item batches. + /// Maximum list size. Oldest items are removed when the limit is exceeded. + /// Optional scheduler for scheduling removals. public static IObservable> ToObservableChangeSet( this IObservable> source, int limitSizeTo, @@ -1747,16 +2220,13 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: limitSizeTo, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set, allowing size to be specified. - /// Change set observes observable change events. + /// Bridges an of batches into a list changeset stream with time-based expiry. /// - /// The type of the object. - /// The source. - /// Specify on a per object level the maximum time before an object expires from a cache. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source. + /// The source observable of item batches. + /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// Optional scheduler for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable> source, Func expireAfter, @@ -1768,19 +2238,14 @@ public static IObservable> ToObservableChangeSet( limitSizeTo: -1, scheduler: scheduler); + /// /// - /// Converts the observable to an observable change set, allowing size and time limit to be specified. - /// Change set observes observable change events. + /// Bridges an of batches into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The type of the object. - /// The source. - /// Specify on a per object level the maximum time before an object expires from a cache. - /// Remove the oldest items when the size has reached this limit. - /// The scheduler (only used for time expiry). - /// An observable which emits a change set. - /// source - /// or - /// keySelector. + /// The source observable of item batches. + /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// Maximum list size. Oldest items removed when exceeded. + /// Optional scheduler for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( this IObservable> source, Func? expireAfter, @@ -1794,12 +2259,20 @@ public static IObservable> ToObservableChangeSet( scheduler: scheduler); /// - /// Limits the size of the result set to the specified number of items. + /// Takes the first items from the source list. Implemented as Virtualise with a fixed window starting at index 0. /// /// The type of the item. - /// The source. - /// The number of items. - /// An observable which emits the change set. + /// The source list changeset stream. + /// The maximum number of items to include. Must be greater than zero. + /// A virtual changeset stream containing at most items from the beginning of the source. + /// is null. + /// is zero or negative. + /// + /// The source should ideally be sorted before applying Top, since list order determines which items appear. + /// + /// + /// + /// public static IObservable> Top(this IObservable> source, int numberOfItems) where T : notnull { @@ -1814,24 +2287,29 @@ public static IObservable> Top(this IObservable> } /// - /// Converts the change set into a fully formed sorted collection. Each change in the source results in a new sorted collection. + /// Emits a sorted after every changeset, sorted by the value returned by . /// /// The type of the object. - /// The sort key. - /// The source. - /// The sort function. - /// The sort order. Defaults to ascending. - /// An observable which emits the read only collection. + /// The type of the sort key. + /// The source list changeset stream. + /// A function extracting the sort key from each item. + /// The sort direction. Defaults to ascending. + /// An observable emitting a sorted collection snapshot after each change. + /// + /// + /// public static IObservable> ToSortedCollection(this IObservable> source, Func sort, SortDirection sortOrder = SortDirection.Ascending) where TObject : notnull => source.QueryWhenChanged(query => sortOrder == SortDirection.Ascending ? new ReadOnlyCollectionLight(query.OrderBy(sort)) : new ReadOnlyCollectionLight(query.OrderByDescending(sort))); /// - /// Converts the change set into a fully formed sorted collection. Each change in the source results in a new sorted collection. + /// Emits a sorted after every changeset, sorted using the specified . /// /// The type of the object. - /// The source. - /// The sort comparer. - /// An observable which emits the read only collection. + /// The source list changeset stream. + /// The comparer used for sorting. + /// An observable emitting a sorted collection snapshot after each change. + /// + /// public static IObservable> ToSortedCollection(this IObservable> source, IComparer comparer) where TObject : notnull => source.QueryWhenChanged( query => @@ -1842,19 +2320,38 @@ public static IObservable> ToSortedCollection - /// Projects each update item to a new form using the specified transform function. + /// Projects each item to a new form using a synchronous transform function. /// /// The type of the source. /// The type of the destination. - /// The source. - /// The transform factory. - /// Should a new transform be applied when a refresh event is received. - /// An observable which emits the change set. - /// - /// source - /// or - /// valueSelector. - /// + /// The source list changeset stream. + /// The transform function applied to each item. + /// When true, Refresh events re-invoke the factory and emit an update. When false (the default), Refresh is forwarded without re-transforming. + /// A list changeset stream of transformed items. + /// + /// + /// Maintains an internal list of transformed items via ChangeAwareList. Each source changeset is + /// processed and a corresponding output changeset is produced with the transformed items. + /// + /// + /// EventBehavior + /// AddThe factory is called and an Add is emitted at the same index. + /// AddRangeThe factory is called for each item. An AddRange is emitted at the same start index. + /// ReplaceThe factory is called for the new item. A Replace is emitted at the same index. The previous transformed value is available to overloads that accept Optional<TDestination>. + /// RemoveA Remove is emitted (no factory call). + /// RemoveRangeA RemoveRange is emitted. + /// MovedA Moved is emitted with updated indices (no factory call). + /// RefreshIf is false (default), the Refresh is forwarded without re-transforming. If true, the factory is re-invoked and the result replaces the current value. + /// ClearA Clear is emitted and the internal list is emptied. + /// OnErrorForwarded. If the factory throws, the exception propagates as OnError. + /// OnCompletedForwarded to the downstream observer. + /// + /// Worth noting: By default, Refresh does NOT re-transform the item (it just forwards the signal). Set to true if you need the factory re-invoked on Refresh. Add operations with out-of-bounds indices silently append to the end. + /// + /// or is null. + /// + /// + /// public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -1866,20 +2363,13 @@ public static IObservable> Transform((t, _, _) => transformFactory(t), transformOnRefresh); } + /// /// - /// Projects each update item to a new form using the specified transform function. + /// Projects each item using a transform function that also receives the item's index. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform function. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// + /// The source list changeset stream. + /// A function receiving the source item and its index, returning the transformed item. + /// When true, Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -1890,21 +2380,14 @@ public static IObservable> Transform((t, _, idx) => transformFactory(t, idx), transformOnRefresh); } + /// /// - /// Projects each update item to a new form using the specified transform function. - /// *** Annoyingly when using this overload you will have to explicitly specify the generic type arguments as type inference fails. + /// Projects each item using a transform function that also receives the previously transformed value (if any). + /// Type arguments must be specified explicitly as type inference fails for this overload. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform function. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// + /// The source list changeset stream. + /// A function receiving the source item and the previous transformed value (as ), returning the new transformed item. + /// When true, Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -1915,21 +2398,14 @@ public static IObservable> Transform((t, previous, _) => transformFactory(t, previous), transformOnRefresh); } + /// /// - /// Projects each update item to a new form using the specified transform function. - /// *** Annoyingly when using this overload you will have to explicitly specify the generic type arguments as type inference fails. + /// Projects each item using a transform function that receives the source item, the previously transformed value, and the index. + /// Type arguments must be specified explicitly as type inference fails for this overload. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform factory. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// + /// The source list changeset stream. + /// A function receiving the source item, previous transformed value, and index. + /// When true, Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, int, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -1941,19 +2417,31 @@ public static IObservable> Transform - /// Projects each update item to a new form using the specified transform function. + /// Projects each item to a new form using an async transform function. Behaves like but the factory returns a . /// /// The type of the source. /// The type of the destination. - /// The source. - /// The transform factory. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// + /// The source list changeset stream. + /// An async function that transforms each source item. + /// When true, Refresh events re-invoke the factory. + /// A list changeset stream of asynchronously transformed items. + /// or is null. + /// + /// Change handling is identical to the synchronous except the factory is awaited. Operations are serialized per changeset via a semaphore. + /// + /// EventBehavior + /// Add/AddRangeThe async factory is awaited for each item. An Add/AddRange is emitted with the transformed results. + /// ReplaceThe async factory is awaited for the new item. A Replace is emitted. + /// Remove/RemoveRangeEmitted without invoking the factory. + /// MovedEmitted with updated indices (no factory call). + /// RefreshIf is false (default), forwarded without re-transforming. If true, the factory is re-awaited. + /// ClearEmitted and internal list cleared. + /// OnErrorForwarded. If the async factory throws, the exception propagates as OnError. + /// OnCompletedForwarded after the last changeset is processed. + /// + /// Worth noting: All async transforms within a single changeset are serialized (not parallel). Each changeset is fully processed before the next begins. By default, Refresh does NOT re-transform. + /// + /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design.")] public static IObservable> TransformAsync( this IObservable> source, @@ -1968,20 +2456,10 @@ public static IObservable> TransformAsync((t, _, _) => transformFactory(t), transformOnRefresh); } + /// /// - /// Projects each update item to a new form using the specified transform function. + /// Async transform overload receiving the source item and its index. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform factory. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design.")] public static IObservable> TransformAsync( this IObservable> source, @@ -1996,20 +2474,10 @@ public static IObservable> TransformAsync((t, _, i) => transformFactory(t, i), transformOnRefresh); } + /// /// - /// Projects each update item to a new form using the specified transform function. + /// Async transform overload receiving the source item and the previously transformed value. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform factory. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design.")] public static IObservable> TransformAsync( this IObservable> source, @@ -2024,20 +2492,10 @@ public static IObservable> TransformAsync((t, d, _) => transformFactory(t, d), transformOnRefresh); } + /// /// - /// Projects each update item to a new form using the specified transform function. + /// Async transform overload receiving the source item, previously transformed value, and index. This is the terminal overload that all other TransformAsync overloads delegate to. /// - /// The type of the source. - /// The type of the destination. - /// The source. - /// The transform factory. - /// Should a new transform be applied when a refresh event is received. - /// A an observable change set of the transformed object. - /// - /// source - /// or - /// valueSelector. - /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design.")] public static IObservable> TransformAsync( this IObservable> source, @@ -2053,19 +2511,29 @@ public static IObservable> TransformAsync - /// Equivalent to a select many transform. To work, the key must individually identify each child. + /// Flattens each source item into multiple destination items using . Each source item produces zero or more children, + /// all of which are merged into a single flat list changeset stream. /// - /// The type of the destination. - /// The type of the source. - /// The source. - /// The selector function which selects the enumerable. - /// Used when an item has been replaced to determine whether child items are the same as previous children. - /// An observable which emits the change set. - /// - /// source - /// or - /// manySelector. - /// + /// The type of the destination items. + /// The type of the source items. + /// The source list changeset stream. + /// A function that returns the child items for each source item. + /// Optional comparer used during Replace to determine which child items changed between old and new parent values. + /// A list changeset stream of all child items from all source items. + /// or is null. + /// + /// + /// EventBehavior + /// Add/AddRangeChildren expanded and added to the output. + /// ReplaceOld children diffed against new children (using ). Removed, added, or kept as appropriate. + /// Remove/RemoveRange/ClearAll children of the removed parents are removed from the output. + /// RefreshChildren re-expanded and diffed. + /// OnErrorForwarded to the downstream observer. + /// OnCompletedForwarded to the downstream observer. + /// + /// + /// + /// public static IObservable> TransformMany(this IObservable> source, Func> manySelector, IEqualityComparer? equalityComparer = null) where TDestination : notnull where TSource : notnull @@ -2076,52 +2544,47 @@ public static IObservable> TransformMany(source, manySelector, equalityComparer).Run(); } + /// /// - /// Flatten the nested observable collection, and observe subsequently observable collection changes. + /// Flattens each source item into children from an . The collection is observed for subsequent changes. /// - /// The type of the destination. - /// The type of the source. - /// The source. - /// The selector function which selects the enumerable. - /// Used when an item has been replaced to determine whether child items are the same as previous children. - /// An observable which emits the change set. public static IObservable> TransformMany(this IObservable> source, Func> manySelector, IEqualityComparer? equalityComparer = null) where TDestination : notnull where TSource : notnull => new TransformMany(source, manySelector, equalityComparer).Run(); + /// /// - /// Flatten the nested observable collection, and observe subsequently observable collection changes. + /// Flattens each source item into children from a . The collection is observed for subsequent changes. /// - /// The type of the destination. - /// The type of the source. - /// The source. - /// The selector function which selects the enumerable. - /// Used when an item has been replaced to determine whether child items are the same as previous children. - /// An observable which emits the change set. public static IObservable> TransformMany(this IObservable> source, Func> manySelector, IEqualityComparer? equalityComparer = null) where TDestination : notnull where TSource : notnull => new TransformMany(source, manySelector, equalityComparer).Run(); + /// /// - /// Flatten the nested observable list, and observe subsequent observable collection changes. + /// Flattens each source item into children from an . The inner list is observed for subsequent changes. /// - /// The type of the destination. - /// The type of the source. - /// The source. - /// The selector function which selects the enumerable. - /// Used when an item has been replaced to determine whether child items are the same as previous children. - /// An observable which emits the change set. public static IObservable> TransformMany(this IObservable> source, Func> manySelector, IEqualityComparer? equalityComparer = null) where TDestination : notnull where TSource : notnull => new TransformMany(source, manySelector, equalityComparer).Run(); /// - /// Virtualises the source using parameters provided via the requests observable. + /// Applies a sliding window to the source list using start index and size from . + /// Only items within the window are included downstream. /// /// The type of the item. - /// The source. - /// The requests. - /// An observable which emits the change set. + /// The source list changeset stream. + /// An observable of specifying the start index and size of the window. + /// An stream containing only items within the current virtual window. + /// or is null. + /// + /// + /// Like but uses absolute start index and size instead of page number and page size. + /// Internally maintains the full source list and recalculates the window on each change or request. + /// + /// + /// + /// public static IObservable> Virtualise(this IObservable> source, IObservable requests) where T : notnull { @@ -2133,12 +2596,21 @@ public static IObservable> Virtualise(this IObservable - /// Watches each item in the collection and notifies when any of them has changed. + /// Watches all items in the source list and emits the item when any of its properties change. + /// Requires to implement . + /// This is NOT a changeset operator: it returns a flat . /// - /// The type of the object. - /// The source. - /// specify properties to Monitor, or omit to monitor all property changes. - /// An observable which emits the object. + /// The type of the object. Must implement . + /// The source list changeset stream. + /// Optional list of property names to monitor. If empty, all property changes are observed. + /// An observable emitting the item whenever any monitored property changes. + /// is null. + /// + /// Implemented via . Subscriptions are managed per item: created on add, disposed on remove. + /// + /// + /// + /// public static IObservable WhenAnyPropertyChanged(this IObservable> source, params string[] propertiesToMonitor) where TObject : INotifyPropertyChanged { @@ -2148,14 +2620,22 @@ public static IObservable> Virtualise(this IObservable - /// Watches each item in the collection and notifies when any of them has changed. + /// Watches a specific property on all items in the source list and emits a (item + value pair) when it changes. + /// Requires to implement . + /// This is NOT a changeset operator: it returns a flat . /// - /// The type of object. - /// The type of the value. - /// The source. - /// The property accessor. - /// If true the resulting observable includes the initial value. - /// An observable which emits the property value. + /// The type of item. Must implement . + /// The type of the property value. + /// The source list changeset stream. + /// An expression selecting the property to observe. + /// When true (default), the current value is emitted immediately upon subscribing to each item. + /// An observable emitting whenever the property changes on any tracked item. + /// or is null. + /// + /// Implemented via . + /// + /// + /// public static IObservable> WhenPropertyChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) where TObject : INotifyPropertyChanged { @@ -2167,14 +2647,19 @@ public static IObservable> WhenPropertyChanged - /// Watches each item in the collection and notifies when any of them has changed. + /// Watches a specific property on all items and emits just the property value (without the sender) when it changes. + /// Requires to implement . + /// This is NOT a changeset operator: it returns a flat . /// - /// The type of object. - /// The type of the value. - /// The source. - /// The property accessor. - /// If true the resulting observable includes the initial value. - /// An observable which emits the value. + /// The type of item. Must implement . + /// The type of the property value. + /// The source list changeset stream. + /// An expression selecting the property to observe. + /// When true (default), the current value is emitted immediately upon subscribing to each item. + /// An observable emitting the property value whenever it changes on any tracked item. + /// or is null. + /// + /// public static IObservable WhenValueChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) where TObject : INotifyPropertyChanged { @@ -2186,13 +2671,28 @@ public static IObservable> WhenPropertyChanged - /// Includes changes for the specified reasons only. + /// Filters the changeset stream to include only changes with the specified values. + /// Index information is stripped from the output (via YieldWithoutIndex). /// /// The type of the item. - /// The source. - /// The reasons. - /// An observable which emits the change set. - /// Must enter at least 1 reason. + /// The source list changeset stream. + /// The change reasons to include. Must specify at least one. + /// A list changeset stream containing only changes with the specified reasons. + /// is null. + /// is empty. + /// + /// Filters individual changes within each changeset. If filtering removes all changes from a changeset, the empty changeset is suppressed via . + /// + /// EventBehavior + /// Any matching reasonThe change is included in the output. Index information is stripped. + /// Any non-matching reasonThe change is dropped from the output. + /// OnErrorForwarded. + /// OnCompletedForwarded. + /// + /// Worth noting: Filtering out Remove changes can cause downstream operators to accumulate items indefinitely (memory leak). Index information is stripped because removing some changes invalidates the original index positions. + /// + /// + /// public static IObservable> WhereReasonsAre(this IObservable> source, params ListChangeReason[] reasons) where T : notnull { @@ -2213,13 +2713,23 @@ public static IObservable> WhereReasonsAre(this IObservable - /// Excludes updates for the specified reasons. + /// Filters the changeset stream to exclude changes with the specified values. + /// Index information is stripped from the output (via YieldWithoutIndex), except when only filtering out . /// /// The type of the item. - /// The source. - /// The reasons. - /// An observable which emits the change set. - /// Must enter at least 1 reason. + /// The source list changeset stream. + /// The change reasons to exclude. Must specify at least one. + /// A list changeset stream with the specified change reasons removed. + /// is null. + /// is empty. + /// + /// + /// Empty changesets (after filtering) are automatically suppressed. When only is excluded, + /// indices are preserved (no YieldWithoutIndex), since removing Refresh does not affect index calculations. + /// + /// + /// + /// public static IObservable> WhereReasonsAreNot(this IObservable> source, params ListChangeReason[] reasons) where T : notnull { @@ -2250,13 +2760,34 @@ public static IObservable> WhereReasonsAreNot(this IObservable< } /// - /// Apply a logical Xor operator between the collections. - /// Items which are only in one of the sources are included in the result. + /// Applies a logical XOR (symmetric difference) between the source and other streams. + /// Items present in exactly one source are included in the result. /// /// The type of the item. - /// The source. - /// The others. - /// An observable which emits the change set. + /// The primary source list changeset stream. + /// The other list changeset streams to combine with. + /// A list changeset stream containing items that exist in exactly one source. + /// is null. + /// + /// + /// Uses reference-counted equality. An item is included when it exists in exactly one source. + /// If it appears in a second source, it is removed from the result. If it then leaves one source, + /// it re-enters the result. Moved changes are ignored. + /// + /// + /// EventBehavior + /// Add/AddRangeReference count updated. If the item is now in exactly one source, an Add is emitted. If now in two or more, a Remove is emitted. + /// Remove/RemoveRange/ClearReference count decremented. If now in exactly one source, an Add is emitted. If now in zero, a Remove is emitted. + /// ReplaceOld item reference count decremented, new item incremented, with Xor logic applied. + /// RefreshForwarded if item is in the result set. + /// MovedIgnored. + /// OnErrorForwarded from any source. + /// OnCompletedForwarded when all sources have completed. + /// + /// + /// + /// + /// public static IObservable> Xor(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -2265,43 +2796,31 @@ public static IObservable> Xor(this IObservable> return source.Combine(CombineOperator.Xor, others); } + /// /// - /// Apply a logical Xor operator between the collections. - /// Items which are only in one of the sources are included in the result. + /// Applies a logical XOR between a pre-built collection of list changeset sources. /// - /// The type of the item. - /// The sources. - /// An observable which emits the change set. public static IObservable> Xor(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.Xor); + /// /// - /// Dynamically apply a logical Xor operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. + /// Dynamic XOR: sources can be added or removed from the at runtime. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Xor(this IObservableList>> sources) where T : notnull => sources.Combine(CombineOperator.Xor); + /// /// - /// Dynamically apply a logical Xor operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. + /// Dynamic XOR accepting of . Each inner list's Connect() is used as a source. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Xor(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.Xor); + /// /// - /// Dynamically apply a logical Xor operator between the items in the outer observable list. - /// Items which are in any of the sources are included in the result. + /// Dynamic XOR accepting of . Each inner list's Connect() is used as a source. /// - /// The type of the item. - /// The source. - /// An observable which emits the change set. public static IObservable> Xor(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.Xor); From 25e479efaf9428397738b5d11edc2a9b75bf7e2d Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 13 Apr 2026 20:03:07 -0700 Subject: [PATCH 02/22] docs: add event tables to remaining list operators Add event behavior tables to OnItemAdded, OnItemRemoved, ForEachChange, WhereReasonsAre, TransformAsync, QueryWhenChanged, and other operators that were missing them. Fix last old-style param description. --- src/DynamicData/List/ObservableListEx.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 19c7fe57a..3143dcf4f 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1030,6 +1030,13 @@ public static IObservable> FlattenBufferResult(this IObservable /// or is null. /// /// This is a side-effect operator. It does not modify the changeset. If you need each individual item from range operations flattened out, use instead. + /// + /// EventBehavior + /// Add/Replace/Remove/Moved/RefreshCallback invoked with the (single-item change). Changeset forwarded. + /// AddRange/RemoveRange/ClearCallback invoked once with the containing the range (accessible via Range property). Changeset forwarded. + /// OnErrorForwarded. If callback throws, propagates as OnError. + /// OnCompletedForwarded. + /// /// /// /// @@ -1843,6 +1850,13 @@ public static IObservable QueryWhenChanged( /// is null. /// /// This is a non-changeset operator. It emits the entire collection state on each change, not incremental diffs. + /// + /// EventBehavior + /// Add/AddRange/Replace/Remove/RemoveRange/Moved/Refresh/ClearThe internal list is updated, then the full snapshot is emitted. + /// OnErrorForwarded. + /// OnCompletedForwarded. + /// + /// Worth noting: A new snapshot is emitted on every changeset, which can be chatty. The collection is rebuilt by cloning each changeset into an internal list. For sorted output, use . /// /// /// From 7f7b919101db46e5a68e3064493bddacd568958c Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 13 Apr 2026 21:35:37 -0700 Subject: [PATCH 03/22] docs: fix review findings in list operator docs - Fix MergeChangeSets Replace docs (was incorrectly claimed to decompose into Remove+Add; actually uses ReplaceOrAdd which emits a single Replace) - Add Moved exception documentation to Transform (throws UnspecifiedIndexException when indices are missing) - Standardize multi-source event table headers to Event (source) and Event (per-item observable) --- src/DynamicData/List/ObservableListEx.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 3143dcf4f..6e1b31214 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -950,7 +950,7 @@ public static IObservable> Filter( /// The item's inclusion is determined by the most recent boolean value emitted by that observable. /// /// - /// Source changeset eventBehavior + /// Event (source)Behavior /// Add/AddRangeSubscribes to the per-item observable. Item is included when it first emits true. /// ReplaceOld subscription disposed, new subscription created for the replacement item. /// Remove/RemoveRange/ClearSubscription disposed. If the item was downstream, a Remove is emitted. @@ -959,7 +959,7 @@ public static IObservable> Filter( /// OnCompletedForwarded to the downstream observer. /// /// - /// Per-item observable eventBehavior + /// Event (per-item observable)Behavior /// Emits trueIf not already included, an Add is emitted downstream. /// Emits falseIf currently included, a Remove is emitted downstream. /// @@ -1267,7 +1267,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// When an item is added, a new subscription is created via . When removed or replaced, the old subscription is disposed. /// /// - /// Source changeset eventSubscription behavior + /// Event (source)Subscription behavior /// Add/AddRangeSubscribes to the per-item observable. Emissions are merged into the output. /// ReplaceOld subscription disposed, new subscription created for the replacement item. /// Remove/RemoveRange/ClearSubscription disposed. @@ -1307,7 +1307,7 @@ public static IObservable MergeMany(this IObserva /// /// EventBehavior /// Add/AddRangeForwarded to the merged output. - /// ReplaceDecomposed into Remove (old) + Add (new). + /// ReplaceThe old value is replaced by the new value in the merged output. If the old value is not found (by reference), the new value is added instead. /// Remove/RemoveRange/ClearForwarded to the merged output. /// RefreshForwarded to the merged output. /// MovedIgnored. @@ -1503,7 +1503,7 @@ public static IObservable> MergeChangeSets /// - /// Source changeset eventBehavior + /// Event (source)Behavior /// Add/AddRangeSubscribes to the child stream. Child emissions are merged into the output. /// ReplaceOld child subscription disposed (and its items removed from output). New child subscription created. /// Remove/RemoveRange/ClearChild subscription disposed. All child items from that parent are removed. @@ -2354,7 +2354,7 @@ public static IObservable> ToSortedCollectionReplaceThe factory is called for the new item. A Replace is emitted at the same index. The previous transformed value is available to overloads that accept Optional<TDestination>. /// RemoveA Remove is emitted (no factory call). /// RemoveRangeA RemoveRange is emitted. - /// MovedA Moved is emitted with updated indices (no factory call). + /// MovedA Moved is emitted with updated indices (no factory call). Throws if the source change has no index information. /// RefreshIf is false (default), the Refresh is forwarded without re-transforming. If true, the factory is re-invoked and the result replaces the current value. /// ClearA Clear is emitted and the internal list is emptied. /// OnErrorForwarded. If the factory throws, the exception propagates as OnError. From 7d044e1744039d119de298fb417567916b1a7767 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 07:02:07 -0700 Subject: [PATCH 04/22] docs: remove internal type names from public XML comments Replace references to ChangeSetMergeTracker and ChangeAwareList with behavioral descriptions. Public docs should describe functionality, not implementation details. --- src/DynamicData/List/ObservableListEx.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 6e1b31214..1948b0e40 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1300,7 +1300,7 @@ public static IObservable MergeMany(this IObserva /// is null. /// /// - /// Uses ChangeSetMergeTracker internally. All changes from inner streams are forwarded to the output. + /// All changes from inner streams are forwarded to the output. /// Replace changes are decomposed into a Remove of the old item followed by an Add of the new item. /// Moved changes from inner streams are ignored. /// @@ -1376,7 +1376,7 @@ public static IObservable> MergeChangeSets(this IOb /// is null. /// /// - /// Uses ChangeSetMergeTracker internally. Replace is decomposed into Remove + Add. Moved is ignored. + /// Replace changes from inner streams are handled as a replace-or-add: if the old item is found in the merged output, it is replaced; otherwise the new item is added. Moved changes from inner streams are ignored. /// There is no key-based deduplication (unlike cache MergeChangeSets). /// /// @@ -1959,7 +1959,7 @@ public static IObservable> SkipInitial(this IObservable or is null. /// /// - /// Maintains an internal sorted ChangeAwareList. Each incoming change is applied incrementally: adds are inserted at the correct sorted position, + /// Maintains an internal sorted list. Each incoming change is applied incrementally: adds are inserted at the correct sorted position, /// removes are removed by index, and refreshes re-evaluate position (emitting Moved if changed). /// /// @@ -2344,7 +2344,7 @@ public static IObservable> ToSortedCollectionA list changeset stream of transformed items. /// /// - /// Maintains an internal list of transformed items via ChangeAwareList. Each source changeset is + /// Maintains an internal list of transformed items. Each source changeset is /// processed and a corresponding output changeset is produced with the transformed items. /// /// From 53eb8c8f22798a427ebb7a190e53af7664295284 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 07:13:53 -0700 Subject: [PATCH 05/22] docs: replace inline YieldWithoutIndex references with seealso links Describe the behavior (index information is stripped) without naming the method inline. Link YieldWithoutIndex via seealso on RemoveIndex, WhereReasonsAre, and WhereReasonsAreNot. --- src/DynamicData/List/ObservableListEx.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 1948b0e40..e9de3fc0d 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1890,15 +1890,16 @@ public static IObservable> RefCount(this IObservable - /// Strips index information from all changes in the stream using YieldWithoutIndex. + /// Strips index information from all changes in the stream. /// /// The type of the object. /// The source list changeset stream. /// A list changeset stream with all index values removed from changes. /// is null. /// - /// This is a workaround operator introduced for internal use (e.g., creating Or operators via MergeMany). Most consumers should not need this. + /// Removes index positions from every change in each changeset. This is useful when downstream operators do not require or support index-based operations. /// + /// public static IObservable> RemoveIndex(this IObservable> source) where T : notnull { @@ -2686,7 +2687,7 @@ public static IObservable> WhenPropertyChanged /// Filters the changeset stream to include only changes with the specified values. - /// Index information is stripped from the output (via YieldWithoutIndex). + /// Index information is stripped from the output because removing some changes invalidates the original index positions. /// /// The type of the item. /// The source list changeset stream. @@ -2707,6 +2708,7 @@ public static IObservable> WhenPropertyChanged /// /// + /// public static IObservable> WhereReasonsAre(this IObservable> source, params ListChangeReason[] reasons) where T : notnull { @@ -2728,7 +2730,8 @@ public static IObservable> WhereReasonsAre(this IObservable /// Filters the changeset stream to exclude changes with the specified values. - /// Index information is stripped from the output (via YieldWithoutIndex), except when only filtering out . + /// Index information is stripped from the output because removing some changes invalidates the original index positions. + /// The exception is when only is excluded, since removing Refresh does not affect index calculations. /// /// The type of the item. /// The source list changeset stream. @@ -2739,11 +2742,12 @@ public static IObservable> WhereReasonsAre(this IObservable /// /// Empty changesets (after filtering) are automatically suppressed. When only is excluded, - /// indices are preserved (no YieldWithoutIndex), since removing Refresh does not affect index calculations. + /// indices are preserved, since removing Refresh does not affect index calculations. /// /// /// /// + /// public static IObservable> WhereReasonsAreNot(this IObservable> source, params ListChangeReason[] reasons) where T : notnull { From d8857ea289748520d31b1949daa82d13416f1337 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 07:21:49 -0700 Subject: [PATCH 06/22] docs: link types with see/cref instead of inline code tags Replace IObservable, IList, Optional, CalculateDiff, ClearAndReplace etc. with proper links for discoverability. Internal adaptor class names replaced with behavioral descriptions. --- src/DynamicData/List/ObservableListEx.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index e9de3fc0d..92c09e17b 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -73,7 +73,7 @@ public static IObservable> Adapt(this IObservable /// The type of the key. /// The source list changeset stream. /// A function to extract a unique key from each item. - /// A cache changeset stream (IObservable<IChangeSet<TObject, TKey>>) with keyed items. + /// A cache changeset stream ( of ) with keyed items. /// /// /// All index information is dropped during conversion because cache changesets are unordered by default. @@ -311,7 +311,7 @@ public static IObservable> AutoRefreshOnObservable or is null. /// /// - /// Delegates to with an ObservableCollectionAdaptor. + /// Delegates to with an an internal collection adaptor. /// Each changeset is applied to the target collection on the calling thread. For UI binding, ensure the source is /// observed on the UI thread (e.g., via ObserveOn). /// @@ -407,7 +407,7 @@ public static IObservable> Bind(this IObservable> /// The source list changeset stream. /// The target to keep in sync. /// When a changeset exceeds this many changes, the list is reset. - /// This overload binds to a (WinForms binding). Uses a BindingListAdaptor internally. + /// This overload binds to a (WinForms binding). Uses a an internal binding list adaptor internally. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this IObservable> source, BindingList bindingList, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -559,7 +559,7 @@ public static IObservable> CastToObject(this IObservableA continuation of the source changeset stream. /// is null. /// - /// Lower-level than . Uses IList<T>.Clone() to apply all changeset operations directly. + /// Lower-level than . Uses .Clone() to apply all changeset operations directly. /// /// /// @@ -852,7 +852,7 @@ public static IObservable> Filter( /// The type of the item. /// The source list changeset stream. /// An observable that emits new predicate functions. Each emission triggers a full re-evaluation of all items. - /// Controls re-filtering behavior: CalculateDiff (default) computes the minimal diff between old and new results; ClearAndReplace clears and repopulates entirely. + /// Controls re-filtering behavior: (default) computes the minimal diff between old and new results; clears and repopulates entirely. /// A list changeset stream containing only items that satisfy the most recent predicate. /// /// @@ -867,11 +867,11 @@ public static IObservable> Filter( /// RemoveIf the item was downstream, a Remove is emitted. Otherwise dropped. /// RefreshRe-evaluated. If inclusion status changed, an Add or Remove is emitted. If unchanged, Refresh forwarded or dropped. /// ClearAll downstream items are cleared. - /// Predicate changedAll items re-evaluated against the new predicate. With CalculateDiff, only items that changed status emit Add/Remove. With ClearAndReplace, a Clear is emitted followed by AddRange of all matching items. + /// Predicate changedAll items re-evaluated against the new predicate. With , only items that changed status emit Add/Remove. With , a Clear is emitted followed by AddRange of all matching items. /// OnErrorForwarded from the source or from . /// OnCompletedForwarded when the source completes. Independent completion of does not terminate the filter. /// - /// Worth noting: No items are included until emits its first function. CalculateDiff is generally preferred for performance; ClearAndReplace is useful when downstream consumers (like UI bindings) handle full resets more efficiently than individual changes. + /// Worth noting: No items are included until emits its first function. is generally preferred for performance; is useful when downstream consumers (like UI bindings) handle full resets more efficiently than individual changes. /// /// or is null. /// @@ -895,7 +895,7 @@ public static IObservable> Filter(this IObservableThe source list changeset stream. /// A stream of state values to be passed to . /// A predicate receiving the current state and an item, returning true to include or false to exclude. - /// Controls re-filtering behavior: CalculateDiff (default) computes minimal diff; ClearAndReplace clears and repopulates. + /// Controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. /// When true (default), empty changesets are suppressed. Set to false to publish empty changesets (useful for monitoring loading status). /// A list changeset stream containing only items satisfying with the current state. /// , , or is null. @@ -911,7 +911,7 @@ public static IObservable> Filter(this IObservableRemove/RemoveRangeIf the item was downstream, a Remove is emitted. /// RefreshRe-evaluated against current state. Inclusion status may change. /// ClearAll downstream items are cleared. - /// State changedAll items re-evaluated with new state value. CalculateDiff emits minimal Add/Remove; ClearAndReplace emits Clear then AddRange. + /// State changedAll items re-evaluated with new state value. emits minimal Add/Remove; emits Clear then AddRange. /// OnErrorForwarded from the source or from . /// OnCompletedForwarded when the source completes. /// @@ -2352,7 +2352,7 @@ public static IObservable> ToSortedCollectionEventBehavior /// AddThe factory is called and an Add is emitted at the same index. /// AddRangeThe factory is called for each item. An AddRange is emitted at the same start index. - /// ReplaceThe factory is called for the new item. A Replace is emitted at the same index. The previous transformed value is available to overloads that accept Optional<TDestination>. + /// ReplaceThe factory is called for the new item. A Replace is emitted at the same index. The previous transformed value is available to overloads that accept . /// RemoveA Remove is emitted (no factory call). /// RemoveRangeA RemoveRange is emitted. /// MovedA Moved is emitted with updated indices (no factory call). Throws if the source change has no index information. From 897a19d6f86950e0c20e9f58681002de08dc20d8 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 07:58:51 -0700 Subject: [PATCH 07/22] docs: add type links to all param descriptions in list operators Every param tag now mentions and links its type via see/cref. For example 'source' params link to IObservable{T} and IChangeSet{T}, 'scheduler' params link to IScheduler, 'predicate' params link to Func{T, TResult}, transform factories link to Func or Task as appropriate. --- src/DynamicData/List/ObservableListEx.cs | 384 +++++++++++------------ 1 file changed, 192 insertions(+), 192 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 92c09e17b..06d3a6288 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. +// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. @@ -28,8 +28,8 @@ public static class ObservableListEx /// The adaptor's Adapt method is called for each changeset under a synchronized lock, then the changeset is forwarded downstream. /// /// The type of items in the list. - /// The source list changeset stream. - /// The adaptor whose Adapt method is invoked for each changeset. + /// The source of . + /// The adaptor whose Adapt method is invoked for each changeset. /// A list changeset stream identical to the source, with the adaptor side effect applied. /// or is null. /// @@ -71,8 +71,8 @@ public static IObservable> Adapt(this IObservable /// /// The type of items in the list. /// The type of the key. - /// The source list changeset stream. - /// A function to extract a unique key from each item. + /// The source of . + /// A function to extract a unique key from each item. /// A cache changeset stream ( of ) with keyed items. /// /// @@ -96,8 +96,8 @@ public static IObservable> AddKey(this /// Only items present in ALL sources appear in the result. /// /// The type of items in the lists. - /// The primary source list changeset stream. - /// Additional changeset streams to intersect with. + /// The primary source of . + /// Additional changeset streams to intersect with. /// A list changeset stream containing items that exist in every source. /// /// @@ -128,25 +128,25 @@ public static IObservable> And(this IObservable> } /// - /// A fixed collection of changeset streams to intersect. + /// A of changeset streams to intersect. /// This overload accepts a pre-built collection of sources instead of params array. public static IObservable> And(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.And); /// - /// An observable list of changeset streams. Sources can be added or removed dynamically. + /// An of changeset streams. Sources can be added or removed dynamically. /// This overload supports dynamic source management: adding or removing changeset streams from the observable list triggers re-evaluation. public static IObservable> And(this IObservableList>> sources) where T : notnull => sources.Combine(CombineOperator.And); /// - /// An observable list of observable lists. Each inner list's changes are connected automatically. + /// An of . Each inner list's changes are connected automatically. /// This overload accepts instances directly, calling Connect() internally. public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); /// - /// An observable list of source lists. Each inner list's changes are connected automatically. + /// An of . Each inner list's changes are connected automatically. /// This overload accepts instances directly, calling Connect() internally. public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); @@ -155,7 +155,7 @@ public static IObservable> And(this IObservableList as a read-only , hiding mutation methods. /// /// The type of items in the list. - /// The mutable source list to wrap. + /// The mutable source list to wrap. /// A read-only observable list that mirrors the source. /// is null. public static IObservableList AsObservableList(this ISourceList source) @@ -171,7 +171,7 @@ public static IObservableList AsObservableList(this ISourceList source) /// The list is kept in sync with the source stream for the lifetime of the subscription. /// /// The type of items in the list. - /// The source changeset stream. + /// The source of . /// A read-only observable list reflecting the current state of the stream. /// is null. /// @@ -188,9 +188,9 @@ public static IObservableList AsObservableList(this IObservable /// The type of items, which must implement . - /// The source list changeset stream. - /// Optional buffer duration to batch multiple refresh signals into a single changeset. - /// Optional throttle applied to each item's property change notifications. + /// The source of . + /// Optional buffer duration to batch multiple refresh signals into a single changeset. + /// Optional throttle applied to each item's property change notifications. /// The scheduler for throttle and buffer timing. Defaults to . /// A list changeset stream with additional Refresh changes injected when properties change. /// @@ -235,11 +235,11 @@ public static IObservable> AutoRefresh(this IObserv /// /// The type of the monitored property. - /// The source list changeset stream. - /// An expression selecting the specific property to monitor. - /// Optional buffer duration to batch refresh signals. - /// Optional throttle per item's property change notifications. - /// The scheduler for throttle and buffer timing. + /// The source of . + /// An expression selecting the specific property to monitor. + /// Optional buffer duration to batch refresh signals. + /// Optional throttle per item's property change notifications. + /// The for throttle and buffer timing. /// This overload monitors a single property instead of all properties. More efficient when only one property affects downstream operators. public static IObservable> AutoRefresh(this IObservable> source, Expression> propertyAccessor, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged @@ -267,10 +267,10 @@ public static IObservable> AutoRefresh(t /// /// The type of items in the list. /// The type emitted by the re-evaluator observable (value is ignored). - /// The source list changeset stream. - /// A factory that, given an item, returns an observable whose emissions trigger a Refresh for that item. - /// Optional buffer duration to batch refresh signals into a single changeset. - /// The scheduler for buffering. + /// The source of . + /// A factory that, given an item, returns an observable whose emissions trigger a Refresh for that item. + /// Optional buffer duration to batch refresh signals into a single changeset. + /// The for buffering. /// A list changeset stream with additional Refresh changes injected when per-item observables fire. /// /// @@ -304,8 +304,8 @@ public static IObservable> AutoRefreshOnObservable for UI data binding. /// /// The type of items in the list. - /// The source list changeset stream. - /// The target collection to keep in sync. + /// The source of . + /// The target collection to keep in sync. /// When a changeset exceeds this many changes, the collection is reset instead of applying individual changes. /// A continuation of the source changeset stream (allows further chaining). /// or is null. @@ -350,9 +350,9 @@ public static IObservable> Bind(this IObservable> } /// - /// The source list changeset stream. - /// The target collection to keep in sync. - /// Binding options controlling reset threshold and other behaviors. + /// The source of . + /// The target collection to keep in sync. + /// options controlling reset threshold and other behaviors. /// This overload accepts a struct for fine-grained control over binding behavior. public static IObservable> Bind(this IObservable> source, IObservableCollection targetCollection, BindingOptions options) where T : notnull @@ -365,7 +365,7 @@ public static IObservable> Bind(this IObservable> } /// - /// The source list changeset stream. + /// The source of . /// Output parameter receiving the created . /// When a changeset exceeds this many changes, the collection is reset. /// This overload creates a via an out parameter, backed by an internal ObservableCollectionExtended. @@ -385,9 +385,9 @@ public static IObservable> Bind(this IObservable> } /// - /// The source list changeset stream. + /// The source of . /// Output parameter receiving the created . - /// Binding options controlling reset threshold and other behaviors. + /// options controlling reset threshold and other behaviors. /// This overload creates a with for fine-grained control. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, BindingOptions options) where T : notnull @@ -404,7 +404,7 @@ public static IObservable> Bind(this IObservable> #if SUPPORTS_BINDINGLIST /// - /// The source list changeset stream. + /// The source of . /// The target to keep in sync. /// When a changeset exceeds this many changes, the list is reset. /// This overload binds to a (WinForms binding). Uses a an internal binding list adaptor internally. @@ -444,11 +444,11 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. - /// The source list changeset stream. - /// An observable that controls buffering: true pauses (buffers), false resumes (flushes). + /// The source of . + /// An of that controls buffering: true pauses (buffers), false resumes (flushes). /// The initial pause state. When true, buffering starts immediately. - /// Optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. - /// The scheduler for timeout scheduling. + /// Optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. + /// The for timeout scheduling. /// A list changeset stream that buffers during pause and emits combined changesets on resume. /// or is null. /// @@ -481,9 +481,9 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. - /// The source list changeset stream. - /// The time period (measured from first emission) during which changes are buffered. - /// The scheduler for timing the buffer window. + /// The source of . + /// The time period (measured from first emission) during which changes are buffered. + /// The for timing the buffer window. /// A list changeset stream where the initial burst is combined into one changeset. /// /// @@ -506,7 +506,7 @@ public static IObservable> BufferInitial(this IObse /// Casts each item in the changeset from object to using a direct cast. /// /// The target type to cast to. - /// The source list changeset stream of object items. + /// The source of . of object items. /// A list changeset stream of cast items. /// /// @@ -523,8 +523,8 @@ public static IObservable> Cast(this IObs /// /// The source item type. /// The destination item type. - /// The source list changeset stream. - /// A function to convert each item from to . + /// The source of . + /// A function to convert each item from to . /// A list changeset stream of converted items. /// Use this overload when type inference requires explicit specification of both source and destination types. Alternatively, call first, then the single-type-parameter overload. /// @@ -544,7 +544,7 @@ public static IObservable> Cast( /// Casts each item in the changeset to object. Typically used before to work around type inference limitations. /// /// The source item type (must be a reference type). - /// The source list changeset stream. + /// The source of . /// A list changeset stream of object items. /// public static IObservable> CastToObject(this IObservable> source) @@ -554,8 +554,8 @@ public static IObservable> CastToObject(this IObservable /// The type of items in the list. - /// The source list changeset stream. - /// The target list to clone changes into. + /// The source of . + /// The target list to clone changes into. /// A continuation of the source changeset stream. /// is null. /// @@ -577,8 +577,8 @@ public static IObservable> Clone(this IObservable /// /// The type of the object. /// The type of the destination. - /// The source changeset stream. - /// The conversion factory. + /// The source of . + /// The conversion factory. /// An observable which emits the change set. [Obsolete("Prefer Cast as it is does the same thing but is semantically correct")] public static IObservable> Convert(this IObservable> source, Func conversionFactory) @@ -596,7 +596,7 @@ public static IObservable> Convert /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A list changeset stream that begins emitting only after the source has produced its first changeset. /// is null. /// @@ -639,7 +639,7 @@ public static IObservable> DeferUntilLoaded(this IObservableLis /// All remaining tracked items are disposed when the stream finalizes (OnCompleted, OnError, or subscription disposal). /// /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A continuation of the source changeset stream with disposal side effects applied. /// is null. /// @@ -673,8 +673,8 @@ public static IObservable> DisposeMany(this IObservable /// The type of items in the source list. /// The type of distinct values produced. - /// The source list changeset stream. - /// A function that extracts the value to track from each source item. + /// The source of . + /// A function that extracts the value to track from each source item. /// A list changeset stream of distinct values. /// or is null. /// @@ -711,8 +711,8 @@ public static IObservable> DistinctValues(th /// Items present in the first source but not in any of the are included in the result. /// /// The type of the item. - /// The primary source list changeset stream. - /// The other list changeset streams to exclude from the result. + /// The primary source of . + /// The other changeset streams to exclude from the result. /// A list changeset stream containing items from that are not in any of . /// is null. /// @@ -778,9 +778,9 @@ public static IObservable> Except(this IObservableList /// The type of the item. - /// The source list to monitor and remove expired items from. - /// A function returning the time-to-live for each item. Return null for items that should never expire. - /// Optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. + /// The source list to monitor and remove expired items from. + /// A function returning the time-to-live for each item. Return null for items that should never expire. + /// Optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. /// The scheduler for scheduling expiry timers. Defaults to . /// An observable that emits collections of items each time expired items are removed from the source list. /// @@ -813,8 +813,8 @@ public static IObservable> ExpireAfter( /// Only items satisfying are included downstream. /// /// The type of items in the list. - /// The source list changeset stream to filter. - /// A predicate that determines which items are included. Items returning true appear downstream; items returning false are excluded. + /// The source of . to filter. + /// A predicate that determines which items are included. Items returning true appear downstream; items returning false are excluded. /// A list changeset stream containing only items that satisfy . /// Thrown when or is null. /// @@ -850,8 +850,8 @@ public static IObservable> Filter( /// When emits a new function, all items are re-evaluated. /// /// The type of the item. - /// The source list changeset stream. - /// An observable that emits new predicate functions. Each emission triggers a full re-evaluation of all items. + /// The source of . + /// An that emits new predicate functions. Each emission triggers a full re-evaluation of all items. /// Controls re-filtering behavior: (default) computes the minimal diff between old and new results; clears and repopulates entirely. /// A list changeset stream containing only items that satisfy the most recent predicate. /// @@ -892,9 +892,9 @@ public static IObservable> Filter(this IObservable /// The type of the item. /// The type of state value required by . - /// The source list changeset stream. - /// A stream of state values to be passed to . - /// A predicate receiving the current state and an item, returning true to include or false to exclude. + /// The source of . + /// An stream of state values to be passed to . + /// A predicate receiving the current state and an item, returning true to include or false to exclude. /// Controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. /// When true (default), empty changesets are suppressed. Set to false to publish empty changesets (useful for monitoring loading status). /// A list changeset stream containing only items satisfying with the current state. @@ -938,10 +938,10 @@ public static IObservable> Filter( /// When an item's observable emits true the item enters the result; when it emits false the item is removed. /// /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A function that returns an observable of for each item, controlling its inclusion. - /// Optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. - /// The scheduler used when throttling. Defaults to the system default scheduler. + /// Optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. + /// The used when throttling. Defaults to the system default scheduler. /// A list changeset stream containing only items whose per-item observable most recently emitted true. /// or is null. /// @@ -980,11 +980,11 @@ public static IObservable> FilterOnObservable(this /// /// The type of the object. Must implement . /// The type of the property. - /// The source list changeset stream. - /// Expression selecting the property to monitor for changes. - /// A predicate evaluated against the item to determine inclusion. - /// Optional throttle duration for property change notifications. - /// The scheduler used when throttling. + /// The source of . + /// selecting the property to monitor for changes. + /// A predicate evaluated against the item to determine inclusion. + /// Optional throttle duration for property change notifications. + /// The used when throttling. /// A list changeset stream of items satisfying the predicate, re-evaluated on property changes. /// /// Deprecated. Use followed by instead. @@ -1009,7 +1009,7 @@ public static IObservable> FilterOnProperty /// The type of the item. - /// The buffered source of changeset lists. + /// The of buffered changeset lists. /// A list changeset stream with all buffered changes concatenated into single changesets. /// /// Use this after applying Observable.Buffer() to a changeset stream to re-merge the batched changesets into a single stream. @@ -1024,7 +1024,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// The changeset is forwarded downstream unchanged. /// /// The type of the object. - /// The source list changeset stream. + /// The source of . /// The action invoked for each . Range changes (AddRange, RemoveRange, Clear) are received as a single with a populated Range property. /// A continuation of the source changeset stream. /// or is null. @@ -1056,8 +1056,8 @@ public static IObservable> ForEachChange(this IObse /// Range changes are flattened into individual item changes first, so the callback only receives Add, Replace, Remove, and Refresh. /// /// The type of the object. - /// The source list changeset stream. - /// The action invoked for each individual item change. + /// The source of . + /// The action invoked for each individual item change. /// A continuation of the source changeset stream. /// or is null. /// @@ -1083,9 +1083,9 @@ public static IObservable> ForEachItemChange(this I /// /// The type of the object. /// The type of the group key. - /// The source list changeset stream. - /// A function that returns the group key for each item. - /// Optional observable that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). + /// The source of . + /// A function that returns the group key for each item. + /// Optional of that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). /// A list changeset stream of objects, each containing the items belonging to that group. /// or is null. /// @@ -1124,10 +1124,10 @@ public static IObservable>> GroupOn /// The type of the object. Must implement . /// The type of the group key. - /// The source list changeset stream. - /// Expression selecting the property whose value determines the group key. - /// Optional throttle duration for property change notifications. - /// The scheduler used when throttling. + /// The source of . + /// selecting the property whose value determines the group key. + /// Optional throttle duration for property change notifications. + /// The used when throttling. /// A list changeset stream of objects. /// or is null. /// @@ -1156,10 +1156,10 @@ public static IObservable>> GroupOnProperty /// The type of the object. Must implement . /// The type of the group key. - /// The source list changeset stream. - /// Expression selecting the property whose value determines the group key. - /// Optional throttle duration for property change notifications. - /// The scheduler used when throttling. + /// The source of . + /// selecting the property whose value determines the group key. + /// Optional throttle duration for property change notifications. + /// The used when throttling. /// A list changeset stream of immutable group snapshots. /// or is null. /// @@ -1189,9 +1189,9 @@ public static IObservable>> GroupOnProperty /// The type of the object. /// The type of the group key. - /// The source list changeset stream. - /// A function that returns the group key for each item. - /// Optional observable that forces all items to be re-evaluated when it fires. + /// The source of . + /// A function that returns the group key for each item. + /// Optional of that forces all items to be re-evaluated when it fires. /// A list changeset stream of immutable snapshots. /// or is null. /// @@ -1220,7 +1220,7 @@ public static IObservable>> GroupOnProperty /// The type of the item. - /// The source list to monitor and evict items from. + /// The source list to monitor and evict items from. /// The maximum number of items allowed. Must be greater than zero. /// The scheduler for scheduling size checks. Defaults to . /// An observable that emits collections of items each time excess items are removed from the source list. @@ -1257,8 +1257,8 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// /// The type of items in the source list. /// The type of values emitted by per-item observables. - /// The source list changeset stream. - /// A function that returns an observable for each source item. + /// The source of . + /// A function that returns an observable for each source item. /// An observable that emits values from all per-item observables, merged together. /// or is null. /// @@ -1294,7 +1294,7 @@ public static IObservable MergeMany(this IObserva /// Unlike cache MergeChangeSets, list merging performs no key-based deduplication. /// /// The type of the object. - /// An observable that emits list changeset observables to be merged. + /// The source of nested changeset observables. /// Optional used by the merge tracker to compare items. /// A single list changeset stream containing all changes from all inner streams. /// is null. @@ -1331,8 +1331,8 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges two list changeset streams into a single unified stream. /// - /// The first list changeset stream. - /// The second list changeset stream to merge with. + /// The first of changeset stream. + /// The second of changeset stream to merge with. /// Optional used to compare items. /// Optional for scheduling enumeration. /// When true (default), the result completes when all sources complete. @@ -1349,8 +1349,8 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges the source list changeset stream with additional changeset streams into a single unified stream. /// - /// The primary list changeset stream. - /// Additional list changeset streams to merge with. + /// The primary of changeset stream. + /// Additional of list changeset streams to merge with. /// Optional used to compare items. /// Optional for scheduling enumeration. /// When true (default), the result completes when all sources complete. @@ -1368,7 +1368,7 @@ public static IObservable> MergeChangeSets(this IOb /// This is the primary overload that all other list MergeChangeSets overloads delegate to. /// /// The type of the object. - /// The collection of list changeset streams to merge. + /// The collection of list changeset streams to merge. /// Optional used by the merge tracker to compare items. /// Optional for scheduling enumeration. /// When true (default), the result completes when all sources complete. @@ -1421,7 +1421,7 @@ public static IObservable> MergeChangeSets(this IOb /// /// The type of the object. /// The type of the object key. - /// The observable list of cache changeset observables. + /// The of cache changeset observables. /// to resolve which value wins when the same key appears in multiple sources. /// A single cache changeset stream with key-based deduplication. /// is null. @@ -1443,7 +1443,7 @@ public static IObservable> MergeChangeSets /// Merges cache changeset streams from an into a single cache changeset stream, with optional equality and ordering comparers. /// - /// The observable list of cache changeset observables. + /// The of cache changeset observables. /// Optional to determine if two elements are the same. /// Optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservableList>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) @@ -1459,7 +1459,7 @@ public static IObservable> MergeChangeSets /// Merges cache changeset streams from a list changeset of cache changeset observables, using a comparer for conflict resolution. /// - /// The list changeset stream whose items are cache changeset observables. + /// The source of whose items are cache changeset observables. /// to resolve which value wins when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IComparer comparer) where TObject : notnull @@ -1474,7 +1474,7 @@ public static IObservable> MergeChangeSets /// Merges cache changeset streams from a list changeset of cache changeset observables, with optional equality and ordering comparers. /// - /// The list changeset stream whose items are cache changeset observables. + /// The source of whose items are cache changeset observables. /// Optional to determine if two elements are the same. /// Optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) @@ -1492,8 +1492,8 @@ public static IObservable> MergeChangeSets /// The type of items in the source list. /// The type of items in the child changeset streams. - /// The source list changeset stream. - /// A function that returns a child list changeset stream for each source item. + /// The source of . + /// A function that returns a child list changeset stream for each source item. /// Optional used to compare child items. /// A single list changeset stream containing all items from all child streams. /// or is null. @@ -1538,8 +1538,8 @@ public static IObservable> MergeManyChangeSetsThe type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source list changeset stream. - /// A function that returns a child cache changeset stream for each source item. + /// The source of . + /// A function that returns a child cache changeset stream for each source item. /// to resolve which value wins when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. /// , , or is null. @@ -1566,8 +1566,8 @@ public static IObservable> MergeManyCh /// The type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source list changeset stream. - /// A function that returns a child cache changeset stream for each source item. + /// The source of . + /// A function that returns a child cache changeset stream for each source item. /// Optional to determine if two elements are the same. /// Optional to resolve conflicts when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. @@ -1596,7 +1596,7 @@ public static IObservable> MergeManyCh /// Suppresses empty changesets from the stream. Only changesets with at least one change are forwarded. /// /// The type of the item. - /// The source list changeset stream. + /// The source of . /// A list changeset stream with empty changesets filtered out. /// is null. /// @@ -1614,8 +1614,8 @@ public static IObservable> NotEmpty(this IObservable, , and the new item of . /// /// The type of items in the list. - /// The source list changeset stream. - /// The action to invoke for each added item. + /// The source of . + /// The action to invoke for each added item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is null. /// @@ -1646,8 +1646,8 @@ public static IObservable> OnItemAdded( /// Invokes for every item with a change in the source stream. /// /// The type of items in the list. - /// The source list changeset stream. - /// The action to invoke for each refreshed item. + /// The source of . + /// The action to invoke for each refreshed item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is null. /// @@ -1666,8 +1666,8 @@ public static IObservable> OnItemRefreshed( /// Triggers on , , , and the old item of . /// /// The type of items in the list. - /// The source list changeset stream. - /// The action to invoke for each removed item. + /// The source of . + /// The action to invoke for each removed item. /// When true (default), is also invoked for all remaining tracked items upon stream disposal, completion, or error. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is null. @@ -1713,8 +1713,8 @@ public static IObservable> Or(this ICollection /// The type of the item. - /// The primary source list changeset stream. - /// The other list changeset streams to combine with. + /// The primary source of . + /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in at least one source. /// is null. /// @@ -1770,7 +1770,7 @@ public static IObservable> Or(this IObservableList) are included downstream. /// /// The type of the item. - /// The source list changeset stream. + /// The source of . /// An observable of controlling which page to display (page number and page size). /// An stream containing only items within the current page window. /// or is null. @@ -1798,8 +1798,8 @@ public static IObservable> Page(this IObservable . /// /// The type of the object. - /// The source list changeset stream. - /// The target source list to receive all changes. + /// The source of . + /// The destination to receive all changes. /// An representing the subscription. Dispose to stop piping changes. /// or is null. /// @@ -1822,8 +1822,8 @@ public static IDisposable PopulateInto(this IObservable> source /// /// The type of items in the list. /// The type of the projected result. - /// The source list changeset stream. - /// A function projecting the current list snapshot to a result value. + /// The source of . + /// A function projecting the current list snapshot to a result value. /// An observable emitting the projected value after each changeset. /// or is null. /// @@ -1845,7 +1845,7 @@ public static IObservable QueryWhenChanged( /// Maintains an internal list updated by cloning each changeset. /// /// The type of items in the list. - /// The source list changeset stream. + /// The source of . /// An observable emitting the full list snapshot as after each change. /// is null. /// @@ -1874,7 +1874,7 @@ public static IObservable> QueryWhenChanged(this IObse /// The shared list is created on the first subscriber and disposed when the last subscriber unsubscribes. /// /// The type of the item. - /// The source list changeset stream. + /// The source of . /// A list changeset stream backed by a shared, reference-counted . /// is null. /// @@ -1893,7 +1893,7 @@ public static IObservable> RefCount(this IObservable /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A list changeset stream with all index values removed from changes. /// is null. /// @@ -1912,7 +1912,7 @@ public static IObservable> RemoveIndex(this IObservablenew_index = length - old_index - 1. /// /// The type of the item. - /// The source list changeset stream. + /// The source of . /// A list changeset stream with all index positions reversed. /// is null. /// @@ -1933,7 +1933,7 @@ public static IObservable> Reverse(this IObservable /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A list changeset stream that omits the initial snapshot. /// is null. /// @@ -1950,11 +1950,11 @@ public static IObservable> SkipInitial(this IObservable /// The type of the item. - /// The source list changeset stream. - /// The comparer used for sorting. + /// The source of . + /// The comparer used for sorting. /// Sort options. Use for improved performance when sorted values are immutable. - /// Optional observable that forces a full re-sort when it fires. Required when sorted property values are mutable. - /// Optional observable that replaces the comparer, triggering a full re-sort. + /// Optional of that forces a full re-sort when it fires. Required when sorted property values are mutable. + /// Optional of that replaces the comparer, triggering a full re-sort. /// When the number of changes exceeds this threshold, a full reset is performed instead of incremental updates. Default is 50. /// A list changeset stream with items in sorted order. /// or is null. @@ -1992,10 +1992,10 @@ public static IObservable> Sort(this IObservable> /// /// Sorts the list using an observable comparer. The initial comparer is taken from the first emission; subsequent emissions trigger a full re-sort. /// - /// The source list changeset stream. - /// An observable that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. - /// Sort options. - /// Optional observable to force a re-sort with the current comparer. + /// The source of . + /// An of that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. + /// for controlling sort behavior. + /// Optional of to force a re-sort with the current comparer. /// Threshold for triggering a full reset instead of incremental updates. public static IObservable> Sort(this IObservable> source, IObservable> comparerChanged, SortOptions options = SortOptions.None, IObservable? resort = null, int resetThreshold = 50) where T : notnull @@ -2010,7 +2010,7 @@ public static IObservable> Sort(this IObservable> /// Prepends an empty changeset to the source stream. Useful for initializing downstream consumers that expect an initial emission. /// /// The type of item. - /// The source list changeset stream. + /// The source of . /// A list changeset stream that begins with an empty changeset. /// /// @@ -2023,7 +2023,7 @@ public static IObservable> StartWithEmpty(this IObservable /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A function that creates an for each item. /// A continuation of the source changeset stream with per-item subscriptions managed as a side effect. /// or is null. @@ -2053,7 +2053,7 @@ public static IObservable> SubscribeMany(this IObservable changes from the stream. All other change reasons pass through. /// /// The type of the object. - /// The source list changeset stream. + /// The source of . /// A list changeset stream with Refresh changes removed. /// /// @@ -2084,7 +2084,7 @@ public static IObservable> Switch(this IObservable /// The type of the object. - /// An observable that emits changeset observables. Each emission triggers a switch to the new stream. + /// The source of nested changeset observables. /// A list changeset stream reflecting the most recently received inner changeset stream. /// is null. /// @@ -2106,7 +2106,7 @@ public static IObservable> Switch(this IObservable after every changeset. Equivalent to QueryWhenChanged(items => items). /// /// The type of the object. - /// The source list changeset stream. + /// The source of . /// An observable emitting the full collection snapshot after each change. /// /// @@ -2118,8 +2118,8 @@ public static IObservable> ToCollection(th /// Each emission becomes an Add operation in the resulting changeset stream. /// /// The type of the object. - /// The source observable of individual items. - /// Optional scheduler for time-based operations (expiry, size limiting). + /// The source . + /// Optional for time-based operations (expiry, size limiting). /// A list changeset stream where each source emission is an Add. /// is null. /// @@ -2147,9 +2147,9 @@ public static IObservable> ToObservableChangeSet( /// Bridges an into a list changeset stream with per-item time-based expiry. /// Expired items are automatically removed. /// - /// The source observable of individual items. - /// A function returning the time-to-live for each item. Return null for non-expiring items. - /// Optional scheduler for expiry timers. + /// The source . + /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// Optional for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable source, Func expireAfter, @@ -2166,9 +2166,9 @@ public static IObservable> ToObservableChangeSet( /// Bridges an into a list changeset stream with FIFO size limiting. /// When the list exceeds , the oldest items are removed. /// - /// The source observable of individual items. + /// The source . /// Maximum list size. Supply -1 to disable size limiting. - /// Optional scheduler for scheduling removals. + /// Optional for scheduling removals. public static IObservable> ToObservableChangeSet( this IObservable source, int limitSizeTo, @@ -2184,10 +2184,10 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The source observable of individual items. - /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// The source . + /// A function returning the time-to-live for each item. Return null for non-expiring items. /// Maximum list size. Supply -1 to disable size limiting. - /// Optional scheduler for expiry timers and size-limit checks. + /// Optional for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( this IObservable source, Func? expireAfter, @@ -2205,8 +2205,8 @@ public static IObservable> ToObservableChangeSet( /// Bridges an of batches into a list changeset stream. /// Each emitted batch becomes an AddRange. /// - /// The source observable of item batches. - /// Optional scheduler for time-based operations. + /// The source of . + /// Optional for time-based operations. public static IObservable> ToObservableChangeSet( this IObservable> source, IScheduler? scheduler = null) @@ -2221,9 +2221,9 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with FIFO size limiting. /// - /// The source observable of item batches. + /// The source of . /// Maximum list size. Oldest items are removed when the limit is exceeded. - /// Optional scheduler for scheduling removals. + /// Optional for scheduling removals. public static IObservable> ToObservableChangeSet( this IObservable> source, int limitSizeTo, @@ -2239,9 +2239,9 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with time-based expiry. /// - /// The source observable of item batches. - /// A function returning the time-to-live for each item. Return null for non-expiring items. - /// Optional scheduler for expiry timers. + /// The source of . + /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// Optional for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable> source, Func expireAfter, @@ -2257,10 +2257,10 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The source observable of item batches. - /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// The source of . + /// A function returning the time-to-live for each item. Return null for non-expiring items. /// Maximum list size. Oldest items removed when exceeded. - /// Optional scheduler for expiry timers and size-limit checks. + /// Optional for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( this IObservable> source, Func? expireAfter, @@ -2277,7 +2277,7 @@ public static IObservable> ToObservableChangeSet( /// Takes the first items from the source list. Implemented as Virtualise with a fixed window starting at index 0. /// /// The type of the item. - /// The source list changeset stream. + /// The source of . /// The maximum number of items to include. Must be greater than zero. /// A virtual changeset stream containing at most items from the beginning of the source. /// is null. @@ -2306,9 +2306,9 @@ public static IObservable> Top(this IObservable> /// /// The type of the object. /// The type of the sort key. - /// The source list changeset stream. - /// A function extracting the sort key from each item. - /// The sort direction. Defaults to ascending. + /// The source of . + /// A function extracting the sort key from each item. + /// The sort direction. Defaults to ascending. /// An observable emitting a sorted collection snapshot after each change. /// /// @@ -2320,8 +2320,8 @@ public static IObservable> ToSortedCollection after every changeset, sorted using the specified . /// /// The type of the object. - /// The source list changeset stream. - /// The comparer used for sorting. + /// The source of . + /// The comparer used for sorting. /// An observable emitting a sorted collection snapshot after each change. /// /// @@ -2339,8 +2339,8 @@ public static IObservable> ToSortedCollection /// The type of the source. /// The type of the destination. - /// The source list changeset stream. - /// The transform function applied to each item. + /// The source of . + /// The transform function applied to each item. /// When true, Refresh events re-invoke the factory and emit an update. When false (the default), Refresh is forwarded without re-transforming. /// A list changeset stream of transformed items. /// @@ -2382,8 +2382,8 @@ public static IObservable> Transform /// Projects each item using a transform function that also receives the item's index. /// - /// The source list changeset stream. - /// A function receiving the source item and its index, returning the transformed item. + /// The source of . + /// A function receiving the source item and its index, returning the transformed item. /// When true, Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull @@ -2400,7 +2400,7 @@ public static IObservable> Transform - /// The source list changeset stream. + /// The source of . /// A function receiving the source item and the previous transformed value (as ), returning the new transformed item. /// When true, Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, TDestination> transformFactory, bool transformOnRefresh = false) @@ -2418,8 +2418,8 @@ public static IObservable> Transform - /// The source list changeset stream. - /// A function receiving the source item, previous transformed value, and index. + /// The source of . + /// A function receiving the source item, previous transformed value, and index. /// When true, Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, int, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull @@ -2436,8 +2436,8 @@ public static IObservable> Transform /// The type of the source. /// The type of the destination. - /// The source list changeset stream. - /// An async function that transforms each source item. + /// The source of . + /// An async function that transforms each source item. /// When true, Refresh events re-invoke the factory. /// A list changeset stream of asynchronously transformed items. /// or is null. @@ -2531,9 +2531,9 @@ public static IObservable> TransformAsync /// The type of the destination items. /// The type of the source items. - /// The source list changeset stream. - /// A function that returns the child items for each source item. - /// Optional comparer used during Replace to determine which child items changed between old and new parent values. + /// The source of . + /// A function that returns the child items for each source item. + /// Optional comparer used during Replace to determine which child items changed between old and new parent values. /// A list changeset stream of all child items from all source items. /// or is null. /// @@ -2588,7 +2588,7 @@ public static IObservable> TransformMany /// The type of the item. - /// The source list changeset stream. + /// The source of . /// An observable of specifying the start index and size of the window. /// An stream containing only items within the current virtual window. /// or is null. @@ -2616,7 +2616,7 @@ public static IObservable> Virtualise(this IObservable. /// /// The type of the object. Must implement . - /// The source list changeset stream. + /// The source of . /// Optional list of property names to monitor. If empty, all property changes are observed. /// An observable emitting the item whenever any monitored property changes. /// is null. @@ -2641,8 +2641,8 @@ public static IObservable> Virtualise(this IObservable /// The type of item. Must implement . /// The type of the property value. - /// The source list changeset stream. - /// An expression selecting the property to observe. + /// The source of . + /// An expression selecting the property to observe. /// When true (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting whenever the property changes on any tracked item. /// or is null. @@ -2668,8 +2668,8 @@ public static IObservable> WhenPropertyChanged /// The type of item. Must implement . /// The type of the property value. - /// The source list changeset stream. - /// An expression selecting the property to observe. + /// The source of . + /// An expression selecting the property to observe. /// When true (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting the property value whenever it changes on any tracked item. /// or is null. @@ -2690,8 +2690,8 @@ public static IObservable> WhenPropertyChanged /// The type of the item. - /// The source list changeset stream. - /// The change reasons to include. Must specify at least one. + /// The source of . + /// The change reasons to include. Must specify at least one. /// A list changeset stream containing only changes with the specified reasons. /// is null. /// is empty. @@ -2734,8 +2734,8 @@ public static IObservable> WhereReasonsAre(this IObservable is excluded, since removing Refresh does not affect index calculations. /// /// The type of the item. - /// The source list changeset stream. - /// The change reasons to exclude. Must specify at least one. + /// The source of . + /// The change reasons to exclude. Must specify at least one. /// A list changeset stream with the specified change reasons removed. /// is null. /// is empty. @@ -2782,8 +2782,8 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// Items present in exactly one source are included in the result. /// /// The type of the item. - /// The primary source list changeset stream. - /// The other list changeset streams to combine with. + /// The primary source of . + /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in exactly one source. /// is null. /// From ffe39c31285a6a04b562d787c218f009f6807e4d Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 10:38:51 -0700 Subject: [PATCH 08/22] docs: fix CS1712 warning for AutoRefresh typeparam Add missing typeparam tag for TObject on the specific-property AutoRefresh overload. When inheritdoc is combined with explicit typeparam tags for other type parameters, all type parameters must be explicitly declared. --- src/DynamicData/List/ObservableListEx.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 06d3a6288..12775f790 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -234,6 +234,7 @@ public static IObservable> AutoRefresh(this IObserv } /// + /// The type of items in the list. Must implement . /// The type of the monitored property. /// The source of . /// An expression selecting the specific property to monitor. From 79a58e9932218d373f5d1e32ac54637ea35f296f Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 10:44:03 -0700 Subject: [PATCH 09/22] docs: use see langword for C# keywords (true, false, null) Replace true, false, null with , , for proper keyword rendering in generated HTML documentation. --- src/DynamicData/List/ObservableListEx.cs | 186 +++++++++++------------ 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 12775f790..a79a03be5 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. +// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. @@ -31,7 +31,7 @@ public static class ObservableListEx /// The source of . /// The adaptor whose Adapt method is invoked for each changeset. /// A list changeset stream identical to the source, with the adaptor side effect applied. - /// or is null. + /// or is . /// /// /// This operator synchronizes access with a lock, then calls adaptor.Adapt(changes) before forwarding the changeset. @@ -157,7 +157,7 @@ public static IObservable> And(this IObservableListThe type of items in the list. /// The mutable source list to wrap. /// A read-only observable list that mirrors the source. - /// is null. + /// is . public static IObservableList AsObservableList(this ISourceList source) where T : notnull { @@ -173,7 +173,7 @@ public static IObservableList AsObservableList(this ISourceList source) /// The type of items in the list. /// The source of . /// A read-only observable list reflecting the current state of the stream. - /// is null. + /// is . /// public static IObservableList AsObservableList(this IObservable> source) where T : notnull @@ -309,7 +309,7 @@ public static IObservable> AutoRefreshOnObservableThe target collection to keep in sync. /// When a changeset exceeds this many changes, the collection is reset instead of applying individual changes. /// A continuation of the source changeset stream (allows further chaining). - /// or is null. + /// or is . /// /// /// Delegates to with an an internal collection adaptor. @@ -446,12 +446,12 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. /// The source of . - /// An of that controls buffering: true pauses (buffers), false resumes (flushes). - /// The initial pause state. When true, buffering starts immediately. + /// An of that controls buffering: pauses (buffers), resumes (flushes). + /// The initial pause state. When , buffering starts immediately. /// Optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. /// The for timeout scheduling. /// A list changeset stream that buffers during pause and emits combined changesets on resume. - /// or is null. + /// or is . /// /// /// All changeset events are buffered at the changeset level (not individual changes) while paused. @@ -558,7 +558,7 @@ public static IObservable> CastToObject(this IObservableThe source of . /// The target list to clone changes into. /// A continuation of the source changeset stream. - /// is null. + /// is . /// /// Lower-level than . Uses .Clone() to apply all changeset operations directly. /// @@ -599,7 +599,7 @@ public static IObservable> ConvertThe type of the object. /// The source of . /// A list changeset stream that begins emitting only after the source has produced its first changeset. - /// is null. + /// is . /// /// /// Subscribes to the source immediately but buffers internally until the first changeset arrives, at which point it emits @@ -642,7 +642,7 @@ public static IObservable> DeferUntilLoaded(this IObservableLis /// The type of the object. /// The source of . /// A continuation of the source changeset stream with disposal side effects applied. - /// is null. + /// is . /// /// /// Items are cast to and disposed after the changeset has been forwarded downstream. @@ -677,7 +677,7 @@ public static IObservable> DisposeMany(this IObservableThe source of . /// A function that extracts the value to track from each source item. /// A list changeset stream of distinct values. - /// or is null. + /// or is . /// /// /// Maintains an internal reference count per distinct value. A value is included when its count first exceeds zero @@ -715,7 +715,7 @@ public static IObservable> DistinctValues(th /// The primary source of . /// The other changeset streams to exclude from the result. /// A list changeset stream containing items from that are not in any of . - /// is null. + /// is . /// /// /// Uses reference-counted equality comparison across all sources. Items are compared by equality (not index position). @@ -780,7 +780,7 @@ public static IObservable> Except(this IObservableList /// The type of the item. /// The source list to monitor and remove expired items from. - /// A function returning the time-to-live for each item. Return null for items that should never expire. + /// A function returning the time-to-live for each item. Return for items that should never expire. /// Optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. /// The scheduler for scheduling expiry timers. Defaults to . /// An observable that emits collections of items each time expired items are removed from the source list. @@ -815,9 +815,9 @@ public static IObservable> ExpireAfter( /// /// The type of items in the list. /// The source of . to filter. - /// A predicate that determines which items are included. Items returning true appear downstream; items returning false are excluded. + /// A predicate that determines which items are included. Items returning appear downstream; items returning are excluded. /// A list changeset stream containing only items that satisfy . - /// Thrown when or is null. + /// Thrown when or is . /// /// Use this overload when the predicate is fixed for the lifetime of the subscription. Item ordering is preserved. /// @@ -874,7 +874,7 @@ public static IObservable> Filter( /// /// Worth noting: No items are included until emits its first function. is generally preferred for performance; is useful when downstream consumers (like UI bindings) handle full resets more efficiently than individual changes. /// - /// or is null. + /// or is . /// /// public static IObservable> Filter(this IObservable> source, IObservable> predicate, ListFilterPolicy filterPolicy = ListFilterPolicy.CalculateDiff) @@ -895,11 +895,11 @@ public static IObservable> Filter(this IObservableThe type of state value required by . /// The source of . /// An stream of state values to be passed to . - /// A predicate receiving the current state and an item, returning true to include or false to exclude. + /// A predicate receiving the current state and an item, returning to include or to exclude. /// Controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. - /// When true (default), empty changesets are suppressed. Set to false to publish empty changesets (useful for monitoring loading status). + /// When (default), empty changesets are suppressed. Set to to publish empty changesets (useful for monitoring loading status). /// A list changeset stream containing only items satisfying with the current state. - /// , , or is null. + /// , , or is . /// /// /// The predicate cannot be invoked until the first state value is received. Until then, all items are treated as excluded. @@ -936,15 +936,15 @@ public static IObservable> Filter( /// /// Filters each item using a per-item of that dynamically controls inclusion. - /// When an item's observable emits true the item enters the result; when it emits false the item is removed. + /// When an item's observable emits the item enters the result; when it emits the item is removed. /// /// The type of the object. /// The source of . /// A function that returns an observable of for each item, controlling its inclusion. /// Optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. /// The used when throttling. Defaults to the system default scheduler. - /// A list changeset stream containing only items whose per-item observable most recently emitted true. - /// or is null. + /// A list changeset stream containing only items whose per-item observable most recently emitted . + /// or is . /// /// /// Each item in the source gets its own subscription to the observable returned by . @@ -952,7 +952,7 @@ public static IObservable> Filter( /// /// /// Event (source)Behavior - /// Add/AddRangeSubscribes to the per-item observable. Item is included when it first emits true. + /// Add/AddRangeSubscribes to the per-item observable. Item is included when it first emits . /// ReplaceOld subscription disposed, new subscription created for the replacement item. /// Remove/RemoveRange/ClearSubscription disposed. If the item was downstream, a Remove is emitted. /// RefreshForwarded if the item is currently included. @@ -961,8 +961,8 @@ public static IObservable> Filter( /// /// /// Event (per-item observable)Behavior - /// Emits trueIf not already included, an Add is emitted downstream. - /// Emits falseIf currently included, a Remove is emitted downstream. + /// Emits If not already included, an Add is emitted downstream. + /// Emits If currently included, a Remove is emitted downstream. /// /// /// @@ -1028,7 +1028,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// The source of . /// The action invoked for each . Range changes (AddRange, RemoveRange, Clear) are received as a single with a populated Range property. /// A continuation of the source changeset stream. - /// or is null. + /// or is . /// /// This is a side-effect operator. It does not modify the changeset. If you need each individual item from range operations flattened out, use instead. /// @@ -1060,7 +1060,7 @@ public static IObservable> ForEachChange(this IObse /// The source of . /// The action invoked for each individual item change. /// A continuation of the source changeset stream. - /// or is null. + /// or is . /// /// /// Unlike , this operator flattens @@ -1088,7 +1088,7 @@ public static IObservable> ForEachItemChange(this I /// A function that returns the group key for each item. /// Optional of that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). /// A list changeset stream of objects, each containing the items belonging to that group. - /// or is null. + /// or is . /// /// /// Groups are created lazily and removed when empty. Each group exposes an inner observable list that receives incremental updates. @@ -1130,7 +1130,7 @@ public static IObservable>> GroupOnOptional throttle duration for property change notifications. /// The used when throttling. /// A list changeset stream of objects. - /// or is null. + /// or is . /// /// /// Convenience operator equivalent to .AutoRefresh(propertySelector).GroupOn(item => property). @@ -1162,7 +1162,7 @@ public static IObservable>> GroupOnPropertyOptional throttle duration for property change notifications. /// The used when throttling. /// A list changeset stream of immutable group snapshots. - /// or is null. + /// or is . /// /// /// Combines @@ -1194,7 +1194,7 @@ public static IObservable>> GroupOnPropertyA function that returns the group key for each item. /// Optional of that forces all items to be re-evaluated when it fires. /// A list changeset stream of immutable snapshots. - /// or is null. + /// or is . /// /// /// Works like @@ -1225,7 +1225,7 @@ public static IObservable>> GroupOnPropertyThe maximum number of items allowed. Must be greater than zero. /// The scheduler for scheduling size checks. Defaults to . /// An observable that emits collections of items each time excess items are removed from the source list. - /// is null. + /// is . /// is zero or negative. /// /// @@ -1261,7 +1261,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// The source of . /// A function that returns an observable for each source item. /// An observable that emits values from all per-item observables, merged together. - /// or is null. + /// or is . /// /// /// Internally uses to manage per-item subscriptions. @@ -1298,7 +1298,7 @@ public static IObservable MergeMany(this IObserva /// The source of nested changeset observables. /// Optional used by the merge tracker to compare items. /// A single list changeset stream containing all changes from all inner streams. - /// is null. + /// is . /// /// /// All changes from inner streams are forwarded to the output. @@ -1336,7 +1336,7 @@ public static IObservable> MergeChangeSets(this IOb /// The second of changeset stream to merge with. /// Optional used to compare items. /// Optional for scheduling enumeration. - /// When true (default), the result completes when all sources complete. + /// When (default), the result completes when all sources complete. public static IObservable> MergeChangeSets(this IObservable> source, IObservable> other, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull { @@ -1354,7 +1354,7 @@ public static IObservable> MergeChangeSets(this IOb /// Additional of list changeset streams to merge with. /// Optional used to compare items. /// Optional for scheduling enumeration. - /// When true (default), the result completes when all sources complete. + /// When (default), the result completes when all sources complete. public static IObservable> MergeChangeSets(this IObservable> source, IEnumerable>> others, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull { @@ -1372,9 +1372,9 @@ public static IObservable> MergeChangeSets(this IOb /// The collection of list changeset streams to merge. /// Optional used by the merge tracker to compare items. /// Optional for scheduling enumeration. - /// When true (default), the result completes when all sources complete. + /// When (default), the result completes when all sources complete. /// A single list changeset stream containing all changes from all sources. - /// is null. + /// is . /// /// /// Replace changes from inner streams are handled as a replace-or-add: if the old item is found in the merged output, it is replaced; otherwise the new item is added. Moved changes from inner streams are ignored. @@ -1425,7 +1425,7 @@ public static IObservable> MergeChangeSets(this IOb /// The of cache changeset observables. /// to resolve which value wins when the same key appears in multiple sources. /// A single cache changeset stream with key-based deduplication. - /// is null. + /// is . /// /// Sources can be added or removed dynamically from the observable list. Parent item removal triggers cleanup of all child items from that source. /// @@ -1497,7 +1497,7 @@ public static IObservable> MergeChangeSetsA function that returns a child list changeset stream for each source item. /// Optional used to compare child items. /// A single list changeset stream containing all items from all child streams. - /// or is null. + /// or is . /// /// /// Internally subscribes to each child stream when a source item is added and disposes the subscription when it is removed. @@ -1543,9 +1543,9 @@ public static IObservable> MergeManyChangeSetsA function that returns a child cache changeset stream for each source item. /// to resolve which value wins when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. - /// , , or is null. + /// , , or is . /// - /// Delegates to with a null equality comparer. + /// Delegates to with a equality comparer. /// /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IComparer comparer) @@ -1572,7 +1572,7 @@ public static IObservable> MergeManyCh /// Optional to determine if two elements are the same. /// Optional to resolve conflicts when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. - /// or is null. + /// or is . /// /// /// Each source item produces a keyed child stream via . All child items are tracked by key. @@ -1599,7 +1599,7 @@ public static IObservable> MergeManyCh /// The type of the item. /// The source of . /// A list changeset stream with empty changesets filtered out. - /// is null. + /// is . /// /// public static IObservable> NotEmpty(this IObservable> source) @@ -1618,7 +1618,7 @@ public static IObservable> NotEmpty(this IObservableThe source of . /// The action to invoke for each added item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. - /// or is null. + /// or is . /// /// The action fires before the changeset is forwarded downstream. /// @@ -1650,7 +1650,7 @@ public static IObservable> OnItemAdded( /// The source of . /// The action to invoke for each refreshed item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. - /// or is null. + /// or is . /// /// /// @@ -1669,25 +1669,25 @@ public static IObservable> OnItemRefreshed( /// The type of items in the list. /// The source of . /// The action to invoke for each removed item. - /// When true (default), is also invoked for all remaining tracked items upon stream disposal, completion, or error. + /// When (default), is also invoked for all remaining tracked items upon stream disposal, completion, or error. /// A continuation of the source changeset stream, with the side effect applied before forwarding. - /// or is null. + /// or is . /// /// - /// When is true, the operator tracks all items that have been added but not yet removed, + /// When is , the operator tracks all items that have been added but not yet removed, /// and fires for each of them during finalization. This is useful for resource cleanup patterns. /// /// /// EventBehavior - /// Add/AddRangeTracked internally (when is true). No callback invoked. Changeset forwarded. + /// Add/AddRangeTracked internally (when is ). No callback invoked. Changeset forwarded. /// ReplaceCallback invoked for the previous (replaced) item. New item tracked. Changeset forwarded. /// RemoveCallback invoked for the removed item. Changeset forwarded. /// RemoveRange/ClearCallback invoked for each removed item. Changeset forwarded. /// Moved/RefreshNo callback. Changeset forwarded. - /// OnErrorIf is true, callback is invoked for all tracked items before the error propagates. - /// OnCompletedIf is true, callback is invoked for all tracked items before completion propagates. + /// OnErrorIf is , callback is invoked for all tracked items before the error propagates. + /// OnCompletedIf is , callback is invoked for all tracked items before completion propagates. /// - /// Worth noting: When is true (the default), disposing the subscription also invokes the callback for every item still in the list, not just items that were explicitly removed during the subscription. Exceptions in are not caught. + /// Worth noting: When is (the default), disposing the subscription also invokes the callback for every item still in the list, not just items that were explicitly removed during the subscription. Exceptions in are not caught. /// /// /// @@ -1717,7 +1717,7 @@ public static IObservable> Or(this ICollectionThe primary source of . /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in at least one source. - /// is null. + /// is . /// /// /// Uses reference-counted equality comparison. An item is included when it first appears in any source and removed when it no longer exists in any source. @@ -1774,7 +1774,7 @@ public static IObservable> Or(this IObservableListThe source of . /// An observable of controlling which page to display (page number and page size). /// An stream containing only items within the current page window. - /// or is null. + /// or is . /// /// /// Maintains the full source list internally and calculates the page window on each change or page request. @@ -1802,7 +1802,7 @@ public static IObservable> Page(this IObservableThe source of . /// The destination to receive all changes. /// An representing the subscription. Dispose to stop piping changes. - /// or is null. + /// or is . /// /// Each changeset is applied to the destination using Clone() inside an Edit() call, producing a single batch update per changeset. /// @@ -1826,7 +1826,7 @@ public static IDisposable PopulateInto(this IObservable> source /// The source of . /// A function projecting the current list snapshot to a result value. /// An observable emitting the projected value after each changeset. - /// or is null. + /// or is . /// /// Delegates to and applies via Select. /// @@ -1848,7 +1848,7 @@ public static IObservable QueryWhenChanged( /// The type of items in the list. /// The source of . /// An observable emitting the full list snapshot as after each change. - /// is null. + /// is . /// /// This is a non-changeset operator. It emits the entire collection state on each change, not incremental diffs. /// @@ -1877,7 +1877,7 @@ public static IObservable> QueryWhenChanged(this IObse /// The type of the item. /// The source of . /// A list changeset stream backed by a shared, reference-counted . - /// is null. + /// is . /// /// Equivalent to Publish().RefCount() for changeset streams. The underlying list is created lazily on first subscription. /// @@ -1896,7 +1896,7 @@ public static IObservable> RefCount(this IObservableThe type of the object. /// The source of . /// A list changeset stream with all index values removed from changes. - /// is null. + /// is . /// /// Removes index positions from every change in each changeset. This is useful when downstream operators do not require or support index-based operations. /// @@ -1915,7 +1915,7 @@ public static IObservable> RemoveIndex(this IObservableThe type of the item. /// The source of . /// A list changeset stream with all index positions reversed. - /// is null. + /// is . /// /// This is a pure index transformation. The items themselves are unchanged; only their positional indices are inverted. /// @@ -1936,7 +1936,7 @@ public static IObservable> Reverse(this IObservableThe type of the object. /// The source of . /// A list changeset stream that omits the initial snapshot. - /// is null. + /// is . /// /// public static IObservable> SkipInitial(this IObservable> source) @@ -1958,7 +1958,7 @@ public static IObservable> SkipInitial(this IObservableOptional of that replaces the comparer, triggering a full re-sort. /// When the number of changes exceeds this threshold, a full reset is performed instead of incremental updates. Default is 50. /// A list changeset stream with items in sorted order. - /// or is null. + /// or is . /// /// /// Maintains an internal sorted list. Each incoming change is applied incrementally: adds are inserted at the correct sorted position, @@ -2027,7 +2027,7 @@ public static IObservable> StartWithEmpty(this IObservableThe source of . /// A function that creates an for each item. /// A continuation of the source changeset stream with per-item subscriptions managed as a side effect. - /// or is null. + /// or is . /// /// /// EventBehavior @@ -2067,7 +2067,7 @@ public static IObservable> SuppressRefresh(this IObservableThe type of the object. /// An observable that emits instances. Each emission triggers a switch to the new list. /// A list changeset stream reflecting the most recently received inner list. - /// is null. + /// is . /// /// Convenience overload that calls Connect() on each inner list, then delegates to . /// @@ -2087,7 +2087,7 @@ public static IObservable> Switch(this IObservableThe type of the object. /// The source of nested changeset observables. /// A list changeset stream reflecting the most recently received inner changeset stream. - /// is null. + /// is . /// /// /// On each new inner stream, the operator clears the destination, disposes the previous subscription, and subscribes to the new stream. @@ -2122,7 +2122,7 @@ public static IObservable> ToCollection(th /// The source . /// Optional for time-based operations (expiry, size limiting). /// A list changeset stream where each source emission is an Add. - /// is null. + /// is . /// /// /// This is the primary bridge from standard Rx into DynamicData's list changeset model. Each item emitted by @@ -2149,7 +2149,7 @@ public static IObservable> ToObservableChangeSet( /// Expired items are automatically removed. /// /// The source . - /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// A function returning the time-to-live for each item. Return for non-expiring items. /// Optional for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable source, @@ -2186,7 +2186,7 @@ public static IObservable> ToObservableChangeSet( /// Bridges an into a list changeset stream with both time-based expiry and FIFO size limiting. /// /// The source . - /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// A function returning the time-to-live for each item. Return for non-expiring items. /// Maximum list size. Supply -1 to disable size limiting. /// Optional for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( @@ -2241,7 +2241,7 @@ public static IObservable> ToObservableChangeSet( /// Bridges an of batches into a list changeset stream with time-based expiry. /// /// The source of . - /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// A function returning the time-to-live for each item. Return for non-expiring items. /// Optional for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable> source, @@ -2259,7 +2259,7 @@ public static IObservable> ToObservableChangeSet( /// Bridges an of batches into a list changeset stream with both time-based expiry and FIFO size limiting. /// /// The source of . - /// A function returning the time-to-live for each item. Return null for non-expiring items. + /// A function returning the time-to-live for each item. Return for non-expiring items. /// Maximum list size. Oldest items removed when exceeded. /// Optional for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( @@ -2281,7 +2281,7 @@ public static IObservable> ToObservableChangeSet( /// The source of . /// The maximum number of items to include. Must be greater than zero. /// A virtual changeset stream containing at most items from the beginning of the source. - /// is null. + /// is . /// is zero or negative. /// /// The source should ideally be sorted before applying Top, since list order determines which items appear. @@ -2342,7 +2342,7 @@ public static IObservable> ToSortedCollectionThe type of the destination. /// The source of . /// The transform function applied to each item. - /// When true, Refresh events re-invoke the factory and emit an update. When false (the default), Refresh is forwarded without re-transforming. + /// When , Refresh events re-invoke the factory and emit an update. When (the default), Refresh is forwarded without re-transforming. /// A list changeset stream of transformed items. /// /// @@ -2357,14 +2357,14 @@ public static IObservable> ToSortedCollectionRemoveA Remove is emitted (no factory call). /// RemoveRangeA RemoveRange is emitted. /// MovedA Moved is emitted with updated indices (no factory call). Throws if the source change has no index information. - /// RefreshIf is false (default), the Refresh is forwarded without re-transforming. If true, the factory is re-invoked and the result replaces the current value. + /// RefreshIf is (default), the Refresh is forwarded without re-transforming. If , the factory is re-invoked and the result replaces the current value. /// ClearA Clear is emitted and the internal list is emptied. /// OnErrorForwarded. If the factory throws, the exception propagates as OnError. /// OnCompletedForwarded to the downstream observer. /// - /// Worth noting: By default, Refresh does NOT re-transform the item (it just forwards the signal). Set to true if you need the factory re-invoked on Refresh. Add operations with out-of-bounds indices silently append to the end. + /// Worth noting: By default, Refresh does NOT re-transform the item (it just forwards the signal). Set to if you need the factory re-invoked on Refresh. Add operations with out-of-bounds indices silently append to the end. /// - /// or is null. + /// or is . /// /// /// @@ -2385,7 +2385,7 @@ public static IObservable> Transform /// The source of . /// A function receiving the source item and its index, returning the transformed item. - /// When true, Refresh events re-invoke the factory. + /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2403,7 +2403,7 @@ public static IObservable> Transform /// The source of . /// A function receiving the source item and the previous transformed value (as ), returning the new transformed item. - /// When true, Refresh events re-invoke the factory. + /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2421,7 +2421,7 @@ public static IObservable> Transform /// The source of . /// A function receiving the source item, previous transformed value, and index. - /// When true, Refresh events re-invoke the factory. + /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, int, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2439,9 +2439,9 @@ public static IObservable> TransformThe type of the destination. /// The source of . /// An async function that transforms each source item. - /// When true, Refresh events re-invoke the factory. + /// When , Refresh events re-invoke the factory. /// A list changeset stream of asynchronously transformed items. - /// or is null. + /// or is . /// /// Change handling is identical to the synchronous except the factory is awaited. Operations are serialized per changeset via a semaphore. /// @@ -2450,7 +2450,7 @@ public static IObservable> TransformReplaceThe async factory is awaited for the new item. A Replace is emitted. /// Remove/RemoveRangeEmitted without invoking the factory. /// MovedEmitted with updated indices (no factory call). - /// RefreshIf is false (default), forwarded without re-transforming. If true, the factory is re-awaited. + /// RefreshIf is (default), forwarded without re-transforming. If , the factory is re-awaited. /// ClearEmitted and internal list cleared. /// OnErrorForwarded. If the async factory throws, the exception propagates as OnError. /// OnCompletedForwarded after the last changeset is processed. @@ -2536,7 +2536,7 @@ public static IObservable> TransformAsyncA function that returns the child items for each source item. /// Optional comparer used during Replace to determine which child items changed between old and new parent values. /// A list changeset stream of all child items from all source items. - /// or is null. + /// or is . /// /// /// EventBehavior @@ -2592,7 +2592,7 @@ public static IObservable> TransformManyThe source of . /// An observable of specifying the start index and size of the window. /// An stream containing only items within the current virtual window. - /// or is null. + /// or is . /// /// /// Like but uses absolute start index and size instead of page number and page size. @@ -2620,7 +2620,7 @@ public static IObservable> Virtualise(this IObservableThe source of . /// Optional list of property names to monitor. If empty, all property changes are observed. /// An observable emitting the item whenever any monitored property changes. - /// is null. + /// is . /// /// Implemented via . Subscriptions are managed per item: created on add, disposed on remove. /// @@ -2644,9 +2644,9 @@ public static IObservable> Virtualise(this IObservableThe type of the property value. /// The source of . /// An expression selecting the property to observe. - /// When true (default), the current value is emitted immediately upon subscribing to each item. + /// When (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting whenever the property changes on any tracked item. - /// or is null. + /// or is . /// /// Implemented via . /// @@ -2671,9 +2671,9 @@ public static IObservable> WhenPropertyChangedThe type of the property value. /// The source of . /// An expression selecting the property to observe. - /// When true (default), the current value is emitted immediately upon subscribing to each item. + /// When (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting the property value whenever it changes on any tracked item. - /// or is null. + /// or is . /// /// public static IObservable WhenValueChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) @@ -2694,7 +2694,7 @@ public static IObservable> WhenPropertyChangedThe source of . /// The change reasons to include. Must specify at least one. /// A list changeset stream containing only changes with the specified reasons. - /// is null. + /// is . /// is empty. /// /// Filters individual changes within each changeset. If filtering removes all changes from a changeset, the empty changeset is suppressed via . @@ -2738,7 +2738,7 @@ public static IObservable> WhereReasonsAre(this IObservableThe source of . /// The change reasons to exclude. Must specify at least one. /// A list changeset stream with the specified change reasons removed. - /// is null. + /// is . /// is empty. /// /// @@ -2786,7 +2786,7 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// The primary source of . /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in exactly one source. - /// is null. + /// is . /// /// /// Uses reference-counted equality. An item is included when it exists in exactly one source. From 080f81e79b3bfa9100b46d94cbffdde256cf5f61 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 10:51:52 -0700 Subject: [PATCH 10/22] docs: add cross-links from list operators to cache equivalents 27 primary list operators now link to their cache counterpart via seealso, enabling navigation between the two collection types in generated docs. --- src/DynamicData/List/ObservableListEx.cs | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index a79a03be5..3240a11b6 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -119,6 +119,7 @@ public static IObservable> AddKey(this /// /// /// + /// public static IObservable> And(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -214,6 +215,7 @@ public static IObservableList AsObservableList(this IObservable /// /// + /// public static IObservable> AutoRefresh(this IObservable> source, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged { @@ -292,6 +294,7 @@ public static IObservable> AutoRefresh(t /// /// /// + /// public static IObservable> AutoRefreshOnObservable(this IObservable> source, Func> reevaluator, TimeSpan? changeSetBuffer = null, IScheduler? scheduler = null) where TObject : notnull { @@ -333,6 +336,7 @@ public static IObservable> AutoRefreshOnObservable /// /// + /// public static IObservable> Bind(this IObservable> source, IObservableCollection targetCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -661,6 +665,7 @@ public static IObservable> DeferUntilLoaded(this IObservableLis /// /// /// + /// public static IObservable> DisposeMany(this IObservable> source) where T : notnull { @@ -696,6 +701,7 @@ public static IObservable> DisposeMany(this IObservable /// /// + /// public static IObservable> DistinctValues(this IObservable> source, Func valueSelector) where TObject : notnull where TValue : notnull @@ -738,6 +744,7 @@ public static IObservable> DistinctValues(th /// /// /// + /// public static IObservable> Except(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -837,6 +844,7 @@ public static IObservable> ExpireAfter( /// /// /// + /// public static IObservable> Filter( this IObservable> source, Func predicate) @@ -968,6 +976,7 @@ public static IObservable> Filter( /// /// /// + /// public static IObservable> FilterOnObservable(this IObservable> source, Func> objectFilterObservable, TimeSpan? propertyChangedThrottle = null, IScheduler? scheduler = null) where TObject : notnull { @@ -1042,6 +1051,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// /// /// + /// public static IObservable> ForEachChange(this IObservable> source, Action> action) where TObject : notnull { @@ -1280,6 +1290,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// /// /// + /// public static IObservable MergeMany(this IObservable> source, Func> observableSelector) where T : notnull { @@ -1320,6 +1331,7 @@ public static IObservable MergeMany(this IObserva /// /// /// + /// public static IObservable> MergeChangeSets(this IObservable>> source, IEqualityComparer? equalityComparer = null) where TObject : notnull { @@ -1515,6 +1527,7 @@ public static IObservable> MergeChangeSets /// /// + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TDestination : notnull @@ -1635,6 +1648,7 @@ public static IObservable> NotEmpty(this IObservable /// /// + /// public static IObservable> OnItemAdded( this IObservable> source, Action addAction) @@ -1654,6 +1668,7 @@ public static IObservable> OnItemAdded( /// /// /// + /// public static IObservable> OnItemRefreshed( this IObservable> source, Action refreshAction) @@ -1692,6 +1707,7 @@ public static IObservable> OnItemRefreshed( /// /// /// + /// public static IObservable> OnItemRemoved( this IObservable> source, Action removeAction, @@ -1706,6 +1722,7 @@ public static IObservable> OnItemRemoved( /// /// Applies a logical OR (union) between a pre-built collection of list changeset sources. Items present in any source are included. /// + /// public static IObservable> Or(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.Or); @@ -1832,6 +1849,7 @@ public static IDisposable PopulateInto(this IObservable> source /// /// /// + /// public static IObservable QueryWhenChanged(this IObservable> source, Func, TDestination> resultSelector) where TObject : notnull { @@ -1980,6 +1998,7 @@ public static IObservable> SkipInitial(this IObservable /// /// + /// public static IObservable> Sort(this IObservable> source, IComparer comparer, SortOptions options = SortOptions.None, IObservable? resort = null, IObservable>? comparerChanged = null, int resetThreshold = 50) where T : notnull { @@ -2041,6 +2060,7 @@ public static IObservable> StartWithEmpty(this IObservable /// /// + /// public static IObservable> SubscribeMany(this IObservable> source, Func subscriptionFactory) where T : notnull { @@ -2368,6 +2388,7 @@ public static IObservable> ToSortedCollection /// /// + /// public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2458,6 +2479,7 @@ public static IObservable> TransformWorth noting: All async transforms within a single changeset are serialized (not parallel). Each changeset is fully processed before the next begins. By default, Refresh does NOT re-transform. /// /// + /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design.")] public static IObservable> TransformAsync( this IObservable> source, @@ -2550,6 +2572,7 @@ public static IObservable> TransformAsync /// /// + /// public static IObservable> TransformMany(this IObservable> source, Func> manySelector, IEqualityComparer? equalityComparer = null) where TDestination : notnull where TSource : notnull @@ -2627,6 +2650,7 @@ public static IObservable> Virtualise(this IObservable /// /// + /// public static IObservable WhenAnyPropertyChanged(this IObservable> source, params string[] propertiesToMonitor) where TObject : INotifyPropertyChanged { @@ -2652,6 +2676,7 @@ public static IObservable> Virtualise(this IObservable /// /// + /// public static IObservable> WhenPropertyChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) where TObject : INotifyPropertyChanged { @@ -2676,6 +2701,7 @@ public static IObservable> WhenPropertyChanged or is . /// /// + /// public static IObservable WhenValueChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) where TObject : INotifyPropertyChanged { @@ -2807,6 +2833,7 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// /// /// + /// public static IObservable> Xor(this IObservable> source, params IObservable>[] others) where T : notnull { From 2b5544eaff400cb335da51bc38cd4d3abb9742fd Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 11:34:01 -0700 Subject: [PATCH 11/22] Fix param descriptions: proper English with type links - Rewrite 111+ param descriptions to read as natural English with type links woven in - Fix double-brace cref syntax ({{T}} to {T}) - Fix wrong types in cref attributes to match actual parameter types - Fix Optional/Additional/Factory articles (An optional, The additional, A factory) - Fix filterPolicy, options, resetThreshold descriptions - Add cross-link seealso references to cache file operators --- .../Cache/ObservableCacheEx.SortAndBind.cs | 152 +++++---- .../ObservableCacheEx.VirtualiseAndPage.cs | 84 ++--- src/DynamicData/Cache/ObservableCacheEx.cs | 56 +++- src/DynamicData/List/ObservableListEx.cs | 292 +++++++++--------- 4 files changed, 343 insertions(+), 241 deletions(-) diff --git a/src/DynamicData/Cache/ObservableCacheEx.SortAndBind.cs b/src/DynamicData/Cache/ObservableCacheEx.SortAndBind.cs index 06c14e0d4..d7194c5ba 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.SortAndBind.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.SortAndBind.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. +// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. @@ -18,8 +18,9 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. + /// The source of . + /// The resulting read only observable collection. + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -38,9 +39,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// Bind and sort default options. + /// The source of . + /// The resulting read only observable collection. + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -60,8 +62,9 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. + /// The source of . + /// The list to bind to. + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -75,9 +78,12 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// Bind and sort default options. + /// The source of . + /// The list to bind to. + /// The Bind and sort default options. + /// + /// + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -92,8 +98,9 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. + /// The source of . + /// The resulting read only observable collection. + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -112,9 +119,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// Bind and sort default options. + /// The source of . + /// The resulting read only observable collection. + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -134,8 +142,9 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. + /// The source of . + /// The list to bind to. + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -149,9 +158,12 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// Bind and sort default options. + /// The source of . + /// The list to bind to. + /// The Bind and sort default options. + /// + /// + /// /// An observable which will emit change sets. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable>> source, @@ -166,8 +178,9 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. + /// The source of . + /// The list to bind to. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -181,9 +194,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// Bind and sort default options. + /// The source of . + /// The list to bind to. + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -198,9 +212,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// The comparer to order the resulting dataset. + /// The source of . + /// The list to bind to. + /// An comparer to order the resulting dataset. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -215,10 +230,21 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// The comparer to order the resulting dataset. - /// Bind and sort default options. + /// The source of . + /// The list to bind to. + /// An comparer to order the resulting dataset. + /// The Bind and sort default options. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -234,9 +260,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// An observable of comparers which enables the sort order to be changed.> + /// The source of . + /// The list to bind to. + /// An of which enables the sort order to be changed.> + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -251,10 +278,11 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The list to bind to. - /// An observable of comparers which enables the sort order to be changed.> - /// Bind and sort default options. + /// The source of . + /// The list to bind to. + /// An of which enables the sort order to be changed.> + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -270,8 +298,9 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. + /// The source of . + /// The resulting read only observable collection. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -285,9 +314,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// Bind and sort default options. + /// The source of . + /// The resulting read only observable collection. + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -302,9 +332,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// The comparer to order the resulting dataset. + /// The source of . + /// The resulting read only observable collection. + /// An comparer to order the resulting dataset. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -319,10 +350,11 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// The comparer to order the resulting dataset. - /// Bind and sort default options. + /// The source of . + /// The resulting read only observable collection. + /// An comparer to order the resulting dataset. + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -347,9 +379,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// An observable of comparers which enables the sort order to be changed. + /// The source of . + /// The resulting read only observable collection. + /// An of which enables the sort order to be changed. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, @@ -364,10 +397,11 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The resulting read only observable collection. - /// An observable of comparers which enables the sort order to be changed.> - /// Bind and sort default options. + /// The source of . + /// The resulting read only observable collection. + /// An of which enables the sort order to be changed.> + /// The Bind and sort default options. + /// /// An observable which will emit change sets. public static IObservable> SortAndBind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TObject, TKey>( this IObservable> source, diff --git a/src/DynamicData/Cache/ObservableCacheEx.VirtualiseAndPage.cs b/src/DynamicData/Cache/ObservableCacheEx.VirtualiseAndPage.cs index d4a5f060c..b6b8e1412 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.VirtualiseAndPage.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.VirtualiseAndPage.cs @@ -17,9 +17,10 @@ public static partial class ObservableCacheEx /// /// The type of the object. /// The type of the key. - /// The source. - /// The comparer to order the resulting dataset. - /// The virtualizing requests. + /// The source of . + /// An comparer to order the resulting dataset. + /// An of that specifies the virtualizing parameters. + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndVirtualize(this IObservable> source, @@ -34,9 +35,10 @@ public static IObservable>> So /// /// The type of the object. /// The type of the key. - /// The source. - /// An observable of comparers which enables the sort order to be changed.> - /// The virtualizing requests. + /// The source of . + /// An of which enables the sort order to be changed.> + /// An of that specifies the virtualizing parameters. + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndVirtualize( @@ -57,10 +59,11 @@ public static IObservable>> So /// /// The type of the object. /// The type of the key. - /// The source. - /// The comparer to order the resulting dataset. - /// The virtualizing requests. - /// Addition optimization options for virtualization. + /// The source of . + /// An comparer to order the resulting dataset. + /// An of that specifies the virtualizing parameters. + /// The Addition optimization options for virtualization. + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndVirtualize( @@ -82,10 +85,13 @@ public static IObservable>> So /// /// The type of the object. /// The type of the key. - /// The source. - /// An observable of comparers which enables the sort order to be changed.> - /// The virtualizing requests. - /// Addition optimization options for virtualization. + /// The source of . + /// An of which enables the sort order to be changed.> + /// An of that specifies the virtualizing parameters. + /// The Addition optimization options for virtualization. + /// + /// + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndVirtualize( @@ -107,8 +113,8 @@ public static IObservable>> So /// /// The type of the object. /// The type of the key. - /// The source. - /// The virtualising requests. + /// The source of . + /// An of that specifies the virtualizing parameters. /// An observable which will emit virtual change sets. /// source. [Obsolete(Constants.VirtualizeIsObsolete)] @@ -127,9 +133,10 @@ public static IObservable> Virtualise /// The type of the object. /// The type of the key. - /// The source. - /// The comparer. + /// The source of . + /// An comparer. /// The size. + /// /// An observable which will emit virtual change sets. /// source. /// size;Size should be greater than zero. @@ -153,8 +160,9 @@ public static IObservable>> To /// /// The type of the object. /// The type of the key. - /// The source. + /// The source of . /// The size. + /// /// An observable which will emit virtual change sets. /// source. /// size;Size should be greater than zero. @@ -178,9 +186,10 @@ public static IObservable> Top(t /// /// The type of the object. /// The type of the key. - /// The source. - /// The comparer to order the resulting dataset. - /// The virtualizing requests. + /// The source of . + /// An comparer to order the resulting dataset. + /// An of that specifies the paging parameters. + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndPage(this IObservable> source, @@ -195,9 +204,10 @@ public static IObservable>> SortA /// /// The type of the object. /// The type of the key. - /// The source. - /// An observable of comparers which enables the sort order to be changed.> - /// The virtualizing requests. + /// The source of . + /// An of which enables the sort order to be changed.> + /// An of that specifies the paging parameters. + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndPage( @@ -218,10 +228,11 @@ public static IObservable>> SortA /// /// The type of the object. /// The type of the key. - /// The source. - /// The comparer to order the resulting dataset. - /// The virtualizing requests. - /// Addition optimization options for virtualization. + /// The source of . + /// An comparer to order the resulting dataset. + /// An of that specifies the paging parameters. + /// The Addition optimization options for virtualization. + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndPage( @@ -243,10 +254,13 @@ public static IObservable>> SortA /// /// The type of the object. /// The type of the key. - /// The source. - /// An observable of comparers which enables the sort order to be changed.> - /// The virtualizing requests. - /// Addition optimization options for virtualization. + /// The source of . + /// An of which enables the sort order to be changed.> + /// An of that specifies the paging parameters. + /// The Addition optimization options for virtualization. + /// + /// + /// /// An observable which will emit virtual change sets. /// source. public static IObservable>> SortAndPage( @@ -268,8 +282,8 @@ public static IObservable>> SortA /// /// The type of the object. /// The type of the key. - /// The source. - /// The page requests. + /// The source of . + /// An of that specifies the paging parameters. /// An observable which emits change sets. [Obsolete(Constants.PageIsObsolete)] public static IObservable> Page(this IObservable> source, IObservable pageRequests) diff --git a/src/DynamicData/Cache/ObservableCacheEx.cs b/src/DynamicData/Cache/ObservableCacheEx.cs index 4edf35285..dda2dd629 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. +// Copyright (c) 2011-2025 Roland Pheasant. All rights reserved. // Roland Pheasant licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. @@ -81,6 +81,7 @@ public static IObservable> Adapt(this I /// The source. /// The item. /// source. + /// public static void AddOrUpdate(this ISourceCache source, TObject item) where TObject : notnull where TKey : notnull @@ -99,6 +100,7 @@ public static void AddOrUpdate(this ISourceCache s /// The item. /// The equality comparer used to determine whether a new item is the same as an existing cached item. /// source. + /// public static void AddOrUpdate(this ISourceCache source, TObject item, IEqualityComparer equalityComparer) where TObject : notnull where TKey : notnull @@ -118,6 +120,7 @@ public static void AddOrUpdate(this ISourceCache s /// The source. /// The items. /// source. + /// public static void AddOrUpdate(this ISourceCache source, IEnumerable items) where TObject : notnull where TKey : notnull @@ -138,6 +141,10 @@ public static void AddOrUpdate(this ISourceCache s /// The items. /// The equality comparer used to determine whether a new item is the same as an existing cached item. /// source. + /// + /// + /// + /// public static void AddOrUpdate(this ISourceCache source, IEnumerable items, IEqualityComparer equalityComparer) where TObject : notnull where TKey : notnull @@ -156,6 +163,7 @@ public static void AddOrUpdate(this ISourceCache s /// The item to add or update. /// The key to add or update. /// source. + /// public static void AddOrUpdate(this IIntermediateCache source, TObject item, TKey key) where TObject : notnull where TKey : notnull @@ -955,6 +963,8 @@ public static IObservable> ChangeKeyThe type of the key. /// The source. /// source. + /// + /// public static void Clear(this ISourceCache source) where TObject : notnull where TKey : notnull @@ -971,6 +981,7 @@ public static void Clear(this ISourceCache source) /// The type of the key. /// The source. /// source. + /// public static void Clear(this IIntermediateCache source) where TObject : notnull where TKey : notnull @@ -987,6 +998,7 @@ public static void Clear(this IIntermediateCache s /// The type of the key. /// The source. /// source. + /// public static void Clear(this LockFreeObservableCache source) where TObject : notnull where TKey : notnull @@ -1154,6 +1166,7 @@ public static IObservable> DistinctValuesThe items to add, update or delete. /// The equality comparer used to determine whether a new item is the same as an existing cached item. /// source. + /// public static void EditDiff(this ISourceCache source, IEnumerable allItems, IEqualityComparer equalityComparer) where TObject : notnull where TKey : notnull @@ -1175,6 +1188,9 @@ public static void EditDiff(this ISourceCache sour /// The items to compare and add, update or delete. /// Expression to determine whether an item's value is equal to the old value (current, previous) => current.Version == previous.Version. /// source. + /// + /// + /// public static void EditDiff(this ISourceCache source, IEnumerable allItems, Func areItemsEqual) where TObject : notnull where TKey : notnull @@ -1197,6 +1213,7 @@ public static void EditDiff(this ISourceCache sour /// Optional instance to use for comparing values. /// An observable cache. /// source. + /// public static IObservable> EditDiff(this IObservable> source, Func keySelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TKey : notnull @@ -1217,6 +1234,7 @@ public static IObservable> EditDiff(thi /// Optional instance to use for comparing values. /// An observable changeset. /// source. + /// public static IObservable> EditDiff(this IObservable> source, Func keySelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TKey : notnull @@ -2466,6 +2484,7 @@ public static IObservable>> LimitSizeTo< /// source /// or /// observableSelector. + /// public static IObservable MergeMany(this IObservable> source, Func> observableSelector) where TObject : notnull where TKey : notnull @@ -2489,6 +2508,7 @@ public static IObservable MergeMany(t /// source /// or /// observableSelector. + /// public static IObservable MergeMany(this IObservable> source, Func> observableSelector) where TObject : notnull where TKey : notnull @@ -3150,6 +3170,7 @@ public static IObservable> MergeManyCh /// Factory Function used to create child changesets. /// Optional instance to determine if two elements are the same. /// The result from merging the child changesets together. + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TKey : notnull @@ -3171,6 +3192,7 @@ public static IObservable> MergeManyChangeSetsFactory Function used to create child changesets. /// Optional instance to determine if two elements are the same. /// The result from merging the child changesets together. + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TKey : notnull @@ -3530,6 +3552,7 @@ public static IObservable> Or(this IObs /// or /// keySelector. /// + /// public static IDisposable PopulateFrom(this ISourceCache source, IObservable> observable) where TObject : notnull where TKey : notnull @@ -3552,6 +3575,7 @@ public static IDisposable PopulateFrom(this ISourceCache + /// public static IDisposable PopulateFrom(this ISourceCache source, IObservable observable) where TObject : notnull where TKey : notnull @@ -3574,6 +3598,8 @@ public static IDisposable PopulateFrom(this ISourceCache + /// + /// public static IDisposable PopulateInto(this IObservable> source, ISourceCache destination) where TObject : notnull where TKey : notnull @@ -3595,6 +3621,7 @@ public static IDisposable PopulateInto(this IObservablesource /// or /// destination. + /// public static IDisposable PopulateInto(this IObservable> source, IIntermediateCache destination) where TObject : notnull where TKey : notnull @@ -3613,6 +3640,7 @@ public static IDisposable PopulateInto(this IObservableThe source. /// The destination. /// A disposable which will unsubscribe from the source. + /// public static IDisposable PopulateInto(this IObservable> source, LockFreeObservableCache destination) where TObject : notnull where TKey : notnull @@ -3708,6 +3736,7 @@ public static IObservable> RefCount(thi /// The source. /// The item. /// source. + /// public static void Refresh(this ISourceCache source, TObject item) where TObject : notnull where TKey : notnull @@ -3725,6 +3754,8 @@ public static void Refresh(this ISourceCache sourc /// The source. /// The items. /// source. + /// + /// public static void Refresh(this ISourceCache source, IEnumerable items) where TObject : notnull where TKey : notnull @@ -3741,6 +3772,7 @@ public static void Refresh(this ISourceCache sourc /// The type of the key. /// The source. /// source. + /// public static void Refresh(this ISourceCache source) where TObject : notnull where TKey : notnull @@ -3759,6 +3791,7 @@ public static void Refresh(this ISourceCache sourc /// The source. /// The item. /// source. + /// public static void Remove(this ISourceCache source, TObject item) where TObject : notnull where TKey : notnull @@ -3777,6 +3810,7 @@ public static void Remove(this ISourceCache source /// The source. /// The key. /// source. + /// public static void Remove(this ISourceCache source, TKey key) where TObject : notnull where TKey : notnull @@ -3795,6 +3829,7 @@ public static void Remove(this ISourceCache source /// The source. /// The items. /// source. + /// public static void Remove(this ISourceCache source, IEnumerable items) where TObject : notnull where TKey : notnull @@ -3813,6 +3848,11 @@ public static void Remove(this ISourceCache source /// The source. /// The keys. /// source. + /// + /// + /// + /// + /// public static void Remove(this ISourceCache source, IEnumerable keys) where TObject : notnull where TKey : notnull @@ -3831,6 +3871,7 @@ public static void Remove(this ISourceCache source /// The source. /// The key. /// source. + /// public static void Remove(this IIntermediateCache source, TKey key) where TObject : notnull where TKey : notnull @@ -3849,6 +3890,7 @@ public static void Remove(this IIntermediateCache /// The source. /// The keys. /// source. + /// public static void Remove(this IIntermediateCache source, IEnumerable keys) where TObject : notnull where TKey : notnull @@ -3868,6 +3910,7 @@ public static void Remove(this IIntermediateCache /// The type of key. /// The source. /// An observable which emits change sets. + /// public static IObservable> RemoveKey(this IObservable> source) where TObject : notnull where TKey : notnull @@ -3891,6 +3934,7 @@ public static IObservable> RemoveKey(this IOb /// The source. /// The key. /// source. + /// public static void RemoveKey(this ISourceCache source, TKey key) where TObject : notnull where TKey : notnull @@ -4481,6 +4525,7 @@ public static IObservable> ToObservableChangeSetOptional instance used to determine if an object value has changed. /// An observable optional. /// source is null. + /// public static IObservable> ToObservableOptional(this IObservable> source, TKey key, IEqualityComparer? equalityComparer = null) where TObject : notnull where TKey : notnull @@ -4501,6 +4546,7 @@ public static IObservable> ToObservableOptional /// Optional instance used to determine if an object value has changed. /// An observable optional. /// source is null. + /// public static IObservable> ToObservableOptional(this IObservable> source, TKey key, bool initialOptionalWhenMissing, IEqualityComparer? equalityComparer = null) where TObject : notnull where TKey : notnull @@ -4529,6 +4575,7 @@ public static IObservable> ToObservableOptional /// The sort function. /// The sort order. Defaults to ascending. /// An observable which emits the read only collection. + /// public static IObservable> ToSortedCollection(this IObservable> source, Func sort, SortDirection sortOrder = SortDirection.Ascending) where TObject : notnull where TKey : notnull @@ -4542,6 +4589,7 @@ public static IObservable> ToSortedCollectionThe source. /// The sort comparer. /// An observable which emits the read only collection. + /// public static IObservable> ToSortedCollection(this IObservable> source, IComparer comparer) where TObject : notnull where TKey : notnull => source.QueryWhenChanged( @@ -5936,6 +5984,7 @@ static IEnumerable> ReplaceMoves(IChangeSet /// The equality condition. /// An observable which boolean values indicating if true. /// source. + /// public static IObservable TrueForAll(this IObservable> source, Func> observableSelector, Func equalityCondition) where TObject : notnull where TKey : notnull @@ -5959,6 +6008,7 @@ public static IObservable TrueForAll(this IObservab /// The equality condition. /// An observable which boolean values indicating if true. /// source. + /// public static IObservable TrueForAll(this IObservable> source, Func> observableSelector, Func equalityCondition) where TObject : notnull where TKey : notnull @@ -5984,6 +6034,7 @@ public static IObservable TrueForAll(this IObservab /// or /// equalityCondition. /// + /// public static IObservable TrueForAny(this IObservable> source, Func> observableSelector, Func equalityCondition) where TObject : notnull where TKey : notnull @@ -6009,6 +6060,7 @@ public static IObservable TrueForAny(this IObservab /// or /// equalityCondition. /// + /// public static IObservable TrueForAny(this IObservable> source, Func> observableSelector, Func equalityCondition) where TObject : notnull where TKey : notnull @@ -6058,6 +6110,7 @@ public static IObservable> Watch(this IObse /// The key. /// An observable which emits the object value. /// source. + /// public static IObservable WatchValue(this IObservableCache source, TKey key) where TObject : notnull where TKey : notnull @@ -6076,6 +6129,7 @@ public static IObservable WatchValue(this IObservableCac /// The key. /// An observable which emits the object value. /// source. + /// public static IObservable WatchValue(this IObservable> source, TKey key) where TObject : notnull where TKey : notnull diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 3240a11b6..6fc17e9a7 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -28,7 +28,7 @@ public static class ObservableListEx /// The adaptor's Adapt method is called for each changeset under a synchronized lock, then the changeset is forwarded downstream. /// /// The type of items in the list. - /// The source of . + /// The source of . /// The adaptor whose Adapt method is invoked for each changeset. /// A list changeset stream identical to the source, with the adaptor side effect applied. /// or is . @@ -71,7 +71,7 @@ public static IObservable> Adapt(this IObservable /// /// The type of items in the list. /// The type of the key. - /// The source of . + /// The source of . /// A function to extract a unique key from each item. /// A cache changeset stream ( of ) with keyed items. /// @@ -96,8 +96,8 @@ public static IObservable> AddKey(this /// Only items present in ALL sources appear in the result. /// /// The type of items in the lists. - /// The primary source of . - /// Additional changeset streams to intersect with. + /// The primary source of . + /// The additional changeset streams to intersect with. /// A list changeset stream containing items that exist in every source. /// /// @@ -141,13 +141,13 @@ public static IObservable> And(this IObservableList sources.Combine(CombineOperator.And); /// - /// An of . Each inner list's changes are connected automatically. + /// An of . Each inner list's changes are connected automatically. /// This overload accepts instances directly, calling Connect() internally. public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); /// - /// An of . Each inner list's changes are connected automatically. + /// An of . Each inner list's changes are connected automatically. /// This overload accepts instances directly, calling Connect() internally. public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); @@ -172,7 +172,7 @@ public static IObservableList AsObservableList(this ISourceList source) /// The list is kept in sync with the source stream for the lifetime of the subscription. /// /// The type of items in the list. - /// The source of . + /// The source of . /// A read-only observable list reflecting the current state of the stream. /// is . /// @@ -189,9 +189,9 @@ public static IObservableList AsObservableList(this IObservable /// The type of items, which must implement . - /// The source of . - /// Optional buffer duration to batch multiple refresh signals into a single changeset. - /// Optional throttle applied to each item's property change notifications. + /// The source of . + /// An optional buffer duration to batch multiple refresh signals into a single changeset. + /// An optional throttle applied to each item's property change notifications. /// The scheduler for throttle and buffer timing. Defaults to . /// A list changeset stream with additional Refresh changes injected when properties change. /// @@ -238,10 +238,10 @@ public static IObservable> AutoRefresh(this IObserv /// /// The type of items in the list. Must implement . /// The type of the monitored property. - /// The source of . + /// The source of . /// An expression selecting the specific property to monitor. - /// Optional buffer duration to batch refresh signals. - /// Optional throttle per item's property change notifications. + /// An optional buffer duration to batch refresh signals. + /// An optional throttle per item's property change notifications. /// The for throttle and buffer timing. /// This overload monitors a single property instead of all properties. More efficient when only one property affects downstream operators. public static IObservable> AutoRefresh(this IObservable> source, Expression> propertyAccessor, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) @@ -270,9 +270,9 @@ public static IObservable> AutoRefresh(t /// /// The type of items in the list. /// The type emitted by the re-evaluator observable (value is ignored). - /// The source of . + /// The source of . /// A factory that, given an item, returns an observable whose emissions trigger a Refresh for that item. - /// Optional buffer duration to batch refresh signals into a single changeset. + /// An optional buffer duration to batch refresh signals into a single changeset. /// The for buffering. /// A list changeset stream with additional Refresh changes injected when per-item observables fire. /// @@ -308,7 +308,7 @@ public static IObservable> AutoRefreshOnObservable for UI data binding. /// /// The type of items in the list. - /// The source of . + /// The source of . /// The target collection to keep in sync. /// When a changeset exceeds this many changes, the collection is reset instead of applying individual changes. /// A continuation of the source changeset stream (allows further chaining). @@ -355,7 +355,7 @@ public static IObservable> Bind(this IObservable> } /// - /// The source of . + /// The source of . /// The target collection to keep in sync. /// options controlling reset threshold and other behaviors. /// This overload accepts a struct for fine-grained control over binding behavior. @@ -370,8 +370,8 @@ public static IObservable> Bind(this IObservable> } /// - /// The source of . - /// Output parameter receiving the created . + /// The source of . + /// An output parameter receiving the created . /// When a changeset exceeds this many changes, the collection is reset. /// This overload creates a via an out parameter, backed by an internal ObservableCollectionExtended. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) @@ -390,8 +390,8 @@ public static IObservable> Bind(this IObservable> } /// - /// The source of . - /// Output parameter receiving the created . + /// The source of . + /// An output parameter receiving the created . /// options controlling reset threshold and other behaviors. /// This overload creates a with for fine-grained control. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, BindingOptions options) @@ -449,10 +449,10 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. - /// The source of . - /// An of that controls buffering: pauses (buffers), resumes (flushes). + /// The source of . + /// An of that controls buffering: pauses (buffers), resumes (flushes). /// The initial pause state. When , buffering starts immediately. - /// Optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. + /// An optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. /// The for timeout scheduling. /// A list changeset stream that buffers during pause and emits combined changesets on resume. /// or is . @@ -486,7 +486,7 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. - /// The source of . + /// The source of . /// The time period (measured from first emission) during which changes are buffered. /// The for timing the buffer window. /// A list changeset stream where the initial burst is combined into one changeset. @@ -511,7 +511,7 @@ public static IObservable> BufferInitial(this IObse /// Casts each item in the changeset from object to using a direct cast. /// /// The target type to cast to. - /// The source of . of object items. + /// The source of . of object items. /// A list changeset stream of cast items. /// /// @@ -528,7 +528,7 @@ public static IObservable> Cast(this IObs /// /// The source item type. /// The destination item type. - /// The source of . + /// The source of . /// A function to convert each item from to . /// A list changeset stream of converted items. /// Use this overload when type inference requires explicit specification of both source and destination types. Alternatively, call first, then the single-type-parameter overload. @@ -549,7 +549,7 @@ public static IObservable> Cast( /// Casts each item in the changeset to object. Typically used before to work around type inference limitations. /// /// The source item type (must be a reference type). - /// The source of . + /// The source of . /// A list changeset stream of object items. /// public static IObservable> CastToObject(this IObservable> source) @@ -559,7 +559,7 @@ public static IObservable> CastToObject(this IObservable /// The type of items in the list. - /// The source of . + /// The source of . /// The target list to clone changes into. /// A continuation of the source changeset stream. /// is . @@ -582,7 +582,7 @@ public static IObservable> Clone(this IObservable /// /// The type of the object. /// The type of the destination. - /// The source of . + /// The source of . /// The conversion factory. /// An observable which emits the change set. [Obsolete("Prefer Cast as it is does the same thing but is semantically correct")] @@ -601,7 +601,7 @@ public static IObservable> Convert /// The type of the object. - /// The source of . + /// The source of . /// A list changeset stream that begins emitting only after the source has produced its first changeset. /// is . /// @@ -644,7 +644,7 @@ public static IObservable> DeferUntilLoaded(this IObservableLis /// All remaining tracked items are disposed when the stream finalizes (OnCompleted, OnError, or subscription disposal). /// /// The type of the object. - /// The source of . + /// The source of . /// A continuation of the source changeset stream with disposal side effects applied. /// is . /// @@ -679,7 +679,7 @@ public static IObservable> DisposeMany(this IObservable /// The type of items in the source list. /// The type of distinct values produced. - /// The source of . + /// The source of . /// A function that extracts the value to track from each source item. /// A list changeset stream of distinct values. /// or is . @@ -718,8 +718,8 @@ public static IObservable> DistinctValues(th /// Items present in the first source but not in any of the are included in the result. /// /// The type of the item. - /// The primary source of . - /// The other changeset streams to exclude from the result. + /// The primary source of . + /// The other changeset streams to exclude from the result. /// A list changeset stream containing items from that are not in any of . /// is . /// @@ -788,7 +788,7 @@ public static IObservable> Except(this IObservableListThe type of the item. /// The source list to monitor and remove expired items from. /// A function returning the time-to-live for each item. Return for items that should never expire. - /// Optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. + /// An optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. /// The scheduler for scheduling expiry timers. Defaults to . /// An observable that emits collections of items each time expired items are removed from the source list. /// @@ -821,7 +821,7 @@ public static IObservable> ExpireAfter( /// Only items satisfying are included downstream. /// /// The type of items in the list. - /// The source of . to filter. + /// The source of . to filter. /// A predicate that determines which items are included. Items returning appear downstream; items returning are excluded. /// A list changeset stream containing only items that satisfy . /// Thrown when or is . @@ -859,9 +859,9 @@ public static IObservable> Filter( /// When emits a new function, all items are re-evaluated. /// /// The type of the item. - /// The source of . - /// An that emits new predicate functions. Each emission triggers a full re-evaluation of all items. - /// Controls re-filtering behavior: (default) computes the minimal diff between old and new results; clears and repopulates entirely. + /// The source of . + /// An that emits new predicate functions. Each emission triggers a full re-evaluation of all items. + /// The that controls re-filtering behavior: (default) computes the minimal diff between old and new results; clears and repopulates entirely. /// A list changeset stream containing only items that satisfy the most recent predicate. /// /// @@ -901,10 +901,10 @@ public static IObservable> Filter(this IObservable /// The type of the item. /// The type of state value required by . - /// The source of . - /// An stream of state values to be passed to . + /// The source of . + /// An stream of state values to be passed to . /// A predicate receiving the current state and an item, returning to include or to exclude. - /// Controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. + /// The that controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. /// When (default), empty changesets are suppressed. Set to to publish empty changesets (useful for monitoring loading status). /// A list changeset stream containing only items satisfying with the current state. /// , , or is . @@ -947,9 +947,9 @@ public static IObservable> Filter( /// When an item's observable emits the item enters the result; when it emits the item is removed. /// /// The type of the object. - /// The source of . + /// The source of . /// A function that returns an observable of for each item, controlling its inclusion. - /// Optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. + /// An optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. /// The used when throttling. Defaults to the system default scheduler. /// A list changeset stream containing only items whose per-item observable most recently emitted . /// or is . @@ -990,10 +990,10 @@ public static IObservable> FilterOnObservable(this /// /// The type of the object. Must implement . /// The type of the property. - /// The source of . + /// The source of . /// selecting the property to monitor for changes. /// A predicate evaluated against the item to determine inclusion. - /// Optional throttle duration for property change notifications. + /// An optional throttle duration for property change notifications. /// The used when throttling. /// A list changeset stream of items satisfying the predicate, re-evaluated on property changes. /// @@ -1034,7 +1034,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// The changeset is forwarded downstream unchanged. /// /// The type of the object. - /// The source of . + /// The source of . /// The action invoked for each . Range changes (AddRange, RemoveRange, Clear) are received as a single with a populated Range property. /// A continuation of the source changeset stream. /// or is . @@ -1067,8 +1067,8 @@ public static IObservable> ForEachChange(this IObse /// Range changes are flattened into individual item changes first, so the callback only receives Add, Replace, Remove, and Refresh. /// /// The type of the object. - /// The source of . - /// The action invoked for each individual item change. + /// The source of . + /// The action invoked for each individual item change. /// A continuation of the source changeset stream. /// or is . /// @@ -1094,9 +1094,9 @@ public static IObservable> ForEachItemChange(this I /// /// The type of the object. /// The type of the group key. - /// The source of . + /// The source of . /// A function that returns the group key for each item. - /// Optional of that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). + /// An optional of that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). /// A list changeset stream of objects, each containing the items belonging to that group. /// or is . /// @@ -1135,9 +1135,9 @@ public static IObservable>> GroupOn /// The type of the object. Must implement . /// The type of the group key. - /// The source of . + /// The source of . /// selecting the property whose value determines the group key. - /// Optional throttle duration for property change notifications. + /// An optional throttle duration for property change notifications. /// The used when throttling. /// A list changeset stream of objects. /// or is . @@ -1167,9 +1167,9 @@ public static IObservable>> GroupOnProperty /// The type of the object. Must implement . /// The type of the group key. - /// The source of . + /// The source of . /// selecting the property whose value determines the group key. - /// Optional throttle duration for property change notifications. + /// An optional throttle duration for property change notifications. /// The used when throttling. /// A list changeset stream of immutable group snapshots. /// or is . @@ -1200,9 +1200,9 @@ public static IObservable>> GroupOnProperty /// The type of the object. /// The type of the group key. - /// The source of . + /// The source of . /// A function that returns the group key for each item. - /// Optional of that forces all items to be re-evaluated when it fires. + /// An optional of that forces all items to be re-evaluated when it fires. /// A list changeset stream of immutable snapshots. /// or is . /// @@ -1268,7 +1268,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// /// The type of items in the source list. /// The type of values emitted by per-item observables. - /// The source of . + /// The source of . /// A function that returns an observable for each source item. /// An observable that emits values from all per-item observables, merged together. /// or is . @@ -1307,7 +1307,7 @@ public static IObservable MergeMany(this IObserva /// /// The type of the object. /// The source of nested changeset observables. - /// Optional used by the merge tracker to compare items. + /// An optional used by the merge tracker to compare items. /// A single list changeset stream containing all changes from all inner streams. /// is . /// @@ -1344,10 +1344,10 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges two list changeset streams into a single unified stream. /// - /// The first of changeset stream. - /// The second of changeset stream to merge with. - /// Optional used to compare items. - /// Optional for scheduling enumeration. + /// The first of changeset stream. + /// The second of changeset stream to merge with. + /// An optional used to compare items. + /// An optional for scheduling enumeration. /// When (default), the result completes when all sources complete. public static IObservable> MergeChangeSets(this IObservable> source, IObservable> other, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull @@ -1362,10 +1362,10 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges the source list changeset stream with additional changeset streams into a single unified stream. /// - /// The primary of changeset stream. - /// Additional of list changeset streams to merge with. - /// Optional used to compare items. - /// Optional for scheduling enumeration. + /// The primary of changeset stream. + /// The additional of list changeset streams to merge with. + /// An optional used to compare items. + /// An optional for scheduling enumeration. /// When (default), the result completes when all sources complete. public static IObservable> MergeChangeSets(this IObservable> source, IEnumerable>> others, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull @@ -1382,8 +1382,8 @@ public static IObservable> MergeChangeSets(this IOb /// /// The type of the object. /// The collection of list changeset streams to merge. - /// Optional used by the merge tracker to compare items. - /// Optional for scheduling enumeration. + /// An optional used by the merge tracker to compare items. + /// An optional for scheduling enumeration. /// When (default), the result completes when all sources complete. /// A single list changeset stream containing all changes from all sources. /// is . @@ -1435,7 +1435,7 @@ public static IObservable> MergeChangeSets(this IOb /// The type of the object. /// The type of the object key. /// The of cache changeset observables. - /// to resolve which value wins when the same key appears in multiple sources. + /// to resolve which value wins when the same key appears in multiple sources. /// A single cache changeset stream with key-based deduplication. /// is . /// @@ -1457,8 +1457,8 @@ public static IObservable> MergeChangeSets into a single cache changeset stream, with optional equality and ordering comparers. /// /// The of cache changeset observables. - /// Optional to determine if two elements are the same. - /// Optional to resolve conflicts when the same key appears in multiple sources. + /// An optional to determine if two elements are the same. + /// An optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservableList>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) where TObject : notnull where TKey : notnull @@ -1473,7 +1473,7 @@ public static IObservable> MergeChangeSets /// The source of whose items are cache changeset observables. - /// to resolve which value wins when the same key appears in multiple sources. + /// to resolve which value wins when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IComparer comparer) where TObject : notnull where TKey : notnull @@ -1488,8 +1488,8 @@ public static IObservable> MergeChangeSets /// The source of whose items are cache changeset observables. - /// Optional to determine if two elements are the same. - /// Optional to resolve conflicts when the same key appears in multiple sources. + /// An optional to determine if two elements are the same. + /// An optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) where TObject : notnull where TKey : notnull @@ -1505,9 +1505,9 @@ public static IObservable> MergeChangeSets /// The type of items in the source list. /// The type of items in the child changeset streams. - /// The source of . + /// The source of . /// A function that returns a child list changeset stream for each source item. - /// Optional used to compare child items. + /// An optional used to compare child items. /// A single list changeset stream containing all items from all child streams. /// or is . /// @@ -1552,9 +1552,9 @@ public static IObservable> MergeManyChangeSetsThe type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source of . + /// The source of . /// A function that returns a child cache changeset stream for each source item. - /// to resolve which value wins when the same key appears from multiple children. + /// to resolve which value wins when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. /// , , or is . /// @@ -1580,10 +1580,10 @@ public static IObservable> MergeManyCh /// The type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source of . + /// The source of . /// A function that returns a child cache changeset stream for each source item. - /// Optional to determine if two elements are the same. - /// Optional to resolve conflicts when the same key appears from multiple children. + /// An optional to determine if two elements are the same. + /// An optional to resolve conflicts when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. /// or is . /// @@ -1610,7 +1610,7 @@ public static IObservable> MergeManyCh /// Suppresses empty changesets from the stream. Only changesets with at least one change are forwarded. /// /// The type of the item. - /// The source of . + /// The source of . /// A list changeset stream with empty changesets filtered out. /// is . /// @@ -1628,7 +1628,7 @@ public static IObservable> NotEmpty(this IObservable, , and the new item of . /// /// The type of items in the list. - /// The source of . + /// The source of . /// The action to invoke for each added item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is . @@ -1661,7 +1661,7 @@ public static IObservable> OnItemAdded( /// Invokes for every item with a change in the source stream. /// /// The type of items in the list. - /// The source of . + /// The source of . /// The action to invoke for each refreshed item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is . @@ -1682,7 +1682,7 @@ public static IObservable> OnItemRefreshed( /// Triggers on , , , and the old item of . /// /// The type of items in the list. - /// The source of . + /// The source of . /// The action to invoke for each removed item. /// When (default), is also invoked for all remaining tracked items upon stream disposal, completion, or error. /// A continuation of the source changeset stream, with the side effect applied before forwarding. @@ -1731,8 +1731,8 @@ public static IObservable> Or(this ICollection /// The type of the item. - /// The primary source of . - /// The other changeset streams to combine with. + /// The primary source of . + /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in at least one source. /// is . /// @@ -1788,7 +1788,7 @@ public static IObservable> Or(this IObservableList) are included downstream. /// /// The type of the item. - /// The source of . + /// The source of . /// An observable of controlling which page to display (page number and page size). /// An stream containing only items within the current page window. /// or is . @@ -1816,7 +1816,7 @@ public static IObservable> Page(this IObservable . /// /// The type of the object. - /// The source of . + /// The source of . /// The destination to receive all changes. /// An representing the subscription. Dispose to stop piping changes. /// or is . @@ -1840,7 +1840,7 @@ public static IDisposable PopulateInto(this IObservable> source /// /// The type of items in the list. /// The type of the projected result. - /// The source of . + /// The source of . /// A function projecting the current list snapshot to a result value. /// An observable emitting the projected value after each changeset. /// or is . @@ -1864,7 +1864,7 @@ public static IObservable QueryWhenChanged( /// Maintains an internal list updated by cloning each changeset. /// /// The type of items in the list. - /// The source of . + /// The source of . /// An observable emitting the full list snapshot as after each change. /// is . /// @@ -1893,7 +1893,7 @@ public static IObservable> QueryWhenChanged(this IObse /// The shared list is created on the first subscriber and disposed when the last subscriber unsubscribes. /// /// The type of the item. - /// The source of . + /// The source of . /// A list changeset stream backed by a shared, reference-counted . /// is . /// @@ -1912,7 +1912,7 @@ public static IObservable> RefCount(this IObservable /// The type of the object. - /// The source of . + /// The source of . /// A list changeset stream with all index values removed from changes. /// is . /// @@ -1931,7 +1931,7 @@ public static IObservable> RemoveIndex(this IObservablenew_index = length - old_index - 1. /// /// The type of the item. - /// The source of . + /// The source of . /// A list changeset stream with all index positions reversed. /// is . /// @@ -1952,7 +1952,7 @@ public static IObservable> Reverse(this IObservable /// The type of the object. - /// The source of . + /// The source of . /// A list changeset stream that omits the initial snapshot. /// is . /// @@ -1969,11 +1969,11 @@ public static IObservable> SkipInitial(this IObservable /// The type of the item. - /// The source of . + /// The source of . /// The comparer used for sorting. - /// Sort options. Use for improved performance when sorted values are immutable. - /// Optional of that forces a full re-sort when it fires. Required when sorted property values are mutable. - /// Optional of that replaces the comparer, triggering a full re-sort. + /// The for improved performance when sorted values are immutable. + /// An optional of that forces a full re-sort when it fires. Required when sorted property values are mutable. + /// An optional of that replaces the comparer, triggering a full re-sort. /// When the number of changes exceeds this threshold, a full reset is performed instead of incremental updates. Default is 50. /// A list changeset stream with items in sorted order. /// or is . @@ -2012,11 +2012,11 @@ public static IObservable> Sort(this IObservable> /// /// Sorts the list using an observable comparer. The initial comparer is taken from the first emission; subsequent emissions trigger a full re-sort. /// - /// The source of . - /// An of that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. + /// The source of . + /// An of that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. /// for controlling sort behavior. - /// Optional of to force a re-sort with the current comparer. - /// Threshold for triggering a full reset instead of incremental updates. + /// An optional of to force a re-sort with the current comparer. + /// The threshold for triggering a full reset instead of incremental updates. public static IObservable> Sort(this IObservable> source, IObservable> comparerChanged, SortOptions options = SortOptions.None, IObservable? resort = null, int resetThreshold = 50) where T : notnull { @@ -2030,7 +2030,7 @@ public static IObservable> Sort(this IObservable> /// Prepends an empty changeset to the source stream. Useful for initializing downstream consumers that expect an initial emission. /// /// The type of item. - /// The source of . + /// The source of . /// A list changeset stream that begins with an empty changeset. /// /// @@ -2043,7 +2043,7 @@ public static IObservable> StartWithEmpty(this IObservable /// The type of the object. - /// The source of . + /// The source of . /// A function that creates an for each item. /// A continuation of the source changeset stream with per-item subscriptions managed as a side effect. /// or is . @@ -2074,7 +2074,7 @@ public static IObservable> SubscribeMany(this IObservable changes from the stream. All other change reasons pass through. /// /// The type of the object. - /// The source of . + /// The source of . /// A list changeset stream with Refresh changes removed. /// /// @@ -2105,7 +2105,7 @@ public static IObservable> Switch(this IObservable /// The type of the object. - /// The source of nested changeset observables. + /// An of changeset streams. The operator subscribes to the latest inner stream. /// A list changeset stream reflecting the most recently received inner changeset stream. /// is . /// @@ -2127,7 +2127,7 @@ public static IObservable> Switch(this IObservable after every changeset. Equivalent to QueryWhenChanged(items => items). /// /// The type of the object. - /// The source of . + /// The source of . /// An observable emitting the full collection snapshot after each change. /// /// @@ -2140,7 +2140,7 @@ public static IObservable> ToCollection(th /// /// The type of the object. /// The source . - /// Optional for time-based operations (expiry, size limiting). + /// An optional for time-based operations (expiry, size limiting). /// A list changeset stream where each source emission is an Add. /// is . /// @@ -2170,7 +2170,7 @@ public static IObservable> ToObservableChangeSet( /// /// The source . /// A function returning the time-to-live for each item. Return for non-expiring items. - /// Optional for expiry timers. + /// An optional for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable source, Func expireAfter, @@ -2188,8 +2188,8 @@ public static IObservable> ToObservableChangeSet( /// When the list exceeds , the oldest items are removed. /// /// The source . - /// Maximum list size. Supply -1 to disable size limiting. - /// Optional for scheduling removals. + /// The maximum list size. Supply -1 to disable size limiting. + /// An optional for scheduling removals. public static IObservable> ToObservableChangeSet( this IObservable source, int limitSizeTo, @@ -2207,8 +2207,8 @@ public static IObservable> ToObservableChangeSet( /// /// The source . /// A function returning the time-to-live for each item. Return for non-expiring items. - /// Maximum list size. Supply -1 to disable size limiting. - /// Optional for expiry timers and size-limit checks. + /// The maximum list size. Supply -1 to disable size limiting. + /// An optional for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( this IObservable source, Func? expireAfter, @@ -2226,8 +2226,8 @@ public static IObservable> ToObservableChangeSet( /// Bridges an of batches into a list changeset stream. /// Each emitted batch becomes an AddRange. /// - /// The source of . - /// Optional for time-based operations. + /// The source of . + /// An optional for time-based operations. public static IObservable> ToObservableChangeSet( this IObservable> source, IScheduler? scheduler = null) @@ -2242,9 +2242,9 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with FIFO size limiting. /// - /// The source of . - /// Maximum list size. Oldest items are removed when the limit is exceeded. - /// Optional for scheduling removals. + /// The source of . + /// The maximum list size. Oldest items are removed when the limit is exceeded. + /// An optional for scheduling removals. public static IObservable> ToObservableChangeSet( this IObservable> source, int limitSizeTo, @@ -2260,9 +2260,9 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with time-based expiry. /// - /// The source of . + /// The source of . /// A function returning the time-to-live for each item. Return for non-expiring items. - /// Optional for expiry timers. + /// An optional for expiry timers. public static IObservable> ToObservableChangeSet( this IObservable> source, Func expireAfter, @@ -2278,10 +2278,10 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The source of . + /// The source of . /// A function returning the time-to-live for each item. Return for non-expiring items. - /// Maximum list size. Oldest items removed when exceeded. - /// Optional for expiry timers and size-limit checks. + /// The maximum list size. Oldest items removed when exceeded. + /// An optional for expiry timers and size-limit checks. public static IObservable> ToObservableChangeSet( this IObservable> source, Func? expireAfter, @@ -2298,7 +2298,7 @@ public static IObservable> ToObservableChangeSet( /// Takes the first items from the source list. Implemented as Virtualise with a fixed window starting at index 0. /// /// The type of the item. - /// The source of . + /// The source of . /// The maximum number of items to include. Must be greater than zero. /// A virtual changeset stream containing at most items from the beginning of the source. /// is . @@ -2327,7 +2327,7 @@ public static IObservable> Top(this IObservable> /// /// The type of the object. /// The type of the sort key. - /// The source of . + /// The source of . /// A function extracting the sort key from each item. /// The sort direction. Defaults to ascending. /// An observable emitting a sorted collection snapshot after each change. @@ -2341,8 +2341,8 @@ public static IObservable> ToSortedCollection after every changeset, sorted using the specified . /// /// The type of the object. - /// The source of . - /// The comparer used for sorting. + /// The source of . + /// The comparer used for sorting. /// An observable emitting a sorted collection snapshot after each change. /// /// @@ -2360,7 +2360,7 @@ public static IObservable> ToSortedCollection /// The type of the source. /// The type of the destination. - /// The source of . + /// The source of . /// The transform function applied to each item. /// When , Refresh events re-invoke the factory and emit an update. When (the default), Refresh is forwarded without re-transforming. /// A list changeset stream of transformed items. @@ -2404,7 +2404,7 @@ public static IObservable> Transform /// Projects each item using a transform function that also receives the item's index. /// - /// The source of . + /// The source of . /// A function receiving the source item and its index, returning the transformed item. /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) @@ -2422,7 +2422,7 @@ public static IObservable> Transform - /// The source of . + /// The source of . /// A function receiving the source item and the previous transformed value (as ), returning the new transformed item. /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, TDestination> transformFactory, bool transformOnRefresh = false) @@ -2440,7 +2440,7 @@ public static IObservable> Transform - /// The source of . + /// The source of . /// A function receiving the source item, previous transformed value, and index. /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, int, TDestination> transformFactory, bool transformOnRefresh = false) @@ -2458,7 +2458,7 @@ public static IObservable> Transform /// The type of the source. /// The type of the destination. - /// The source of . + /// The source of . /// An async function that transforms each source item. /// When , Refresh events re-invoke the factory. /// A list changeset stream of asynchronously transformed items. @@ -2554,9 +2554,9 @@ public static IObservable> TransformAsync /// The type of the destination items. /// The type of the source items. - /// The source of . + /// The source of . /// A function that returns the child items for each source item. - /// Optional comparer used during Replace to determine which child items changed between old and new parent values. + /// An optional comparer used during Replace to determine which child items changed between old and new parent values. /// A list changeset stream of all child items from all source items. /// or is . /// @@ -2612,7 +2612,7 @@ public static IObservable> TransformMany /// The type of the item. - /// The source of . + /// The source of . /// An observable of specifying the start index and size of the window. /// An stream containing only items within the current virtual window. /// or is . @@ -2640,8 +2640,8 @@ public static IObservable> Virtualise(this IObservable. /// /// The type of the object. Must implement . - /// The source of . - /// Optional list of property names to monitor. If empty, all property changes are observed. + /// The source of . + /// An optional list of property names to monitor. If empty, all property changes are observed. /// An observable emitting the item whenever any monitored property changes. /// is . /// @@ -2666,7 +2666,7 @@ public static IObservable> Virtualise(this IObservable /// The type of item. Must implement . /// The type of the property value. - /// The source of . + /// The source of . /// An expression selecting the property to observe. /// When (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting whenever the property changes on any tracked item. @@ -2694,7 +2694,7 @@ public static IObservable> WhenPropertyChanged /// The type of item. Must implement . /// The type of the property value. - /// The source of . + /// The source of . /// An expression selecting the property to observe. /// When (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting the property value whenever it changes on any tracked item. @@ -2717,7 +2717,7 @@ public static IObservable> WhenPropertyChanged /// The type of the item. - /// The source of . + /// The source of . /// The change reasons to include. Must specify at least one. /// A list changeset stream containing only changes with the specified reasons. /// is . @@ -2761,7 +2761,7 @@ public static IObservable> WhereReasonsAre(this IObservable is excluded, since removing Refresh does not affect index calculations. /// /// The type of the item. - /// The source of . + /// The source of . /// The change reasons to exclude. Must specify at least one. /// A list changeset stream with the specified change reasons removed. /// is . @@ -2809,8 +2809,8 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// Items present in exactly one source are included in the result. /// /// The type of the item. - /// The primary source of . - /// The other changeset streams to combine with. + /// The primary source of . + /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in exactly one source. /// is . /// From 3f3e6d49d22617873ddf7eaab8575568801d27f6 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 13:16:39 -0700 Subject: [PATCH 12/22] Perfect param descriptions: purpose verbs, combined crefs, no redundancy - Add operator-specific purpose verbs to 81 source params - Combine all split IObservable{T}/IChangeSet crefs into single nested format - Remove 'changeset stream' redundancy after IChangeSet type references - Fix remaining grammar and article issues --- src/DynamicData/List/ObservableListEx.cs | 180 +++++++++++------------ 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 6fc17e9a7..79c08e669 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -28,7 +28,7 @@ public static class ObservableListEx /// The adaptor's Adapt method is called for each changeset under a synchronized lock, then the changeset is forwarded downstream. /// /// The type of items in the list. - /// The source of . + /// The source to observe and adapt. /// The adaptor whose Adapt method is invoked for each changeset. /// A list changeset stream identical to the source, with the adaptor side effect applied. /// or is . @@ -71,9 +71,9 @@ public static IObservable> Adapt(this IObservable /// /// The type of items in the list. /// The type of the key. - /// The source of . + /// The source to add keys to, converting to a cache changeset. /// A function to extract a unique key from each item. - /// A cache changeset stream ( of ) with keyed items. + /// A cache changeset stream with keyed items. /// /// /// All index information is dropped during conversion because cache changesets are unordered by default. @@ -96,7 +96,7 @@ public static IObservable> AddKey(this /// Only items present in ALL sources appear in the result. /// /// The type of items in the lists. - /// The primary source of . + /// The primary source to intersect. /// The additional changeset streams to intersect with. /// A list changeset stream containing items that exist in every source. /// @@ -172,7 +172,7 @@ public static IObservableList AsObservableList(this ISourceList source) /// The list is kept in sync with the source stream for the lifetime of the subscription. /// /// The type of items in the list. - /// The source of . + /// The source to materialize into a read-only list. /// A read-only observable list reflecting the current state of the stream. /// is . /// @@ -189,7 +189,7 @@ public static IObservableList AsObservableList(this IObservable /// The type of items, which must implement . - /// The source of . + /// The source to monitor for property-driven refresh signals. /// An optional buffer duration to batch multiple refresh signals into a single changeset. /// An optional throttle applied to each item's property change notifications. /// The scheduler for throttle and buffer timing. Defaults to . @@ -238,7 +238,7 @@ public static IObservable> AutoRefresh(this IObserv /// /// The type of items in the list. Must implement . /// The type of the monitored property. - /// The source of . + /// The source to monitor for property-driven refresh signals. /// An expression selecting the specific property to monitor. /// An optional buffer duration to batch refresh signals. /// An optional throttle per item's property change notifications. @@ -270,7 +270,7 @@ public static IObservable> AutoRefresh(t /// /// The type of items in the list. /// The type emitted by the re-evaluator observable (value is ignored). - /// The source of . + /// The source to monitor for observable-driven refresh signals. /// A factory that, given an item, returns an observable whose emissions trigger a Refresh for that item. /// An optional buffer duration to batch refresh signals into a single changeset. /// The for buffering. @@ -308,7 +308,7 @@ public static IObservable> AutoRefreshOnObservable for UI data binding. /// /// The type of items in the list. - /// The source of . + /// The source to bind to a collection. /// The target collection to keep in sync. /// When a changeset exceeds this many changes, the collection is reset instead of applying individual changes. /// A continuation of the source changeset stream (allows further chaining). @@ -355,7 +355,7 @@ public static IObservable> Bind(this IObservable> } /// - /// The source of . + /// The source to bind to a collection. /// The target collection to keep in sync. /// options controlling reset threshold and other behaviors. /// This overload accepts a struct for fine-grained control over binding behavior. @@ -370,7 +370,7 @@ public static IObservable> Bind(this IObservable> } /// - /// The source of . + /// The source to bind to a collection. /// An output parameter receiving the created . /// When a changeset exceeds this many changes, the collection is reset. /// This overload creates a via an out parameter, backed by an internal ObservableCollectionExtended. @@ -390,7 +390,7 @@ public static IObservable> Bind(this IObservable> } /// - /// The source of . + /// The source to bind to a collection. /// An output parameter receiving the created . /// options controlling reset threshold and other behaviors. /// This overload creates a with for fine-grained control. @@ -409,7 +409,7 @@ public static IObservable> Bind(this IObservable> #if SUPPORTS_BINDINGLIST /// - /// The source of . + /// The source to bind to a collection. /// The target to keep in sync. /// When a changeset exceeds this many changes, the list is reset. /// This overload binds to a (WinForms binding). Uses a an internal binding list adaptor internally. @@ -449,7 +449,7 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. - /// The source of . + /// The source to conditionally buffer. /// An of that controls buffering: pauses (buffers), resumes (flushes). /// The initial pause state. When , buffering starts immediately. /// An optional maximum duration to keep the buffer open. After this time, the buffer is flushed regardless of pause state. @@ -486,7 +486,7 @@ public static IObservable> BufferIf(this IObservable /// The type of items in the list. - /// The source of . + /// The source to buffer during the initial loading period. /// The time period (measured from first emission) during which changes are buffered. /// The for timing the buffer window. /// A list changeset stream where the initial burst is combined into one changeset. @@ -511,7 +511,7 @@ public static IObservable> BufferInitial(this IObse /// Casts each item in the changeset from object to using a direct cast. /// /// The target type to cast to. - /// The source of . of object items. + /// The source of object items. /// A list changeset stream of cast items. /// /// @@ -528,7 +528,7 @@ public static IObservable> Cast(this IObs /// /// The source item type. /// The destination item type. - /// The source of . + /// The source to cast. /// A function to convert each item from to . /// A list changeset stream of converted items. /// Use this overload when type inference requires explicit specification of both source and destination types. Alternatively, call first, then the single-type-parameter overload. @@ -549,7 +549,7 @@ public static IObservable> Cast( /// Casts each item in the changeset to object. Typically used before to work around type inference limitations. /// /// The source item type (must be a reference type). - /// The source of . + /// The source to cast to object. /// A list changeset stream of object items. /// public static IObservable> CastToObject(this IObservable> source) @@ -559,7 +559,7 @@ public static IObservable> CastToObject(this IObservable /// The type of items in the list. - /// The source of . + /// The source to clone. /// The target list to clone changes into. /// A continuation of the source changeset stream. /// is . @@ -582,7 +582,7 @@ public static IObservable> Clone(this IObservable /// /// The type of the object. /// The type of the destination. - /// The source of . + /// The source to convert. /// The conversion factory. /// An observable which emits the change set. [Obsolete("Prefer Cast as it is does the same thing but is semantically correct")] @@ -601,7 +601,7 @@ public static IObservable> Convert /// The type of the object. - /// The source of . + /// The source to defer until the first changeset arrives. /// A list changeset stream that begins emitting only after the source has produced its first changeset. /// is . /// @@ -644,7 +644,7 @@ public static IObservable> DeferUntilLoaded(this IObservableLis /// All remaining tracked items are disposed when the stream finalizes (OnCompleted, OnError, or subscription disposal). /// /// The type of the object. - /// The source of . + /// The source to track for disposal on removal. /// A continuation of the source changeset stream with disposal side effects applied. /// is . /// @@ -679,7 +679,7 @@ public static IObservable> DisposeMany(this IObservable /// The type of items in the source list. /// The type of distinct values produced. - /// The source of . + /// The source to extract distinct values from. /// A function that extracts the value to track from each source item. /// A list changeset stream of distinct values. /// or is . @@ -718,7 +718,7 @@ public static IObservable> DistinctValues(th /// Items present in the first source but not in any of the are included in the result. /// /// The type of the item. - /// The primary source of . + /// The primary source to subtract from. /// The other changeset streams to exclude from the result. /// A list changeset stream containing items from that are not in any of . /// is . @@ -821,7 +821,7 @@ public static IObservable> ExpireAfter( /// Only items satisfying are included downstream. /// /// The type of items in the list. - /// The source of . to filter. + /// The source to filter. /// A predicate that determines which items are included. Items returning appear downstream; items returning are excluded. /// A list changeset stream containing only items that satisfy . /// Thrown when or is . @@ -859,7 +859,7 @@ public static IObservable> Filter( /// When emits a new function, all items are re-evaluated. /// /// The type of the item. - /// The source of . + /// The source to filter. /// An that emits new predicate functions. Each emission triggers a full re-evaluation of all items. /// The that controls re-filtering behavior: (default) computes the minimal diff between old and new results; clears and repopulates entirely. /// A list changeset stream containing only items that satisfy the most recent predicate. @@ -901,7 +901,7 @@ public static IObservable> Filter(this IObservable /// The type of the item. /// The type of state value required by . - /// The source of . + /// The source to filter. /// An stream of state values to be passed to . /// A predicate receiving the current state and an item, returning to include or to exclude. /// The that controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. @@ -947,7 +947,7 @@ public static IObservable> Filter( /// When an item's observable emits the item enters the result; when it emits the item is removed. /// /// The type of the object. - /// The source of . + /// The source to filter by property value. /// A function that returns an observable of for each item, controlling its inclusion. /// An optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. /// The used when throttling. Defaults to the system default scheduler. @@ -990,7 +990,7 @@ public static IObservable> FilterOnObservable(this /// /// The type of the object. Must implement . /// The type of the property. - /// The source of . + /// The source to filter by property value. /// selecting the property to monitor for changes. /// A predicate evaluated against the item to determine inclusion. /// An optional throttle duration for property change notifications. @@ -1034,7 +1034,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// The changeset is forwarded downstream unchanged. /// /// The type of the object. - /// The source of . + /// The source to observe each change in. /// The action invoked for each . Range changes (AddRange, RemoveRange, Clear) are received as a single with a populated Range property. /// A continuation of the source changeset stream. /// or is . @@ -1067,7 +1067,7 @@ public static IObservable> ForEachChange(this IObse /// Range changes are flattened into individual item changes first, so the callback only receives Add, Replace, Remove, and Refresh. /// /// The type of the object. - /// The source of . + /// The source to observe each item-level change in. /// The action invoked for each individual item change. /// A continuation of the source changeset stream. /// or is . @@ -1094,7 +1094,7 @@ public static IObservable> ForEachItemChange(this I /// /// The type of the object. /// The type of the group key. - /// The source of . + /// The source to group. /// A function that returns the group key for each item. /// An optional of that forces all items to be re-evaluated against when it fires. Useful for time-based groupings (e.g., "Last Hour", "Today"). /// A list changeset stream of objects, each containing the items belonging to that group. @@ -1135,7 +1135,7 @@ public static IObservable>> GroupOn /// The type of the object. Must implement . /// The type of the group key. - /// The source of . + /// The source to group by property value. /// selecting the property whose value determines the group key. /// An optional throttle duration for property change notifications. /// The used when throttling. @@ -1167,7 +1167,7 @@ public static IObservable>> GroupOnProperty /// The type of the object. Must implement . /// The type of the group key. - /// The source of . + /// The source to group by property value with immutable snapshots. /// selecting the property whose value determines the group key. /// An optional throttle duration for property change notifications. /// The used when throttling. @@ -1200,7 +1200,7 @@ public static IObservable>> GroupOnProperty /// The type of the object. /// The type of the group key. - /// The source of . + /// The source to group with immutable snapshots. /// A function that returns the group key for each item. /// An optional of that forces all items to be re-evaluated when it fires. /// A list changeset stream of immutable snapshots. @@ -1268,7 +1268,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// /// The type of items in the source list. /// The type of values emitted by per-item observables. - /// The source of . + /// The source to subscribe to per-item observables from. /// A function that returns an observable for each source item. /// An observable that emits values from all per-item observables, merged together. /// or is . @@ -1344,8 +1344,8 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges two list changeset streams into a single unified stream. /// - /// The first of changeset stream. - /// The second of changeset stream to merge with. + /// The first to merge. + /// The second . /// An optional used to compare items. /// An optional for scheduling enumeration. /// When (default), the result completes when all sources complete. @@ -1362,7 +1362,7 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges the source list changeset stream with additional changeset streams into a single unified stream. /// - /// The primary of changeset stream. + /// The primary source to merge. /// The additional of list changeset streams to merge with. /// An optional used to compare items. /// An optional for scheduling enumeration. @@ -1472,7 +1472,7 @@ public static IObservable> MergeChangeSets /// Merges cache changeset streams from a list changeset of cache changeset observables, using a comparer for conflict resolution. /// - /// The source of whose items are cache changeset observables. + /// The source whose items are cache changeset observables. /// to resolve which value wins when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IComparer comparer) where TObject : notnull @@ -1487,7 +1487,7 @@ public static IObservable> MergeChangeSets /// Merges cache changeset streams from a list changeset of cache changeset observables, with optional equality and ordering comparers. /// - /// The source of whose items are cache changeset observables. + /// The source whose items are cache changeset observables. /// An optional to determine if two elements are the same. /// An optional to resolve conflicts when the same key appears in multiple sources. public static IObservable> MergeChangeSets(this IObservable>>> source, IEqualityComparer? equalityComparer = null, IComparer? comparer = null) @@ -1505,7 +1505,7 @@ public static IObservable> MergeChangeSets /// The type of items in the source list. /// The type of items in the child changeset streams. - /// The source of . + /// The source to subscribe to per-item changeset streams from. /// A function that returns a child list changeset stream for each source item. /// An optional used to compare child items. /// A single list changeset stream containing all items from all child streams. @@ -1552,7 +1552,7 @@ public static IObservable> MergeManyChangeSetsThe type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source of . + /// The source to subscribe to per-item changeset streams from. /// A function that returns a child cache changeset stream for each source item. /// to resolve which value wins when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. @@ -1580,7 +1580,7 @@ public static IObservable> MergeManyCh /// The type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source of . + /// The source to subscribe to per-item changeset streams from. /// A function that returns a child cache changeset stream for each source item. /// An optional to determine if two elements are the same. /// An optional to resolve conflicts when the same key appears from multiple children. @@ -1610,7 +1610,7 @@ public static IObservable> MergeManyCh /// Suppresses empty changesets from the stream. Only changesets with at least one change are forwarded. /// /// The type of the item. - /// The source of . + /// The source to suppress empty changesets from. /// A list changeset stream with empty changesets filtered out. /// is . /// @@ -1628,7 +1628,7 @@ public static IObservable> NotEmpty(this IObservable, , and the new item of . /// /// The type of items in the list. - /// The source of . + /// The source to observe item additions in. /// The action to invoke for each added item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is . @@ -1661,7 +1661,7 @@ public static IObservable> OnItemAdded( /// Invokes for every item with a change in the source stream. /// /// The type of items in the list. - /// The source of . + /// The source to observe item refresh events in. /// The action to invoke for each refreshed item. /// A continuation of the source changeset stream, with the side effect applied before forwarding. /// or is . @@ -1682,7 +1682,7 @@ public static IObservable> OnItemRefreshed( /// Triggers on , , , and the old item of . /// /// The type of items in the list. - /// The source of . + /// The source to observe item removals in. /// The action to invoke for each removed item. /// When (default), is also invoked for all remaining tracked items upon stream disposal, completion, or error. /// A continuation of the source changeset stream, with the side effect applied before forwarding. @@ -1731,7 +1731,7 @@ public static IObservable> Or(this ICollection /// The type of the item. - /// The primary source of . + /// The primary source to union. /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in at least one source. /// is . @@ -1788,7 +1788,7 @@ public static IObservable> Or(this IObservableList) are included downstream. /// /// The type of the item. - /// The source of . + /// The source to page. /// An observable of controlling which page to display (page number and page size). /// An stream containing only items within the current page window. /// or is . @@ -1816,7 +1816,7 @@ public static IObservable> Page(this IObservable . /// /// The type of the object. - /// The source of . + /// The source to populate a target list from. /// The destination to receive all changes. /// An representing the subscription. Dispose to stop piping changes. /// or is . @@ -1840,7 +1840,7 @@ public static IDisposable PopulateInto(this IObservable> source /// /// The type of items in the list. /// The type of the projected result. - /// The source of . + /// The source to project on each change. /// A function projecting the current list snapshot to a result value. /// An observable emitting the projected value after each changeset. /// or is . @@ -1864,7 +1864,7 @@ public static IObservable QueryWhenChanged( /// Maintains an internal list updated by cloning each changeset. /// /// The type of items in the list. - /// The source of . + /// The source to project on each change. /// An observable emitting the full list snapshot as after each change. /// is . /// @@ -1893,7 +1893,7 @@ public static IObservable> QueryWhenChanged(this IObse /// The shared list is created on the first subscriber and disposed when the last subscriber unsubscribes. /// /// The type of the item. - /// The source of . + /// The source to share via reference counting. /// A list changeset stream backed by a shared, reference-counted . /// is . /// @@ -1912,7 +1912,7 @@ public static IObservable> RefCount(this IObservable /// The type of the object. - /// The source of . + /// The source to strip index information from. /// A list changeset stream with all index values removed from changes. /// is . /// @@ -1931,7 +1931,7 @@ public static IObservable> RemoveIndex(this IObservablenew_index = length - old_index - 1. /// /// The type of the item. - /// The source of . + /// The source to reverse. /// A list changeset stream with all index positions reversed. /// is . /// @@ -1952,7 +1952,7 @@ public static IObservable> Reverse(this IObservable /// The type of the object. - /// The source of . + /// The source to skip the initial changeset from. /// A list changeset stream that omits the initial snapshot. /// is . /// @@ -1969,8 +1969,8 @@ public static IObservable> SkipInitial(this IObservable /// The type of the item. - /// The source of . - /// The comparer used for sorting. + /// The source to sort. + /// The used for sorting. /// The for improved performance when sorted values are immutable. /// An optional of that forces a full re-sort when it fires. Required when sorted property values are mutable. /// An optional of that replaces the comparer, triggering a full re-sort. @@ -2012,7 +2012,7 @@ public static IObservable> Sort(this IObservable> /// /// Sorts the list using an observable comparer. The initial comparer is taken from the first emission; subsequent emissions trigger a full re-sort. /// - /// The source of . + /// The source to sort. /// An of that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. /// for controlling sort behavior. /// An optional of to force a re-sort with the current comparer. @@ -2030,7 +2030,7 @@ public static IObservable> Sort(this IObservable> /// Prepends an empty changeset to the source stream. Useful for initializing downstream consumers that expect an initial emission. /// /// The type of item. - /// The source of . + /// The source to prepend an empty changeset to. /// A list changeset stream that begins with an empty changeset. /// /// @@ -2043,7 +2043,7 @@ public static IObservable> StartWithEmpty(this IObservable /// The type of the object. - /// The source of . + /// The source to create per-item subscriptions from. /// A function that creates an for each item. /// A continuation of the source changeset stream with per-item subscriptions managed as a side effect. /// or is . @@ -2074,7 +2074,7 @@ public static IObservable> SubscribeMany(this IObservable changes from the stream. All other change reasons pass through. /// /// The type of the object. - /// The source of . + /// The source to strip refresh events from. /// A list changeset stream with Refresh changes removed. /// /// @@ -2127,7 +2127,7 @@ public static IObservable> Switch(this IObservable after every changeset. Equivalent to QueryWhenChanged(items => items). /// /// The type of the object. - /// The source of . + /// The source to materialize into a collection on each change. /// An observable emitting the full collection snapshot after each change. /// /// @@ -2139,7 +2139,7 @@ public static IObservable> ToCollection(th /// Each emission becomes an Add operation in the resulting changeset stream. /// /// The type of the object. - /// The source . + /// The source to convert into a changeset stream. /// An optional for time-based operations (expiry, size limiting). /// A list changeset stream where each source emission is an Add. /// is . @@ -2168,7 +2168,7 @@ public static IObservable> ToObservableChangeSet( /// Bridges an into a list changeset stream with per-item time-based expiry. /// Expired items are automatically removed. /// - /// The source . + /// The source to convert into a changeset stream. /// A function returning the time-to-live for each item. Return for non-expiring items. /// An optional for expiry timers. public static IObservable> ToObservableChangeSet( @@ -2187,7 +2187,7 @@ public static IObservable> ToObservableChangeSet( /// Bridges an into a list changeset stream with FIFO size limiting. /// When the list exceeds , the oldest items are removed. /// - /// The source . + /// The source to convert into a changeset stream. /// The maximum list size. Supply -1 to disable size limiting. /// An optional for scheduling removals. public static IObservable> ToObservableChangeSet( @@ -2205,7 +2205,7 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The source . + /// The source to convert into a changeset stream. /// A function returning the time-to-live for each item. Return for non-expiring items. /// The maximum list size. Supply -1 to disable size limiting. /// An optional for expiry timers and size-limit checks. @@ -2226,7 +2226,7 @@ public static IObservable> ToObservableChangeSet( /// Bridges an of batches into a list changeset stream. /// Each emitted batch becomes an AddRange. /// - /// The source of . + /// The source of to convert into a changeset stream. /// An optional for time-based operations. public static IObservable> ToObservableChangeSet( this IObservable> source, @@ -2242,7 +2242,7 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with FIFO size limiting. /// - /// The source of . + /// The source of to convert into a changeset stream. /// The maximum list size. Oldest items are removed when the limit is exceeded. /// An optional for scheduling removals. public static IObservable> ToObservableChangeSet( @@ -2260,7 +2260,7 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with time-based expiry. /// - /// The source of . + /// The source of to convert into a changeset stream. /// A function returning the time-to-live for each item. Return for non-expiring items. /// An optional for expiry timers. public static IObservable> ToObservableChangeSet( @@ -2278,7 +2278,7 @@ public static IObservable> ToObservableChangeSet( /// /// Bridges an of batches into a list changeset stream with both time-based expiry and FIFO size limiting. /// - /// The source of . + /// The source of to convert into a changeset stream. /// A function returning the time-to-live for each item. Return for non-expiring items. /// The maximum list size. Oldest items removed when exceeded. /// An optional for expiry timers and size-limit checks. @@ -2298,7 +2298,7 @@ public static IObservable> ToObservableChangeSet( /// Takes the first items from the source list. Implemented as Virtualise with a fixed window starting at index 0. /// /// The type of the item. - /// The source of . + /// The source to take the top items from. /// The maximum number of items to include. Must be greater than zero. /// A virtual changeset stream containing at most items from the beginning of the source. /// is . @@ -2327,7 +2327,7 @@ public static IObservable> Top(this IObservable> /// /// The type of the object. /// The type of the sort key. - /// The source of . + /// The source to materialize into a sorted collection on each change. /// A function extracting the sort key from each item. /// The sort direction. Defaults to ascending. /// An observable emitting a sorted collection snapshot after each change. @@ -2341,8 +2341,8 @@ public static IObservable> ToSortedCollection after every changeset, sorted using the specified . /// /// The type of the object. - /// The source of . - /// The comparer used for sorting. + /// The source to materialize into a sorted collection on each change. + /// The used for sorting. /// An observable emitting a sorted collection snapshot after each change. /// /// @@ -2360,7 +2360,7 @@ public static IObservable> ToSortedCollection /// The type of the source. /// The type of the destination. - /// The source of . + /// The source to transform. /// The transform function applied to each item. /// When , Refresh events re-invoke the factory and emit an update. When (the default), Refresh is forwarded without re-transforming. /// A list changeset stream of transformed items. @@ -2404,7 +2404,7 @@ public static IObservable> Transform /// Projects each item using a transform function that also receives the item's index. /// - /// The source of . + /// The source to transform. /// A function receiving the source item and its index, returning the transformed item. /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) @@ -2422,7 +2422,7 @@ public static IObservable> Transform - /// The source of . + /// The source to transform. /// A function receiving the source item and the previous transformed value (as ), returning the new transformed item. /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, TDestination> transformFactory, bool transformOnRefresh = false) @@ -2440,7 +2440,7 @@ public static IObservable> Transform - /// The source of . + /// The source to transform. /// A function receiving the source item, previous transformed value, and index. /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, int, TDestination> transformFactory, bool transformOnRefresh = false) @@ -2458,7 +2458,7 @@ public static IObservable> Transform /// The type of the source. /// The type of the destination. - /// The source of . + /// The source to transform asynchronously. /// An async function that transforms each source item. /// When , Refresh events re-invoke the factory. /// A list changeset stream of asynchronously transformed items. @@ -2554,9 +2554,9 @@ public static IObservable> TransformAsync /// The type of the destination items. /// The type of the source items. - /// The source of . + /// The source to expand each item into multiple children. /// A function that returns the child items for each source item. - /// An optional comparer used during Replace to determine which child items changed between old and new parent values. + /// An optional used during Replace to determine which child items changed between old and new parent values. /// A list changeset stream of all child items from all source items. /// or is . /// @@ -2612,7 +2612,7 @@ public static IObservable> TransformMany /// The type of the item. - /// The source of . + /// The source to virtualize. /// An observable of specifying the start index and size of the window. /// An stream containing only items within the current virtual window. /// or is . @@ -2640,7 +2640,7 @@ public static IObservable> Virtualise(this IObservable. /// /// The type of the object. Must implement . - /// The source of . + /// The source to observe property changes on items in. /// An optional list of property names to monitor. If empty, all property changes are observed. /// An observable emitting the item whenever any monitored property changes. /// is . @@ -2666,7 +2666,7 @@ public static IObservable> Virtualise(this IObservable /// The type of item. Must implement . /// The type of the property value. - /// The source of . + /// The source to observe a specific property on items in. /// An expression selecting the property to observe. /// When (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting whenever the property changes on any tracked item. @@ -2694,7 +2694,7 @@ public static IObservable> WhenPropertyChanged /// The type of item. Must implement . /// The type of the property value. - /// The source of . + /// The source to observe a specific property value on items in. /// An expression selecting the property to observe. /// When (default), the current value is emitted immediately upon subscribing to each item. /// An observable emitting the property value whenever it changes on any tracked item. @@ -2717,7 +2717,7 @@ public static IObservable> WhenPropertyChanged /// The type of the item. - /// The source of . + /// The source to filter by change reason. /// The change reasons to include. Must specify at least one. /// A list changeset stream containing only changes with the specified reasons. /// is . @@ -2761,7 +2761,7 @@ public static IObservable> WhereReasonsAre(this IObservable is excluded, since removing Refresh does not affect index calculations. /// /// The type of the item. - /// The source of . + /// The source to filter by excluding change reasons. /// The change reasons to exclude. Must specify at least one. /// A list changeset stream with the specified change reasons removed. /// is . @@ -2809,7 +2809,7 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// Items present in exactly one source are included in the result. /// /// The type of the item. - /// The primary source of . + /// The primary source to exclusively combine. /// The other changeset streams to combine with. /// A list changeset stream containing items that exist in exactly one source. /// is . From 5d147a57f3a4532417b7205714bb954676a14400 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 15:04:54 -0700 Subject: [PATCH 13/22] Fix review findings: dangling prepositions, missing purposes - Rewrite dangling 'from.' prepositions in MergeMany/SubscribeMany params - Add purpose to readOnlyObservableCollection and MergeChangeSets other params - Fix 'to suppress/strip/skip X from.' trailing prepositions --- src/DynamicData/List/ObservableListEx.cs | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 79c08e669..9001f9f8e 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -371,7 +371,7 @@ public static IObservable> Bind(this IObservable> /// /// The source to bind to a collection. - /// An output parameter receiving the created . + /// An output parameter that receives the created , bound to the sorted results. /// When a changeset exceeds this many changes, the collection is reset. /// This overload creates a via an out parameter, backed by an internal ObservableCollectionExtended. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) @@ -391,7 +391,7 @@ public static IObservable> Bind(this IObservable> /// /// The source to bind to a collection. - /// An output parameter receiving the created . + /// An output parameter that receives the created , bound to the sorted results. /// options controlling reset threshold and other behaviors. /// This overload creates a with for fine-grained control. public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, BindingOptions options) @@ -679,7 +679,7 @@ public static IObservable> DisposeMany(this IObservable /// The type of items in the source list. /// The type of distinct values produced. - /// The source to extract distinct values from. + /// The source to extract distinct values. /// A function that extracts the value to track from each source item. /// A list changeset stream of distinct values. /// or is . @@ -1268,7 +1268,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// /// The type of items in the source list. /// The type of values emitted by per-item observables. - /// The source to subscribe to per-item observables from. + /// The source whose items each produce an observable. /// A function that returns an observable for each source item. /// An observable that emits values from all per-item observables, merged together. /// or is . @@ -1345,7 +1345,7 @@ public static IObservable> MergeChangeSets(this IOb /// Merges two list changeset streams into a single unified stream. /// /// The first to merge. - /// The second . + /// The second to merge with. /// An optional used to compare items. /// An optional for scheduling enumeration. /// When (default), the result completes when all sources complete. @@ -1505,7 +1505,7 @@ public static IObservable> MergeChangeSets /// The type of items in the source list. /// The type of items in the child changeset streams. - /// The source to subscribe to per-item changeset streams from. + /// The source whose items each produce a child changeset stream. /// A function that returns a child list changeset stream for each source item. /// An optional used to compare child items. /// A single list changeset stream containing all items from all child streams. @@ -1552,7 +1552,7 @@ public static IObservable> MergeManyChangeSetsThe type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source to subscribe to per-item changeset streams from. + /// The source whose items each produce a child changeset stream. /// A function that returns a child cache changeset stream for each source item. /// to resolve which value wins when the same key appears from multiple children. /// A single cache changeset stream with key-based deduplication. @@ -1580,7 +1580,7 @@ public static IObservable> MergeManyCh /// The type of items in the source list. /// The type of items in the child cache changeset streams. /// The type of the key in the child cache changesets. - /// The source to subscribe to per-item changeset streams from. + /// The source whose items each produce a child changeset stream. /// A function that returns a child cache changeset stream for each source item. /// An optional to determine if two elements are the same. /// An optional to resolve conflicts when the same key appears from multiple children. @@ -1610,7 +1610,7 @@ public static IObservable> MergeManyCh /// Suppresses empty changesets from the stream. Only changesets with at least one change are forwarded. /// /// The type of the item. - /// The source to suppress empty changesets from. + /// The source to suppress empty changesets. /// A list changeset stream with empty changesets filtered out. /// is . /// @@ -1816,7 +1816,7 @@ public static IObservable> Page(this IObservable . /// /// The type of the object. - /// The source to populate a target list from. + /// The source to pipe into a target list. /// The destination to receive all changes. /// An representing the subscription. Dispose to stop piping changes. /// or is . @@ -1952,7 +1952,7 @@ public static IObservable> Reverse(this IObservable /// The type of the object. - /// The source to skip the initial changeset from. + /// The source to skip the initial changeset. /// A list changeset stream that omits the initial snapshot. /// is . /// @@ -2043,7 +2043,7 @@ public static IObservable> StartWithEmpty(this IObservable /// The type of the object. - /// The source to create per-item subscriptions from. + /// The source to create a subscription for each item in. /// A function that creates an for each item. /// A continuation of the source changeset stream with per-item subscriptions managed as a side effect. /// or is . @@ -2074,7 +2074,7 @@ public static IObservable> SubscribeMany(this IObservable changes from the stream. All other change reasons pass through. /// /// The type of the object. - /// The source to strip refresh events from. + /// The source to strip refresh events. /// A list changeset stream with Refresh changes removed. /// /// From cc8bddff0f04193c296a52cf898947d69be8f2d6 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Tue, 14 Apr 2026 15:51:20 -0700 Subject: [PATCH 14/22] Eliminate trailing prepositions in param descriptions Rewrite dangling 'from.' prepositions in Except, ExpireAfter, LimitSizeTo, RemoveIndex, and Top source params. --- src/DynamicData/List/ObservableListEx.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 9001f9f8e..22d7f0231 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -718,7 +718,7 @@ public static IObservable> DistinctValues(th /// Items present in the first source but not in any of the are included in the result. /// /// The type of the item. - /// The primary source to subtract from. + /// The primary from which other streams are subtracted. /// The other changeset streams to exclude from the result. /// A list changeset stream containing items from that are not in any of . /// is . @@ -786,7 +786,7 @@ public static IObservable> Except(this IObservableList /// The type of the item. - /// The source list to monitor and remove expired items from. + /// The source list to apply time-based expiration to. /// A function returning the time-to-live for each item. Return for items that should never expire. /// An optional polling interval to batch expiry checks. If omitted, a separate timer is created for each unique expiry time. /// The scheduler for scheduling expiry timers. Defaults to . @@ -1231,7 +1231,7 @@ public static IObservable>> GroupOnProperty /// The type of the item. - /// The source list to monitor and evict items from. + /// The source list to apply size limits to. /// The maximum number of items allowed. Must be greater than zero. /// The scheduler for scheduling size checks. Defaults to . /// An observable that emits collections of items each time excess items are removed from the source list. @@ -1912,7 +1912,7 @@ public static IObservable> RefCount(this IObservable /// The type of the object. - /// The source to strip index information from. + /// The source to strip index information. /// A list changeset stream with all index values removed from changes. /// is . /// @@ -2298,7 +2298,7 @@ public static IObservable> ToObservableChangeSet( /// Takes the first items from the source list. Implemented as Virtualise with a fixed window starting at index 0. /// /// The type of the item. - /// The source to take the top items from. + /// The source to take the top items. /// The maximum number of items to include. Must be greater than zero. /// A virtual changeset stream containing at most items from the beginning of the source. /// is . From b50a95e9afcc039503598d3793ad36eac718e9a6 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Fri, 17 Apr 2026 16:57:38 -0700 Subject: [PATCH 15/22] docs: add bidirectional seealso cross-links for PopulateInto, StartWithEmpty, ToCollection, ToSortedCollection These 4 operators exist on both Cache and List but had no cross-links. Now both sides link to each other for easy discovery in generated docs. --- src/DynamicData/Cache/ObservableCacheEx.cs | 4 ++++ src/DynamicData/List/ObservableListEx.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/DynamicData/Cache/ObservableCacheEx.cs b/src/DynamicData/Cache/ObservableCacheEx.cs index e532d15d1..e584131a8 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.cs @@ -4224,6 +4224,7 @@ public static IDisposable PopulateFrom(this ISourceCache or is . /// /// + /// public static IDisposable PopulateInto(this IObservable> source, ISourceCache destination) where TObject : notnull where TKey : notnull @@ -4892,6 +4893,7 @@ public static IObservable> SortBy /// The type of the key. /// The source to prepend an empty changeset to. /// An observable that emits an empty changeset first, then all source changesets. + /// public static IObservable> StartWithEmpty(this IObservable> source) where TObject : notnull where TKey : notnull => source.StartWith(ChangeSet.Empty); @@ -5102,6 +5104,7 @@ public static IObservable> Switch(this /// The type of the key. /// The source to materialize into a collection on each change. /// An observable which emits the read only collection. + /// public static IObservable> ToCollection(this IObservable> source) where TObject : notnull where TKey : notnull => source.QueryWhenChanged(query => new ReadOnlyCollectionLight(query.Items)); @@ -5254,6 +5257,7 @@ public static IObservable> ToObservableOptional /// The sort function. /// The sort order. Defaults to ascending. /// An observable which emits the read only collection. + /// public static IObservable> ToSortedCollection(this IObservable> source, Func sort, SortDirection sortOrder = SortDirection.Ascending) where TObject : notnull where TKey : notnull diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 22d7f0231..5e04db04e 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1825,6 +1825,7 @@ public static IObservable> Page(this IObservable /// /// + /// public static IDisposable PopulateInto(this IObservable> source, ISourceList destination) where T : notnull { @@ -2034,6 +2035,7 @@ public static IObservable> Sort(this IObservable> /// A list changeset stream that begins with an empty changeset. /// /// + /// public static IObservable> StartWithEmpty(this IObservable> source) where T : notnull => source.StartWith(ChangeSet.Empty); @@ -2131,6 +2133,7 @@ public static IObservable> Switch(this IObservableAn observable emitting the full collection snapshot after each change. /// /// + /// public static IObservable> ToCollection(this IObservable> source) where TObject : notnull => source.QueryWhenChanged(items => items); @@ -2334,6 +2337,7 @@ public static IObservable> Top(this IObservable> /// /// /// + /// public static IObservable> ToSortedCollection(this IObservable> source, Func sort, SortDirection sortOrder = SortDirection.Ascending) where TObject : notnull => source.QueryWhenChanged(query => sortOrder == SortDirection.Ascending ? new ReadOnlyCollectionLight(query.OrderBy(sort)) : new ReadOnlyCollectionLight(query.OrderByDescending(sort))); From bfc2899b857e5c0e98d26311c883cc0098f4149a Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 09:14:45 -0700 Subject: [PATCH 16/22] Address PR #1081 review comments - Fix anti-pattern where local short text silently overrode rich inherited remarks; converted to nested + delta pattern. - Fully qualify generic crefs and remove ambiguous /// cref attributes. - Drop redundant / tags on overloads that inherit via ; fold new-param info into summary with /. - Add tags where ThrowArgumentNullExceptionIfNull is called. - Move ListFilterPolicy enum-value semantics from ObservableListEx.Filter remarks into the enum member docs themselves. --- src/DynamicData/List/ListFilterPolicy.cs | 14 +- src/DynamicData/List/ObservableListEx.cs | 257 +++++++++++++---------- 2 files changed, 158 insertions(+), 113 deletions(-) diff --git a/src/DynamicData/List/ListFilterPolicy.cs b/src/DynamicData/List/ListFilterPolicy.cs index 690998086..8b347a765 100644 --- a/src/DynamicData/List/ListFilterPolicy.cs +++ b/src/DynamicData/List/ListFilterPolicy.cs @@ -10,14 +10,20 @@ namespace DynamicData; public enum ListFilterPolicy { /// - /// Clear all items and replace with matches - optimised for large data sets. - /// This option preserves order. + /// Clears all items and replaces with the new matches. Preserves order. + /// + /// Useful when downstream consumers (such as UI bindings) handle full resets more efficiently than individual + /// Add/Remove changes, or when the change set is expected to be very large relative to the source. + /// /// ClearAndReplace, /// - /// Calculate diff set - optimised for general filtering. - /// This option does not preserve order. + /// Calculates the minimal diff between the previous and new result sets. Does not preserve order. + /// + /// Generally preferred for performance: only items whose inclusion status actually changed produce an Add or Remove. + /// Recommended for most scenarios. + /// /// CalculateDiff } diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 5e04db04e..97fa59966 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -25,7 +25,7 @@ public static class ObservableListEx { /// /// Injects a side effect into a changeset stream via an . - /// The adaptor's Adapt method is called for each changeset under a synchronized lock, then the changeset is forwarded downstream. + /// The adaptor's Adapt method is invoked for each changeset before it is forwarded downstream unchanged. /// /// The type of items in the list. /// The source to observe and adapt. @@ -34,19 +34,11 @@ public static class ObservableListEx /// or is . /// /// - /// This operator synchronizes access with a lock, then calls adaptor.Adapt(changes) before forwarding the changeset. - /// It is the primary extension point for custom UI binding adaptors (e.g., - /// delegates to this operator). + /// This is the primary extension point for custom UI binding adaptors (e.g., + /// delegates to this operator). If the adaptor throws, the exception propagates downstream as OnError. /// - /// - /// EventBehavior - /// Add/AddRange/Replace/Remove/RemoveRange/Moved/Refresh/ClearThe adaptor's Adapt method is called with the full changeset, then it is forwarded downstream unchanged. - /// OnErrorForwarded to the downstream observer. If the adaptor throws, the exception propagates as OnError. - /// OnCompletedForwarded to the downstream observer. - /// /// /// - /// public static IObservable> Adapt(this IObservable> source, IChangeSetAdaptor adaptor) where T : notnull { @@ -74,6 +66,7 @@ public static IObservable> Adapt(this IObservable /// The source to add keys to, converting to a cache changeset. /// A function to extract a unique key from each item. /// A cache changeset stream with keyed items. + /// or is . /// /// /// All index information is dropped during conversion because cache changesets are unordered by default. @@ -96,9 +89,10 @@ public static IObservable> AddKey(this /// Only items present in ALL sources appear in the result. /// /// The type of items in the lists. - /// The primary source to intersect. + /// The first source to intersect. /// The additional changeset streams to intersect with. /// A list changeset stream containing items that exist in every source. + /// is . /// /// /// Uses reference counting per item across all sources. An item appears downstream only when @@ -107,7 +101,7 @@ public static IObservable> AddKey(this /// /// EventBehavior /// Add/AddRangeThe item's reference count is incremented in its source tracker. If the item is now present in all sources, an Add is emitted. - /// ReplaceThe old item is removed from the tracker and the new item is added. Membership is recalculated for both. + /// ReplaceThe old item's reference count is decremented and the new item's is incremented. Depending on whether each is present in ALL sources, this emits an Add, Remove, Replace, or nothing. /// Remove/RemoveRange/ClearThe item's reference count is decremented. If it was in the result and is no longer in all sources, a Remove is emitted. /// RefreshForwarded as Refresh if the item is currently in the result. /// MovedIgnored (set operations are position-independent). @@ -119,7 +113,7 @@ public static IObservable> AddKey(this /// /// /// - /// + /// public static IObservable> And(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -130,25 +124,37 @@ public static IObservable> And(this IObservable> /// /// A of changeset streams to intersect. - /// This overload accepts a pre-built collection of sources instead of params array. + /// + /// + /// This overload accepts a pre-built collection of sources instead of a params array. + /// public static IObservable> And(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.And); /// /// An of changeset streams. Sources can be added or removed dynamically. - /// This overload supports dynamic source management: adding or removing changeset streams from the observable list triggers re-evaluation. + /// + /// + /// This overload supports dynamic source management: adding or removing changeset streams from the observable list triggers re-evaluation. + /// public static IObservable> And(this IObservableList>> sources) where T : notnull => sources.Combine(CombineOperator.And); /// /// An of . Each inner list's changes are connected automatically. - /// This overload accepts instances directly, calling Connect() internally. + /// + /// + /// This overload accepts instances directly, calling Connect() internally. + /// public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); /// /// An of . Each inner list's changes are connected automatically. - /// This overload accepts instances directly, calling Connect() internally. + /// + /// + /// This overload accepts instances directly, calling Connect() internally. + /// public static IObservable> And(this IObservableList> sources) where T : notnull => sources.Combine(CombineOperator.And); @@ -175,6 +181,13 @@ public static IObservableList AsObservableList(this ISourceList source) /// The source to materialize into a read-only list. /// A read-only observable list reflecting the current state of the stream. /// is . + /// + /// + /// This is the primary way to multicast a changeset pipeline. Materializing once into an , + /// then calling Connect() on the result for each downstream consumer, ensures the upstream operators are evaluated only once + /// regardless of how many subscribers consume the result. + /// + /// /// public static IObservableList AsObservableList(this IObservable> source) where T : notnull @@ -194,6 +207,7 @@ public static IObservableList AsObservableList(this IObservableAn optional throttle applied to each item's property change notifications. /// The scheduler for throttle and buffer timing. Defaults to . /// A list changeset stream with additional Refresh changes injected when properties change. + /// is . /// /// /// Wraps using WhenAnyPropertyChanged() as the re-evaluator. @@ -215,7 +229,7 @@ public static IObservableList AsObservableList(this IObservable /// /// - /// + /// public static IObservable> AutoRefresh(this IObservable> source, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged { @@ -235,15 +249,12 @@ public static IObservable> AutoRefresh(this IObserv scheduler); } + /// + /// Monitors a single property (selected by ) on each item via + /// and emits Refresh changes when that property changes, causing downstream operators to re-evaluate. More efficient than + /// the all-properties overload when only one property (of type ) affects downstream behavior. + /// /// - /// The type of items in the list. Must implement . - /// The type of the monitored property. - /// The source to monitor for property-driven refresh signals. - /// An expression selecting the specific property to monitor. - /// An optional buffer duration to batch refresh signals. - /// An optional throttle per item's property change notifications. - /// The for throttle and buffer timing. - /// This overload monitors a single property instead of all properties. More efficient when only one property affects downstream operators. public static IObservable> AutoRefresh(this IObservable> source, Expression> propertyAccessor, TimeSpan? changeSetBuffer = null, TimeSpan? propertyChangeThrottle = null, IScheduler? scheduler = null) where TObject : INotifyPropertyChanged { @@ -275,6 +286,7 @@ public static IObservable> AutoRefresh(t /// An optional buffer duration to batch refresh signals into a single changeset. /// The for buffering. /// A list changeset stream with additional Refresh changes injected when per-item observables fire. + /// or is . /// /// /// This is the general-purpose refresh mechanism. @@ -282,7 +294,7 @@ public static IObservable> AutoRefresh(t /// /// /// EventBehavior - /// Add/AddRangeSubscribes to the re-evaluator observable for each new item via MergeMany. The original change is forwarded. + /// Add/AddRangeSubscribes to the re-evaluator observable for each new item. The original change is forwarded. /// ReplaceUnsubscribes from the old item's observable, subscribes to the new. The original change is forwarded. /// Remove/RemoveRange/ClearUnsubscribes from removed items. The original change is forwarded. /// Moved/RefreshForwarded unchanged. @@ -290,11 +302,10 @@ public static IObservable> AutoRefresh(t /// OnErrorForwarded from source or from any re-evaluator observable. /// OnCompletedForwarded when the source completes. /// - /// Worth noting: The internal index lookup (to find where each item is for the Refresh change) requires maintaining a cloned list, adding memory overhead proportional to list size. /// /// /// - /// + /// public static IObservable> AutoRefreshOnObservable(this IObservable> source, Func> reevaluator, TimeSpan? changeSetBuffer = null, IScheduler? scheduler = null) where TObject : notnull { @@ -315,7 +326,7 @@ public static IObservable> AutoRefreshOnObservable or is . /// /// - /// Delegates to with an an internal collection adaptor. + /// Delegates to with an internal collection adaptor. /// Each changeset is applied to the target collection on the calling thread. For UI binding, ensure the source is /// observed on the UI thread (e.g., via ObserveOn). /// @@ -336,7 +347,7 @@ public static IObservable> AutoRefreshOnObservable /// /// - /// + /// public static IObservable> Bind(this IObservable> source, IObservableCollection targetCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -354,11 +365,10 @@ public static IObservable> Bind(this IObservable> return source.Bind(targetCollection, options); } + /// + /// Binds the source changeset stream to , with fine-grained control over reset threshold and other behaviors. + /// /// - /// The source to bind to a collection. - /// The target collection to keep in sync. - /// options controlling reset threshold and other behaviors. - /// This overload accepts a struct for fine-grained control over binding behavior. public static IObservable> Bind(this IObservable> source, IObservableCollection targetCollection, BindingOptions options) where T : notnull { @@ -369,11 +379,16 @@ public static IObservable> Bind(this IObservable> return source.Adapt(adaptor); } + /// + /// Constructs a and binds the changeset stream to it. + /// Use this overload when you need a read-only view (typically for UI binding) without managing the backing collection yourself. + /// The created collection is returned via the output parameter. + /// /// - /// The source to bind to a collection. - /// An output parameter that receives the created , bound to the sorted results. - /// When a changeset exceeds this many changes, the collection is reset. - /// This overload creates a via an out parameter, backed by an internal ObservableCollectionExtended. + /// + /// + /// The created collection is backed by an internal ObservableCollectionExtended<T>. Callers receive only the read-only wrapper. + /// public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -389,11 +404,16 @@ public static IObservable> Bind(this IObservable> return source.Bind(out readOnlyObservableCollection, options); } + /// + /// Constructs a and binds the changeset stream to it, + /// with fine-grained control over reset threshold and other behaviors. + /// The created collection is returned via the output parameter. + /// /// - /// The source to bind to a collection. - /// An output parameter that receives the created , bound to the sorted results. - /// options controlling reset threshold and other behaviors. - /// This overload creates a with for fine-grained control. + /// + /// + /// The created collection is backed by an internal ObservableCollectionExtended<T>. Callers receive only the read-only wrapper. + /// public static IObservable> Bind(this IObservable> source, out ReadOnlyObservableCollection readOnlyObservableCollection, BindingOptions options) where T : notnull { @@ -408,11 +428,10 @@ public static IObservable> Bind(this IObservable> #if SUPPORTS_BINDINGLIST + /// + /// Binds the source changeset stream to a WinForms , keeping in sync. + /// /// - /// The source to bind to a collection. - /// The target to keep in sync. - /// When a changeset exceeds this many changes, the list is reset. - /// This overload binds to a (WinForms binding). Uses a an internal binding list adaptor internally. public static IObservable> Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this IObservable> source, BindingList bindingList, int resetThreshold = BindingOptions.DefaultResetThreshold) where T : notnull { @@ -425,12 +444,18 @@ public static IObservable> Bind(this IObservable> #endif /// - /// This overload starts unpaused and has no timeout. + /// + /// + /// This overload starts unpaused and has no timeout. + /// public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, IScheduler? scheduler = null) where T : notnull => BufferIf(source, pauseIfTrueSelector, false, scheduler); /// - /// This overload allows setting the initial pause state but has no timeout. + /// + /// + /// This overload allows setting the initial pause state but has no timeout. + /// public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, bool initialPauseState, IScheduler? scheduler = null) where T : notnull { @@ -441,7 +466,10 @@ public static IObservable> BufferIf(this IObservable - /// This overload starts unpaused and accepts a timeout but not an explicit initial pause state. + /// + /// + /// This overload starts unpaused and accepts a timeout but not an explicit initial pause state. + /// public static IObservable> BufferIf(this IObservable> source, IObservable pauseIfTrueSelector, TimeSpan? timeOut, IScheduler? scheduler = null) where T : notnull => BufferIf(source, pauseIfTrueSelector, false, timeOut, scheduler); @@ -492,8 +520,8 @@ public static IObservable> BufferIf(this IObservableA list changeset stream where the initial burst is combined into one changeset. /// /// - /// Composed from , Buffer, and . - /// After the initial buffer period, all subsequent changesets pass through immediately. + /// For a configured duration after the first emission, all changesets are buffered and combined into a single emission. + /// After this initial window, subsequent changesets pass through immediately. /// /// /// @@ -513,6 +541,7 @@ public static IObservable> BufferInitial(this IObse /// The target type to cast to. /// The source of object items. /// A list changeset stream of cast items. + /// is . /// /// public static IObservable> Cast(this IObservable> source) @@ -531,6 +560,7 @@ public static IObservable> Cast(this IObs /// The source to cast. /// A function to convert each item from to . /// A list changeset stream of converted items. + /// or is . /// Use this overload when type inference requires explicit specification of both source and destination types. Alternatively, call first, then the single-type-parameter overload. /// /// @@ -580,8 +610,8 @@ public static IObservable> Clone(this IObservable /// Convert the object using the specified conversion function. /// This is a lighter equivalent of Transform and is designed to be used with non-disposable objects. /// - /// The type of the object. - /// The type of the destination. + /// The type of items in the list. + /// The type of the destination items. /// The source to convert. /// The conversion factory. /// An observable which emits the change set. @@ -629,6 +659,7 @@ public static IObservable> DeferUntilLoaded(this IObservable /// + /// /// Convenience overload that calls source.Connect().DeferUntilLoaded(). /// public static IObservable> DeferUntilLoaded(this IObservableList source) @@ -665,7 +696,7 @@ public static IObservable> DeferUntilLoaded(this IObservableLis /// /// /// - /// + /// public static IObservable> DisposeMany(this IObservable> source) where T : notnull { @@ -699,9 +730,7 @@ public static IObservable> DisposeMany(this IObservableOnCompletedForwarded to the downstream observer. /// /// - /// - /// - /// + /// public static IObservable> DistinctValues(this IObservable> source, Func valueSelector) where TObject : notnull where TValue : notnull @@ -724,7 +753,8 @@ public static IObservable> DistinctValues(th /// is . /// /// - /// Uses reference-counted equality comparison across all sources. Items are compared by equality (not index position). + /// Item identity is determined by the default equality comparer for . Across all sources, items are tracked + /// by reference-counted equality (not by index position). /// The first source has a special role: only items from it can appear in the result, and only if they do not exist in any other source. /// /// @@ -744,7 +774,7 @@ public static IObservable> DistinctValues(th /// /// /// - /// + /// public static IObservable> Except(this IObservable> source, params IObservable>[] others) where T : notnull { @@ -755,6 +785,7 @@ public static IObservable> Except(this IObservable /// + /// /// Static overload accepting a pre-built collection of sources. The first item in the collection is the primary source. /// public static IObservable> Except(this ICollection>> sources) @@ -762,6 +793,7 @@ public static IObservable> Except(this ICollection /// + /// /// Dynamic overload: sources can be added or removed from the at runtime. The first source in the list acts as the primary. /// public static IObservable> Except(this IObservableList>> sources) @@ -769,6 +801,7 @@ public static IObservable> Except(this IObservableList /// + /// /// Dynamic overload accepting of . Each inner list's Connect() is used as a source. /// public static IObservable> Except(this IObservableList> sources) @@ -776,6 +809,7 @@ public static IObservable> Except(this IObservableList /// + /// /// Dynamic overload accepting of . Each inner list's Connect() is used as a source. /// public static IObservable> Except(this IObservableList> sources) @@ -826,7 +860,13 @@ public static IObservable> ExpireAfter( /// A list changeset stream containing only items that satisfy . /// Thrown when or is . /// - /// Use this overload when the predicate is fixed for the lifetime of the subscription. Item ordering is preserved. + /// + /// Use this overload when you need only a single predicate function for the lifetime of the subscription; + /// unlike the dynamic-predicate and state-driven overloads, the predicate function itself never changes. + /// Note that this does not mean an item's inclusion is fixed: Refresh events can re-evaluate each item against the predicate + /// and promote a previously-excluded item to included (or vice versa). + /// Item ordering is preserved. + /// /// /// EventBehavior /// AddThe predicate is evaluated. If the item passes, an Add is emitted at the calculated downstream index. Otherwise dropped. @@ -844,7 +884,7 @@ public static IObservable> ExpireAfter( /// /// /// - /// + /// public static IObservable> Filter( this IObservable> source, Func predicate) @@ -861,12 +901,11 @@ public static IObservable> Filter( /// The type of the item. /// The source to filter. /// An that emits new predicate functions. Each emission triggers a full re-evaluation of all items. - /// The that controls re-filtering behavior: (default) computes the minimal diff between old and new results; clears and repopulates entirely. + /// The that controls re-filtering behavior when the predicate changes. /// A list changeset stream containing only items that satisfy the most recent predicate. /// /// - /// Each time emits, every item is re-evaluated. The controls - /// whether this produces a minimal diff (Add/Remove for items that changed status) or a full Clear+AddRange. + /// Each time emits, every item is re-evaluated against the new predicate. /// /// /// EventBehavior @@ -876,11 +915,11 @@ public static IObservable> Filter( /// RemoveIf the item was downstream, a Remove is emitted. Otherwise dropped. /// RefreshRe-evaluated. If inclusion status changed, an Add or Remove is emitted. If unchanged, Refresh forwarded or dropped. /// ClearAll downstream items are cleared. - /// Predicate changedAll items re-evaluated against the new predicate. With , only items that changed status emit Add/Remove. With , a Clear is emitted followed by AddRange of all matching items. + /// Predicate changedAll items are re-evaluated against the new predicate. The output is shaped by . /// OnErrorForwarded from the source or from . /// OnCompletedForwarded when the source completes. Independent completion of does not terminate the filter. /// - /// Worth noting: No items are included until emits its first function. is generally preferred for performance; is useful when downstream consumers (like UI bindings) handle full resets more efficiently than individual changes. + /// Worth noting: No items are included until emits its first function. /// /// or is . /// @@ -903,8 +942,8 @@ public static IObservable> Filter(this IObservableThe type of state value required by . /// The source to filter. /// An stream of state values to be passed to . - /// A predicate receiving the current state and an item, returning to include or to exclude. - /// The that controls re-filtering behavior: (default) computes minimal diff; clears and repopulates. + /// A static predicate receiving the current state and an item, returning to include or to exclude. The function itself does not change; only the state value passed to it changes. + /// The that controls re-filtering behavior when the state changes. /// When (default), empty changesets are suppressed. Set to to publish empty changesets (useful for monitoring loading status). /// A list changeset stream containing only items satisfying with the current state. /// , , or is . @@ -920,11 +959,10 @@ public static IObservable> Filter(this IObservableRemove/RemoveRangeIf the item was downstream, a Remove is emitted. /// RefreshRe-evaluated against current state. Inclusion status may change. /// ClearAll downstream items are cleared. - /// State changedAll items re-evaluated with new state value. emits minimal Add/Remove; emits Clear then AddRange. + /// State changedAll items are re-evaluated with the new state value. The output is shaped by . /// OnErrorForwarded from the source or from . /// OnCompletedForwarded when the source completes. /// - /// Worth noting: should emit an initial value immediately upon subscription. No items are included until the first state value arrives. /// /// /// @@ -946,7 +984,7 @@ public static IObservable> Filter( /// Filters each item using a per-item of that dynamically controls inclusion. /// When an item's observable emits the item enters the result; when it emits the item is removed. /// - /// The type of the object. + /// The type of items in the list. /// The source to filter by property value. /// A function that returns an observable of for each item, controlling its inclusion. /// An optional throttle duration applied to each per-item observable to reduce re-evaluation frequency. @@ -976,7 +1014,7 @@ public static IObservable> Filter( /// /// /// - /// + /// public static IObservable> FilterOnObservable(this IObservable> source, Func> objectFilterObservable, TimeSpan? propertyChangedThrottle = null, IScheduler? scheduler = null) where TObject : notnull { @@ -1015,7 +1053,7 @@ public static IObservable> FilterOnProperty - /// Flattens a buffered list of changesets (from Rx's Buffer operator) back into a single changeset stream. + /// Flattens buffered changesets (e.g. from ) back into single changesets. /// Empty buffers are dropped. /// /// The type of the item. @@ -1030,12 +1068,13 @@ public static IObservable> FlattenBufferResult(this IObservable where T : notnull => source.Where(x => x.Count != 0).Select(updates => new ChangeSet(updates.SelectMany(u => u))); /// - /// Invokes for every in each changeset, including range changes as-is. + /// Invokes once for every in each changeset. Range changes + /// (AddRange, RemoveRange, Clear) are delivered as a single ; they are not flattened into per-item changes. /// The changeset is forwarded downstream unchanged. /// - /// The type of the object. + /// The type of items in the list. /// The source to observe each change in. - /// The action invoked for each . Range changes (AddRange, RemoveRange, Clear) are received as a single with a populated Range property. + /// The action invoked for each . /// A continuation of the source changeset stream. /// or is . /// @@ -1051,7 +1090,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// /// /// - /// + /// public static IObservable> ForEachChange(this IObservable> source, Action> action) where TObject : notnull { @@ -1066,7 +1105,7 @@ public static IObservable> ForEachChange(this IObse /// Invokes for every individual in each changeset. /// Range changes are flattened into individual item changes first, so the callback only receives Add, Replace, Remove, and Refresh. /// - /// The type of the object. + /// The type of items in the list. /// The source to observe each item-level change in. /// The action invoked for each individual item change. /// A continuation of the source changeset stream. @@ -1092,7 +1131,7 @@ public static IObservable> ForEachItemChange(this I /// Groups source items by the value returned by . Each group is an /// containing an inner observable list of its members. /// - /// The type of the object. + /// The type of items in the list. /// The type of the group key. /// The source to group. /// A function that returns the group key for each item. @@ -1198,7 +1237,7 @@ public static IObservable>> GroupOnProperty. Each update produces immutable grouping snapshots /// rather than live inner observable lists. /// - /// The type of the object. + /// The type of items in the list. /// The type of the group key. /// The source to group with immutable snapshots. /// A function that returns the group key for each item. @@ -1290,7 +1329,7 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// /// /// - /// + /// public static IObservable MergeMany(this IObservable> source, Func> observableSelector) where T : notnull { @@ -1305,7 +1344,7 @@ public static IObservable MergeMany(this IObserva /// Merges multiple list changeset streams from an observable-of-observables into a single unified changeset stream. /// Unlike cache MergeChangeSets, list merging performs no key-based deduplication. /// - /// The type of the object. + /// The type of items in the list. /// The source of nested changeset observables. /// An optional used by the merge tracker to compare items. /// A single list changeset stream containing all changes from all inner streams. @@ -1331,7 +1370,7 @@ public static IObservable MergeMany(this IObserva /// /// /// - /// + /// public static IObservable> MergeChangeSets(this IObservable>> source, IEqualityComparer? equalityComparer = null) where TObject : notnull { @@ -1380,7 +1419,7 @@ public static IObservable> MergeChangeSets(this IOb /// Merges a collection of list changeset streams into a single unified changeset stream. /// This is the primary overload that all other list MergeChangeSets overloads delegate to. /// - /// The type of the object. + /// The type of items in the list. /// The collection of list changeset streams to merge. /// An optional used by the merge tracker to compare items. /// An optional for scheduling enumeration. @@ -1432,7 +1471,7 @@ public static IObservable> MergeChangeSets(this IOb /// Merges cache changeset streams from an into a single cache changeset stream. /// Uses to resolve conflicts when the same key appears in multiple child streams. /// - /// The type of the object. + /// The type of items in the list. /// The type of the object key. /// The of cache changeset observables. /// to resolve which value wins when the same key appears in multiple sources. @@ -1527,7 +1566,7 @@ public static IObservable> MergeChangeSets /// /// - /// + /// public static IObservable> MergeManyChangeSets(this IObservable> source, Func>> observableSelector, IEqualityComparer? equalityComparer = null) where TObject : notnull where TDestination : notnull @@ -1648,7 +1687,7 @@ public static IObservable> NotEmpty(this IObservable /// /// - /// + /// public static IObservable> OnItemAdded( this IObservable> source, Action addAction) @@ -1668,7 +1707,7 @@ public static IObservable> OnItemAdded( /// /// /// - /// + /// public static IObservable> OnItemRefreshed( this IObservable> source, Action refreshAction) @@ -1707,7 +1746,7 @@ public static IObservable> OnItemRefreshed( /// /// /// - /// + /// public static IObservable> OnItemRemoved( this IObservable> source, Action removeAction, @@ -1722,7 +1761,7 @@ public static IObservable> OnItemRemoved( /// /// Applies a logical OR (union) between a pre-built collection of list changeset sources. Items present in any source are included. /// - /// + /// public static IObservable> Or(this ICollection>> sources) where T : notnull => sources.Combine(CombineOperator.Or); @@ -1850,7 +1889,7 @@ public static IDisposable PopulateInto(this IObservable> source /// /// /// - /// + /// public static IObservable QueryWhenChanged(this IObservable> source, Func, TDestination> resultSelector) where TObject : notnull { @@ -1999,7 +2038,7 @@ public static IObservable> SkipInitial(this IObservable /// /// - /// + /// public static IObservable> Sort(this IObservable> source, IComparer comparer, SortOptions options = SortOptions.None, IObservable? resort = null, IObservable>? comparerChanged = null, int resetThreshold = 50) where T : notnull { @@ -2062,7 +2101,7 @@ public static IObservable> StartWithEmpty(this IObservable /// /// - /// + /// public static IObservable> SubscribeMany(this IObservable> source, Func subscriptionFactory) where T : notnull { @@ -2128,7 +2167,7 @@ public static IObservable> Switch(this IObservable /// Emits the full collection as an after every changeset. Equivalent to QueryWhenChanged(items => items). /// - /// The type of the object. + /// The type of items in the list. /// The source to materialize into a collection on each change. /// An observable emitting the full collection snapshot after each change. /// @@ -2328,7 +2367,7 @@ public static IObservable> Top(this IObservable> /// /// Emits a sorted after every changeset, sorted by the value returned by . /// - /// The type of the object. + /// The type of items in the list. /// The type of the sort key. /// The source to materialize into a sorted collection on each change. /// A function extracting the sort key from each item. @@ -2344,7 +2383,7 @@ public static IObservable> ToSortedCollection /// Emits a sorted after every changeset, sorted using the specified . /// - /// The type of the object. + /// The type of items in the list. /// The source to materialize into a sorted collection on each change. /// The used for sorting. /// An observable emitting a sorted collection snapshot after each change. @@ -2362,8 +2401,8 @@ public static IObservable> ToSortedCollection /// Projects each item to a new form using a synchronous transform function. /// - /// The type of the source. - /// The type of the destination. + /// The type of the source items. + /// The type of the destination items. /// The source to transform. /// The transform function applied to each item. /// When , Refresh events re-invoke the factory and emit an update. When (the default), Refresh is forwarded without re-transforming. @@ -2392,7 +2431,7 @@ public static IObservable> ToSortedCollection /// /// - /// + /// public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2460,8 +2499,8 @@ public static IObservable> Transform /// Projects each item to a new form using an async transform function. Behaves like but the factory returns a . /// - /// The type of the source. - /// The type of the destination. + /// The type of the source items. + /// The type of the destination items. /// The source to transform asynchronously. /// An async function that transforms each source item. /// When , Refresh events re-invoke the factory. @@ -2483,7 +2522,7 @@ public static IObservable> TransformWorth noting: All async transforms within a single changeset are serialized (not parallel). Each changeset is fully processed before the next begins. By default, Refresh does NOT re-transform. /// /// - /// + /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Roslynator", "RCS1047:Non-asynchronous method name should not end with 'Async'.", Justification = "By Design.")] public static IObservable> TransformAsync( this IObservable> source, @@ -2576,7 +2615,7 @@ public static IObservable> TransformAsync /// /// - /// + /// public static IObservable> TransformMany(this IObservable> source, Func> manySelector, IEqualityComparer? equalityComparer = null) where TDestination : notnull where TSource : notnull @@ -2654,7 +2693,7 @@ public static IObservable> Virtualise(this IObservable /// /// - /// + /// public static IObservable WhenAnyPropertyChanged(this IObservable> source, params string[] propertiesToMonitor) where TObject : INotifyPropertyChanged { @@ -2680,7 +2719,7 @@ public static IObservable> Virtualise(this IObservable /// /// - /// + /// public static IObservable> WhenPropertyChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) where TObject : INotifyPropertyChanged { @@ -2705,7 +2744,7 @@ public static IObservable> WhenPropertyChanged or is . /// /// - /// + /// public static IObservable WhenValueChanged(this IObservable> source, Expression> propertyAccessor, bool notifyOnInitialValue = true) where TObject : INotifyPropertyChanged { @@ -2837,7 +2876,7 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// /// /// - /// + /// public static IObservable> Xor(this IObservable> source, params IObservable>[] others) where T : notnull { From fb50e0c95012135a3f32042893b6fb093e2e1c76 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 09:28:02 -0700 Subject: [PATCH 17/22] Restore Adapt per-event handling table The table was inadvertently dropped while addressing review feedback; the per-event handling tables are an intentional documentation pattern across this file. --- src/DynamicData/List/ObservableListEx.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 97fa59966..dd8b75705 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -37,6 +37,12 @@ public static class ObservableListEx /// This is the primary extension point for custom UI binding adaptors (e.g., /// delegates to this operator). If the adaptor throws, the exception propagates downstream as OnError. /// + /// + /// EventBehavior + /// Add/AddRange/Replace/Remove/RemoveRange/Moved/Refresh/ClearThe adaptor's Adapt method is called with the full changeset, then it is forwarded downstream unchanged. + /// OnErrorForwarded to the downstream observer. If the adaptor throws, the exception propagates as OnError. + /// OnCompletedForwarded to the downstream observer. + /// /// /// public static IObservable> Adapt(this IObservable> source, IChangeSetAdaptor adaptor) From e618db86dfe470beffb38b9a76e106061ec89c0b Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 09:34:28 -0700 Subject: [PATCH 18/22] Add per-change handling table to MergeManyChangeSets (list-to-cache) --- src/DynamicData/List/ObservableListEx.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index dd8b75705..a76d55e2c 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1603,6 +1603,7 @@ public static IObservable> MergeManyChangeSetsA single cache changeset stream with key-based deduplication. /// , , or is . /// + /// /// Delegates to with a equality comparer. /// /// @@ -1637,6 +1638,15 @@ public static IObservable> MergeManyCh /// When a parent item is removed, all its child items are removed from the merged output. /// When the same key appears from multiple children, determines which value wins. /// + /// + /// Event (source)Behavior + /// Add/AddRangeSubscribes to the child cache stream. Child key/value pairs are merged into the output cache. + /// ReplaceOld child subscription disposed (and its keys removed from output). New child subscription created. + /// Remove/RemoveRange/ClearChild subscription disposed. All keys originating from that child are removed from the output. + /// Moved/RefreshIgnored; this operator emits a cache changeset and source ordering/refresh does not affect key membership. + /// OnErrorForwarded from the source or any child stream. + /// OnCompletedForwarded when the source completes. + /// /// /// /// From 190f6734ee8d7f48e1c064584078559667c1361c Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 09:56:27 -0700 Subject: [PATCH 19/22] Remove useless per-change tables from XML docs Tables where every row says essentially the same thing add noise without information. Removed tables from Adapt, DeferUntilLoaded, QueryWhenChanged, WhereReasonsAre (List) and Adapt, DeferUntilLoaded, QueryWhenChanged, Refresh helper, Remove helper, Switch (Cache). The Adapt table previously restored in fb50e0c9 is removed again per follow-up review feedback. --- src/DynamicData/Cache/ObservableCacheEx.cs | 104 +-------------------- src/DynamicData/List/ObservableListEx.cs | 75 +-------------- 2 files changed, 10 insertions(+), 169 deletions(-) diff --git a/src/DynamicData/Cache/ObservableCacheEx.cs b/src/DynamicData/Cache/ObservableCacheEx.cs index e584131a8..743d31eb2 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.cs @@ -41,15 +41,6 @@ public static partial class ObservableCacheEx /// This is a thin wrapper around Rx's Do operator. The adaptor receives each changeset /// as a side effect; the changeset itself is forwarded downstream unmodified. /// - /// - /// EventBehavior - /// AddPassed to the adaptor, then forwarded. - /// UpdatePassed to the adaptor, then forwarded. - /// RemovePassed to the adaptor, then forwarded. - /// RefreshPassed to the adaptor, then forwarded. - /// OnErrorForwarded to the downstream observer. The adaptor is not called. - /// OnCompletedForwarded to the downstream observer. - /// /// /// or is . /// @@ -488,7 +479,6 @@ public static IObservable> AutoRefreshOnObservableUpdateBuffered and included in the merged changeset. /// RemoveBuffered and included in the merged changeset. /// RefreshBuffered and included in the merged changeset. - /// OnErrorForwarded to the downstream observer. /// OnCompletedAny remaining buffered changes are flushed, then completion is forwarded. /// /// Worth noting: The merged changeset may contain contradictory changes (e.g., Add then Remove for the same key). Downstream operators handle this correctly, but raw inspection of the changeset may be surprising. @@ -546,8 +536,8 @@ public static IObservable> BatchIf(this /// UpdateBuffered while paused; forwarded immediately while active. /// RemoveBuffered while paused; forwarded immediately while active. /// RefreshBuffered while paused; forwarded immediately while active. - /// OnErrorForwarded to the downstream observer. Buffered data is lost. - /// OnCompletedForwarded. Any remaining buffered data is flushed before completion. + /// OnErrorBuffered data is lost. + /// OnCompletedAny remaining buffered data is flushed before completion. /// /// Worth noting: If the source completes while paused, buffered data IS flushed before OnCompleted. However, if the source errors while paused, buffered data is lost. /// @@ -935,8 +925,6 @@ public static IObservable> BufferInitialUpdateCalls on the new value and emits an Update. /// RemoveEmits a Remove. The converter is not called. /// RefreshForwarded as Refresh. The converter is not called. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -967,8 +955,6 @@ public static IObservable> CastUpdate is called on the current item. An Update is emitted with the destination key. If the key selector produces a different destination key for the updated value than it did for the original value, downstream consumers will see an Update for a key that may not match the original Add. /// Remove is called on the item. A Remove is emitted with the destination key. /// Refresh is called on the item. A Refresh is emitted with the destination key. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -1069,8 +1055,6 @@ public static void Clear(this LockFreeObservableCacheUpdateThe previous item is removed from and the current item is added. Forwarded as Update. /// RemoveThe item is removed from . Forwarded as Remove. /// RefreshIgnored ( has no concept of refresh). Forwarded as Refresh. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// public static IObservable> Clone(this IObservable> source, ICollection target) @@ -1145,15 +1129,6 @@ public static IObservable> ConvertThe source to defer until the first changeset arrives. /// An observable that begins emitting changesets once the first non-empty changeset is received. /// - /// - /// EventBehavior - /// AddForwarded as Add once the initial non-empty changeset has been received. - /// UpdateForwarded as Update once loaded. - /// RemoveForwarded as Remove once loaded. - /// RefreshForwarded as Refresh once loaded. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. - /// /// Worth noting: Blocks indefinitely if the cache or stream never receives any data. Ensure the source will eventually emit at least one changeset. /// /// @@ -1314,8 +1289,6 @@ public static void EditDiff(this ISourceCache sour /// UpdateItems present in both snapshots that differ (per ) produce an Update. /// RemoveItems in the previous snapshot whose key is absent from the new snapshot produce a Remove. /// RefreshNot produced by this operator. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// or is . @@ -1347,8 +1320,6 @@ public static IObservable> EditDiff(thi /// UpdateEmitted when the source produces Some(value) and an item was already tracked with a different value (per ). /// RemoveEmitted when the source produces None and an item was previously tracked. /// RefreshNot produced by this operator. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// or is . @@ -1377,8 +1348,7 @@ public static IObservable> EditDiff(thi /// UpdateForwarded as Update if the key is unique within the changeset. /// RemoveForwarded as Remove if the key is unique within the changeset. /// RefreshForwarded as Refresh if the key is unique within the changeset. - /// OnErrorForwarded. Also emitted with if duplicate keys are detected in a changeset. - /// OnCompletedForwarded to the downstream observer. + /// OnErrorAlso emitted with if duplicate keys are detected in a changeset. /// /// public static IObservable> EnsureUniqueKeys(this IObservable> source) @@ -1509,8 +1479,8 @@ public static IObservable> Except(this /// UpdateResets the removal timer for the item. Forwarded as Update. /// RemoveCancels the removal timer. Forwarded as Remove. /// RefreshForwarded as Refresh. No timer change. - /// OnErrorForwarded. All pending timers are cancelled. - /// OnCompletedForwarded. All pending timers are cancelled. + /// OnErrorAll pending timers are cancelled. + /// OnCompletedAll pending timers are cancelled. /// /// Worth noting: A return from means "never expire". Update changes reset the expiration timer. /// @@ -1623,8 +1593,6 @@ public static IObservable>> ExpireAfter< /// UpdateFour outcomes: if both old and new values pass, an Update is emitted. If only the new value passes, an Add is emitted. If only the old value passed, a Remove is emitted. If neither passes, the change is dropped. /// RemoveIf the item was included downstream, a Remove is emitted. Otherwise dropped. /// RefreshThe predicate is re-evaluated. If the item now passes but previously did not, an Add is emitted. If it still passes, a Refresh is forwarded. If it no longer passes, a Remove is emitted. If it still fails, the change is dropped. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// Worth noting: Refresh events trigger re-evaluation, which can promote or demote items. Pair with for property-change-driven filtering. /// @@ -1683,8 +1651,6 @@ public static IObservable> Filter( /// UpdateRe-evaluated. Four outcomes as with the static overload. /// RemoveIf the item was included downstream, a Remove is emitted. Otherwise dropped. /// RefreshRe-evaluated against the current state. May produce Add, Refresh, Remove, or be dropped. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// Worth noting: should emit an initial value immediately. Each emission triggers a full re-evaluation of all items, which can be expensive for large collections. /// @@ -1754,8 +1720,6 @@ public static IObservable> Filter( /// UpdateFour outcomes: if both old and new values pass, an Update is emitted. If only the new value passes, an Add is emitted. If only the old value passed, a Remove is emitted. If neither passes, the change is dropped. /// RemoveIf the item was included downstream, a Remove is emitted. Otherwise dropped. /// RefreshDropped. Because items are assumed immutable, there is nothing to re-evaluate. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// public static IObservable> FilterImmutable( @@ -2137,8 +2101,6 @@ public static IObservable> GroupUpdateThe group key is re-evaluated. If unchanged, an Update is emitted within the same group. If the key changed, the item is removed from the old group (emitting Remove) and added to the new group (emitting Add). An empty old group is removed. /// RemoveThe item is removed from its group. If the group becomes empty, the group itself is removed from the output. /// RefreshThe group key is re-evaluated. If unchanged, a Refresh is forwarded within the group. If the key changed, the item moves between groups (Remove from old, Add to new). - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// Worth noting: Each group is a live sub-cache that can be subscribed to independently. Subscribers @@ -2201,8 +2163,6 @@ public static IObservable> GroupUpdateGroup key re-evaluated. Item may move between groups if the key changed. /// RemoveItem removed from its group. Empty groups are removed. /// RefreshGroup key re-evaluated. Item may move between groups. - /// OnErrorForwarded from source or from . - /// OnCompletedForwarded when the source completes. /// /// /// @@ -2380,8 +2340,6 @@ public static IObservable> Gr /// UpdateIf group key unchanged, group snapshot re-emitted. If changed, item moves between groups; both affected groups emit new snapshots. /// RemoveItem removed from group. Updated snapshot emitted. Empty groups are removed. /// RefreshGroup key re-evaluated. If changed, item moves; affected group snapshots emitted. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -2632,8 +2590,6 @@ public static IObservable> InnerJoinManyUpdateForwarded unchanged. /// RemoveForwarded unchanged. /// RefreshCalls Evaluate() on the item, then forwards the change. - /// OnErrorForwarded to subscribers. - /// OnCompletedForwarded to subscribers. /// /// public static IObservable> InvokeEvaluate(this IObservable> source) @@ -2814,8 +2770,6 @@ public static IObservable> LeftJoinManyUpdateForwarded unchanged. /// RemoveForwarded unchanged. /// RefreshForwarded unchanged. - /// OnErrorForwarded to subscribers. - /// OnCompletedForwarded to subscribers. /// /// /// is . @@ -2904,7 +2858,6 @@ public static IObservable>> LimitSizeTo< /// RemoveDisposes the child subscription for the removed item. /// RefreshNo effect on subscriptions. The child observable continues unchanged. /// OnErrorErrors from child observables are silently swallowed (the child is unsubscribed). Errors from the source changeset stream terminate the merged output. - /// OnCompletedThe output completes only when the source completes and all active child observables have also completed. /// /// Worth noting: The output is a plain , not a changeset stream. If you need merged changesets, use instead. /// @@ -2970,7 +2923,6 @@ public static IObservable MergeMany(t /// UpdateIf the updating source currently owns the downstream value for this key, an Update is emitted. If a comparer is provided and the update causes a different source's value to become the best candidate, an Update is emitted with that other source's value. /// RemoveIf the removed value was the one published downstream, the operator scans all remaining sources for the same key. If another source still holds that key, an Update is emitted with the replacement value (selected by comparer if provided, otherwise the next available). If no other source holds the key, a Remove is emitted. /// RefreshIf the refreshed item matches the currently published value, the Refresh is forwarded. With a comparer, all sources are re-evaluated first; if a different value now wins, an Update is emitted instead of the Refresh. - /// OnErrorAn error from any source (outer or inner) terminates the entire merged output. /// OnCompletedFor dynamic overloads, the output completes when the outer observable completes and all subscribed inner observables have also completed. For static overloads, completion depends on the completable parameter (default ). /// /// @@ -3468,7 +3420,6 @@ public static IObservable> MergeManyCh /// /// EventBehavior /// OnErrorAn error from the source (parent) stream or from any child changeset stream terminates the entire output. Unlike , child errors are NOT swallowed. - /// OnCompletedThe output completes when the source (parent) stream completes and all active child changeset streams have also completed. /// /// /// Worth noting: When multiple parents contribute children with the same destination key, only one value is published @@ -3834,8 +3785,6 @@ public static IObservable> NotEmpty(thi /// UpdateRe-evaluated. If the new item is , emit accordingly. If the old item was downstream but the new one is not, emit Remove. /// RemoveIf the item was downstream, emit Remove. /// RefreshIf the item is downstream, forwarded as Refresh. - /// OnErrorForwarded to subscribers. - /// OnCompletedForwarded to subscribers. /// /// /// is . @@ -4071,8 +4020,6 @@ public static IObservable> OnItemUpdatedUpdateIf the item is currently downstream, an Update is emitted. /// RemoveReference count decremented. If the count reaches zero (no source holds the key), a Remove is emitted. Otherwise no emission. /// RefreshIf the item is downstream, a Refresh is forwarded. - /// OnErrorAn error from any source terminates the combined output. - /// OnCompletedThe output completes when all sources have completed. /// /// /// or is . @@ -4274,15 +4221,6 @@ public static IDisposable PopulateInto(this IObservableA function that projects the current snapshot to a result value. /// An observable that emits a projected value after each changeset. /// - /// - /// EventBehavior - /// AddCache updated, then invoked and result emitted. - /// UpdateCache updated, then invoked and result emitted. - /// RemoveCache updated, then invoked and result emitted. - /// RefreshCache updated, then invoked and result emitted. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. - /// /// Worth noting: The selector is called on every changeset, which can be chatty. The exposes the full cache state for LINQ-style queries. /// /// or is . @@ -4363,11 +4301,6 @@ public static IObservable> RefCount(thi /// The item to refresh. /// /// Convenience method that wraps a Refresh inside . A Refresh does not change data in the cache; it signals downstream operators (such as or ) to re-evaluate the item. - /// - /// EventBehavior - /// RefreshProduced for the specified item. Downstream operators re-evaluate this item against their current logic (filter predicate, sort comparer, group key selector, etc.). - /// OtherNo Add, Update, or Remove events are produced by this method. - /// /// /// is . /// @@ -4423,11 +4356,6 @@ public static void Refresh(this ISourceCache sourc /// The item to remove. /// /// Convenience method that wraps a single-item removal inside . The key is extracted from the item using the cache's key selector. - /// - /// EventBehavior - /// RemoveProduced if the key exists in the cache. The removed value is included in the changeset. - /// OtherNo Add, Update, or Refresh events are produced by this method. - /// /// /// is . /// @@ -5076,15 +5004,6 @@ public static IObservable> Switch(this /// An of changeset streams. The operator subscribes to the latest inner stream. /// A changeset stream reflecting the items from the most recently emitted inner source. /// - /// - /// EventBehavior - /// AddForwarded from the active inner source. - /// UpdateForwarded from the active inner source. - /// RemoveForwarded from the active inner source. - /// RefreshForwarded from the active inner source. - /// OnErrorAn error from any inner source or the outer source terminates the stream. - /// OnCompletedCompletes when the outer source and the current inner source have both completed. - /// /// On switch: Remove is emitted for all items from the previous source, then Add for all items from the new source. /// Worth noting: Each switch clears the entire downstream cache before populating from the new source. Subscribers see a full remove-then-add reset on every switch. /// @@ -5198,8 +5117,6 @@ public static IObservable> ToObservableChangeSetUpdateEmits Optional.Some(newValue) if the new value differs from the previous per . Otherwise suppressed. /// RemoveEmits . /// RefreshEmits Optional.Some(value) if the value differs from the last emission per . Otherwise suppressed. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// Worth noting: No emission occurs if the key is not present at subscription time. To get an initial None when the key is absent, use the overload with initialOptionalWhenMissing: true. /// @@ -6283,8 +6200,6 @@ static IEnumerable> ReplaceMoves(IChangeSet /// UpdateThe item is replaced in the collection snapshot. Condition recalculated. /// RemovePer-item subscription disposed. Condition recalculated over remaining items. /// RefreshNo effect on per-item subscriptions. Condition not recalculated unless the per-item observable emits. - /// OnErrorAn error from any per-item observable terminates the entire stream. Source errors also terminate. - /// OnCompletedCompletes when the source and all per-item observables have completed. /// /// Worth noting: Items whose per-item observable has not yet emitted are treated as not satisfying the condition. An empty cache is vacuously . The result uses DistinctUntilChanged, so duplicate bool values are suppressed. /// @@ -6336,8 +6251,6 @@ public static IObservable TrueForAll(this IObservab /// UpdateThe item is replaced in the collection snapshot. Condition recalculated. /// RemovePer-item subscription disposed. Condition recalculated over remaining items. /// RefreshNo effect on per-item subscriptions. Condition not recalculated unless the per-item observable emits. - /// OnErrorAn error from any per-item observable terminates the entire stream. Source errors also terminate. - /// OnCompletedCompletes when the source and all per-item observables have completed. /// /// Worth noting: Items whose per-item observable has not yet emitted are treated as not satisfying the condition. An empty cache yields . The result uses DistinctUntilChanged, so duplicate bool values are suppressed. /// @@ -6425,8 +6338,6 @@ public static IObservable> Watch(this IObse /// UpdateEmits the new value. /// RemoveEmits the removed item's value (not None; use if you need removal detection). /// RefreshEmits the current value. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// Worth noting: No emission occurs if the key is not present at subscription time. Changes to other keys are ignored entirely. /// @@ -6477,7 +6388,6 @@ public static IObservable WatchValue(this IObservableRemoveDisposes the item's PropertyChanged subscription. /// RefreshNo effect on subscriptions. /// OnErrorErrors from individual property subscriptions are silently ignored. Source errors terminate the stream. - /// OnCompletedCompletes when the source changeset stream completes. /// /// /// @@ -6517,7 +6427,6 @@ public static IObservable WatchValue(this IObservableRemoveDisposes the item's property subscription. No further emissions for this item. /// RefreshNo effect on subscriptions. The existing property subscription continues. /// OnErrorPer-item property subscription errors are silently ignored. Source errors terminate the stream. - /// OnCompletedCompletes when the source changeset stream completes. /// /// /// @@ -6555,7 +6464,6 @@ public static IObservable> WhenPropertyChangedRemoveDisposes the property subscription. /// RefreshNo effect on subscriptions. /// OnErrorPer-item errors silently ignored. Source errors terminate the stream. - /// OnCompletedCompletes when the source completes. /// /// /// @@ -6652,8 +6560,6 @@ public static IObservable> WhereReasonsAreNotUpdateIf the item is currently downstream (count is 1), an Update is emitted. /// RemoveReference count decremented. If the count drops to exactly 1, an Add is emitted (the item is now exclusive to one source). If it drops to 0, a Remove is emitted. /// RefreshIf the item is downstream, a Refresh is forwarded. - /// OnErrorAn error from any source terminates the combined output. - /// OnCompletedThe output completes when all sources have completed. /// /// /// or is . diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index a76d55e2c..2b7d4a25c 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -37,12 +37,6 @@ public static class ObservableListEx /// This is the primary extension point for custom UI binding adaptors (e.g., /// delegates to this operator). If the adaptor throws, the exception propagates downstream as OnError. /// - /// - /// EventBehavior - /// Add/AddRange/Replace/Remove/RemoveRange/Moved/Refresh/ClearThe adaptor's Adapt method is called with the full changeset, then it is forwarded downstream unchanged. - /// OnErrorForwarded to the downstream observer. If the adaptor throws, the exception propagates as OnError. - /// OnCompletedForwarded to the downstream observer. - /// /// /// public static IObservable> Adapt(this IObservable> source, IChangeSetAdaptor adaptor) @@ -111,8 +105,6 @@ public static IObservable> AddKey(this /// Remove/RemoveRange/ClearThe item's reference count is decremented. If it was in the result and is no longer in all sources, a Remove is emitted. /// RefreshForwarded as Refresh if the item is currently in the result. /// MovedIgnored (set operations are position-independent). - /// OnErrorForwarded from any source. - /// OnCompletedForwarded when all sources complete. /// /// Worth noting: Item identity uses object equality, not position. Duplicate items in a single source are reference-counted independently. /// @@ -227,8 +219,6 @@ public static IObservableList AsObservableList(this IObservableRemove/RemoveRange/ClearUnsubscribes from removed items. The original change is forwarded. /// Moved/RefreshForwarded unchanged. /// Property changesA Refresh change is emitted for the item whose property changed. - /// OnErrorForwarded from the source or from the property change observable. - /// OnCompletedForwarded when the source completes. /// /// Worth noting: Each item generates a subscription. For large lists with frequent property changes, use and to reduce churn. /// @@ -305,8 +295,6 @@ public static IObservable> AutoRefresh(t /// Remove/RemoveRange/ClearUnsubscribes from removed items. The original change is forwarded. /// Moved/RefreshForwarded unchanged. /// Re-evaluator firesThe item's current index is looked up and a Refresh change is emitted. - /// OnErrorForwarded from source or from any re-evaluator observable. - /// OnCompletedForwarded when the source completes. /// /// /// @@ -345,8 +333,6 @@ public static IObservable> AutoRefreshOnObservableRemoveRange/ClearItems removed from the collection. /// MovedItem is moved between positions in the collection. /// RefreshDepends on the adaptor implementation. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -645,13 +631,6 @@ public static IObservable> Convert - /// - /// EventBehavior - /// First changesetDelivered downstream, unlocking the stream for all future emissions. - /// Subsequent changesetsForwarded immediately. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. - /// /// /// /// @@ -732,8 +711,6 @@ public static IObservable> DisposeMany(this IObservableRemove/RemoveRangeReference count decremented. If the count reaches zero, a Remove is emitted for that distinct value. /// RefreshValue is re-extracted. If changed, old value decremented and new value incremented (same as Replace logic). /// ClearAll reference counts cleared. Remove emitted for every tracked distinct value. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -772,8 +749,6 @@ public static IObservable> DistinctValues(th /// ReplaceTreated as a Remove of the old item plus an Add of the new item, with set logic re-evaluated. /// MovedIgnored by the set logic (no positional semantics). /// RefreshForwarded if the item is currently in the result set. - /// OnErrorForwarded from any source. - /// OnCompletedForwarded when all sources have completed. /// /// Worth noting: Unlike , the first source is asymmetric: only its items can appear in the result. /// @@ -882,8 +857,6 @@ public static IObservable> ExpireAfter( /// RemoveRangeIncluded items in the range are emitted as individual Remove changes. /// RefreshThe predicate is re-evaluated. If the item now passes but previously did not, an Add is emitted. If it previously passed but no longer does, a Remove is emitted. If still passes, the Refresh is forwarded. If still fails, dropped. /// ClearAll downstream items are cleared. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// Worth noting: Refresh events trigger re-evaluation, which can promote or demote items (turning a Refresh into an Add or Remove). Pair with for property-change-driven filtering. /// @@ -922,8 +895,7 @@ public static IObservable> Filter( /// RefreshRe-evaluated. If inclusion status changed, an Add or Remove is emitted. If unchanged, Refresh forwarded or dropped. /// ClearAll downstream items are cleared. /// Predicate changedAll items are re-evaluated against the new predicate. The output is shaped by . - /// OnErrorForwarded from the source or from . - /// OnCompletedForwarded when the source completes. Independent completion of does not terminate the filter. + /// OnCompletedIndependent completion of does not terminate the filter. /// /// Worth noting: No items are included until emits its first function. /// @@ -966,8 +938,6 @@ public static IObservable> Filter(this IObservableRefreshRe-evaluated against current state. Inclusion status may change. /// ClearAll downstream items are cleared. /// State changedAll items are re-evaluated with the new state value. The output is shaped by . - /// OnErrorForwarded from the source or from . - /// OnCompletedForwarded when the source completes. /// /// /// @@ -1008,8 +978,6 @@ public static IObservable> Filter( /// ReplaceOld subscription disposed, new subscription created for the replacement item. /// Remove/RemoveRange/ClearSubscription disposed. If the item was downstream, a Remove is emitted. /// RefreshForwarded if the item is currently included. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// Event (per-item observable)Behavior @@ -1089,8 +1057,7 @@ public static IObservable> FlattenBufferResult(this IObservable /// EventBehavior /// Add/Replace/Remove/Moved/RefreshCallback invoked with the (single-item change). Changeset forwarded. /// AddRange/RemoveRange/ClearCallback invoked once with the containing the range (accessible via Range property). Changeset forwarded. - /// OnErrorForwarded. If callback throws, propagates as OnError. - /// OnCompletedForwarded. + /// OnErrorIf the callback throws, the exception propagates as OnError. /// /// /// @@ -1156,8 +1123,6 @@ public static IObservable> ForEachItemChange(this I /// RefreshGroup key re-evaluated. If changed, the item moves between groups. /// MovedNot handled by group logic. /// Regrouper firesAll items re-evaluated. Items that changed group key are moved between groups. Empty groups removed, new groups added. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -1329,7 +1294,6 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// Remove/RemoveRange/ClearSubscription disposed. /// Refresh/MovedNo effect on subscriptions. /// OnCompleted (source)Completes only after the source and all active inner observables have completed. - /// OnErrorForwarded from the source or from any per-item observable. /// /// /// @@ -1368,8 +1332,6 @@ public static IObservable MergeMany(this IObserva /// Remove/RemoveRange/ClearForwarded to the merged output. /// RefreshForwarded to the merged output. /// MovedIgnored. - /// OnErrorForwarded from any inner source. - /// OnCompletedForwarded when all inner sources have completed. /// /// Worth noting: There is no key-based deduplication. If the same item appears in multiple inner streams, it will appear multiple times in the merged output. /// @@ -1565,8 +1527,6 @@ public static IObservable> MergeChangeSetsAdd/AddRangeSubscribes to the child stream. Child emissions are merged into the output. /// ReplaceOld child subscription disposed (and its items removed from output). New child subscription created. /// Remove/RemoveRange/ClearChild subscription disposed. All child items from that parent are removed. - /// OnErrorForwarded from the source or any child stream. - /// OnCompletedForwarded when the source completes. /// /// /// @@ -1644,8 +1604,6 @@ public static IObservable> MergeManyCh /// ReplaceOld child subscription disposed (and its keys removed from output). New child subscription created. /// Remove/RemoveRange/ClearChild subscription disposed. All keys originating from that child are removed from the output. /// Moved/RefreshIgnored; this operator emits a cache changeset and source ordering/refresh does not affect key membership. - /// OnErrorForwarded from the source or any child stream. - /// OnCompletedForwarded when the source completes. /// /// /// @@ -1696,8 +1654,7 @@ public static IObservable> NotEmpty(this IObservableReplaceCallback invoked for the new (replacement) item. Changeset forwarded. /// Remove/RemoveRange/ClearNo callback. Changeset forwarded. /// Moved/RefreshNo callback. Changeset forwarded. - /// OnErrorForwarded. If callback throws, propagates as OnError. - /// OnCompletedForwarded. + /// OnErrorIf the callback throws, the exception propagates as OnError. /// /// /// @@ -1802,8 +1759,6 @@ public static IObservable> Or(this ICollectionReplaceOld item reference count decremented, new item reference count incremented. Add/Remove emitted as needed. /// RefreshForwarded if the item is in the result set. /// MovedIgnored. - /// OnErrorForwarded from any source. - /// OnCompletedForwarded when all sources have completed. /// /// /// @@ -1925,12 +1880,6 @@ public static IObservable QueryWhenChanged( /// is . /// /// This is a non-changeset operator. It emits the entire collection state on each change, not incremental diffs. - /// - /// EventBehavior - /// Add/AddRange/Replace/Remove/RemoveRange/Moved/Refresh/ClearThe internal list is updated, then the full snapshot is emitted. - /// OnErrorForwarded. - /// OnCompletedForwarded. - /// /// Worth noting: A new snapshot is emitted on every changeset, which can be chatty. The collection is rebuilt by cloning each changeset into an internal list. For sorted output, use . /// /// @@ -2046,8 +1995,6 @@ public static IObservable> SkipInitial(this IObservableRefreshSort position re-evaluated. If position changed, a Moved is emitted. /// Comparer changedFull re-sort of all items. /// Resort signalFull re-sort using the current comparer. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// Worth noting: is faster but requires that the values being sorted on never mutate. If they do, use the signal or . /// @@ -2438,8 +2385,7 @@ public static IObservable> ToSortedCollectionMovedA Moved is emitted with updated indices (no factory call). Throws if the source change has no index information. /// RefreshIf is (default), the Refresh is forwarded without re-transforming. If , the factory is re-invoked and the result replaces the current value. /// ClearA Clear is emitted and the internal list is emptied. - /// OnErrorForwarded. If the factory throws, the exception propagates as OnError. - /// OnCompletedForwarded to the downstream observer. + /// OnErrorIf the factory throws, the exception propagates as OnError. /// /// Worth noting: By default, Refresh does NOT re-transform the item (it just forwards the signal). Set to if you need the factory re-invoked on Refresh. Add operations with out-of-bounds indices silently append to the end. /// @@ -2532,7 +2478,7 @@ public static IObservable> TransformMovedEmitted with updated indices (no factory call). /// RefreshIf is (default), forwarded without re-transforming. If , the factory is re-awaited. /// ClearEmitted and internal list cleared. - /// OnErrorForwarded. If the async factory throws, the exception propagates as OnError. + /// OnErrorIf the async factory throws, the exception propagates as OnError. /// OnCompletedForwarded after the last changeset is processed. /// /// Worth noting: All async transforms within a single changeset are serialized (not parallel). Each changeset is fully processed before the next begins. By default, Refresh does NOT re-transform. @@ -2625,8 +2571,6 @@ public static IObservable> TransformAsyncReplaceOld children diffed against new children (using ). Removed, added, or kept as appropriate. /// Remove/RemoveRange/ClearAll children of the removed parents are removed from the output. /// RefreshChildren re-expanded and diffed. - /// OnErrorForwarded to the downstream observer. - /// OnCompletedForwarded to the downstream observer. /// /// /// @@ -2783,13 +2727,6 @@ public static IObservable> WhenPropertyChanged is empty. /// /// Filters individual changes within each changeset. If filtering removes all changes from a changeset, the empty changeset is suppressed via . - /// - /// EventBehavior - /// Any matching reasonThe change is included in the output. Index information is stripped. - /// Any non-matching reasonThe change is dropped from the output. - /// OnErrorForwarded. - /// OnCompletedForwarded. - /// /// Worth noting: Filtering out Remove changes can cause downstream operators to accumulate items indefinitely (memory leak). Index information is stripped because removing some changes invalidates the original index positions. /// /// @@ -2885,8 +2822,6 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// ReplaceOld item reference count decremented, new item incremented, with Xor logic applied. /// RefreshForwarded if item is in the result set. /// MovedIgnored. - /// OnErrorForwarded from any source. - /// OnCompletedForwarded when all sources have completed. /// /// /// From cf9d7ffb3b9a468de4f91dbb6003421da0f051a2 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 10:01:47 -0700 Subject: [PATCH 20/22] Restore OnCompleted row for MergeManyChangeSets The output waits for parent AND all active child streams to complete before completing. This is non-obvious enough to be worth documenting. --- src/DynamicData/Cache/ObservableCacheEx.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DynamicData/Cache/ObservableCacheEx.cs b/src/DynamicData/Cache/ObservableCacheEx.cs index 743d31eb2..2f91f6a87 100644 --- a/src/DynamicData/Cache/ObservableCacheEx.cs +++ b/src/DynamicData/Cache/ObservableCacheEx.cs @@ -3420,6 +3420,7 @@ public static IObservable> MergeManyCh /// /// EventBehavior /// OnErrorAn error from the source (parent) stream or from any child changeset stream terminates the entire output. Unlike , child errors are NOT swallowed. + /// OnCompletedThe output completes when the source (parent) stream completes and all active child changeset streams have also completed. /// /// /// Worth noting: When multiple parents contribute children with the same destination key, only one value is published From c3fedfc445903fa5798790b5118be5300237b4d8 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 10:04:26 -0700 Subject: [PATCH 21/22] Add Error/Completion table to list-to-cache MergeManyChangeSets Mirrors the Cache equivalent. The wait-for-all-children completion semantic is non-obvious and worth documenting on both sides. --- src/DynamicData/List/ObservableListEx.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 2b7d4a25c..17fd0dc36 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1605,6 +1605,14 @@ public static IObservable> MergeManyCh /// Remove/RemoveRange/ClearChild subscription disposed. All keys originating from that child are removed from the output. /// Moved/RefreshIgnored; this operator emits a cache changeset and source ordering/refresh does not affect key membership. /// + /// + /// Error and completion: + /// + /// + /// EventBehavior + /// OnErrorAn error from the source (parent) stream or from any child changeset stream terminates the entire output. Unlike , child errors are NOT swallowed. + /// OnCompletedThe output completes when the source (parent) stream completes and all active child changeset streams have also completed. + /// /// /// /// From a84aac0d971447c04705462a48f2f8e8c78a4446 Mon Sep 17 00:00:00 2001 From: "Darrin W. Cullop" Date: Mon, 25 May 2026 13:38:20 -0700 Subject: [PATCH 22/22] Address PR #1081 follow-up review (18 comments) MergeMany: drop SubscribeMany impl-detail remark. MergeChangeSets (IObservable-source): inherit canonical docs from the IEnumerable-source overload; replace 'cache MergeChangeSets' prose with a proper cref link. MergeChangeSets (IEnumerable-source): now holds the canonical docs (table, exception, remarks); other overloads inherit. MergeChangeSets (IObservableList, IComparer): add per-change behavior table for conflict resolution. Or, Xor: explicit reference to default equality comparer parity with And. Page: rewrite misleading 'Distinct() if not sorted' remark; Distinct() always applies. SkipInitial: add prominent warning about non-empty initial changeset causing downstream desync. Sort(IComparer): wording 'Re-sort signal' for clarity. Sort(comparerChanged): document that items sort by Comparer.Default until the first comparer emission. Switch (IObservableList overload): reference RX Observable.Switch as the changeset-incompatible counterpart. Transform overloads (index, prev, prev+index): strip redundant param tags; rely on inheritdoc + delta summary. --- src/DynamicData/List/ObservableListEx.cs | 86 +++++++++++------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/src/DynamicData/List/ObservableListEx.cs b/src/DynamicData/List/ObservableListEx.cs index 17fd0dc36..37f3a3966 100644 --- a/src/DynamicData/List/ObservableListEx.cs +++ b/src/DynamicData/List/ObservableListEx.cs @@ -1283,10 +1283,6 @@ public static IObservable> LimitSizeTo(this ISourceList sou /// An observable that emits values from all per-item observables, merged together. /// or is . /// - /// - /// Internally uses to manage per-item subscriptions. - /// When an item is added, a new subscription is created via . When removed or replaced, the old subscription is disposed. - /// /// /// Event (source)Subscription behavior /// Add/AddRangeSubscribes to the per-item observable. Emissions are merged into the output. @@ -1310,35 +1306,13 @@ public static IObservable MergeMany(this IObserva return new MergeMany(source, observableSelector).Run(); } + /// /// /// Merges multiple list changeset streams from an observable-of-observables into a single unified changeset stream. - /// Unlike cache MergeChangeSets, list merging performs no key-based deduplication. + /// Unlike , list merging performs no key-based deduplication. /// - /// The type of items in the list. /// The source of nested changeset observables. /// An optional used by the merge tracker to compare items. - /// A single list changeset stream containing all changes from all inner streams. - /// is . - /// - /// - /// All changes from inner streams are forwarded to the output. - /// Replace changes are decomposed into a Remove of the old item followed by an Add of the new item. - /// Moved changes from inner streams are ignored. - /// - /// - /// EventBehavior - /// Add/AddRangeForwarded to the merged output. - /// ReplaceThe old value is replaced by the new value in the merged output. If the old value is not found (by reference), the new value is added instead. - /// Remove/RemoveRange/ClearForwarded to the merged output. - /// RefreshForwarded to the merged output. - /// MovedIgnored. - /// - /// Worth noting: There is no key-based deduplication. If the same item appears in multiple inner streams, it will appear multiple times in the merged output. - /// - /// - /// - /// - /// public static IObservable> MergeChangeSets(this IObservable>> source, IEqualityComparer? equalityComparer = null) where TObject : notnull { @@ -1385,23 +1359,32 @@ public static IObservable> MergeChangeSets(this IOb /// /// Merges a collection of list changeset streams into a single unified changeset stream. - /// This is the primary overload that all other list MergeChangeSets overloads delegate to. + /// This is the canonical list MergeChangeSets overload: other overloads accepting , , or pair/params variants ultimately produce equivalent behavior. /// /// The type of items in the list. /// The collection of list changeset streams to merge. - /// An optional used by the merge tracker to compare items. + /// An optional used by the merge tracker to compare items. Defaults to when . /// An optional for scheduling enumeration. /// When (default), the result completes when all sources complete. /// A single list changeset stream containing all changes from all sources. /// is . /// /// - /// Replace changes from inner streams are handled as a replace-or-add: if the old item is found in the merged output, it is replaced; otherwise the new item is added. Moved changes from inner streams are ignored. - /// There is no key-based deduplication (unlike cache MergeChangeSets). + /// All changes from inner streams are forwarded to the output. There is no key-based deduplication (unlike ): if the same item appears in multiple inner streams, it will appear multiple times in the merged output. /// + /// + /// EventBehavior + /// Add/AddRangeForwarded to the merged output. + /// ReplaceThe old value is replaced by the new value in the merged output. If the old value is not found (by ), the new value is added instead. + /// Remove/RemoveRange/ClearForwarded to the merged output. + /// RefreshForwarded to the merged output. + /// MovedIgnored. + /// /// /// /// + /// + /// public static IObservable> MergeChangeSets(this IEnumerable>> source, IEqualityComparer? equalityComparer = null, IScheduler? scheduler = null, bool completable = true) where TObject : notnull { @@ -1447,6 +1430,15 @@ public static IObservable> MergeChangeSets(this IOb /// is . /// /// Sources can be added or removed dynamically from the observable list. Parent item removal triggers cleanup of all child items from that source. + /// + /// EventBehavior + /// Add (child)If the destination key is new, an Add is emitted. If another source already contributed a child with the same key, resolves the conflict (lowest-ordered value wins). The losing value is tracked internally but not emitted. + /// Update (child)If this source currently owns the destination key downstream, an Update is emitted. Otherwise re-evaluates all sources; a different source's value may win, producing an Update to that value instead. + /// Remove (child)If this source's value was the one published downstream for that destination key, the operator scans other sources for the same key. If found, an Update is emitted with the replacement (per ). Otherwise a Remove is emitted. + /// Refresh (child)If the child item is the one currently published downstream, the Refresh is forwarded. Otherwise re-evaluates all sources; if a different value now wins, an Update is emitted instead. + /// Source list AddSubscribes to the new child changeset stream and merges its keys into the output. + /// Source list RemoveDisposes that source's subscription. All keys it contributed are removed. For keys also contributed by other sources, the next-best value (per ) is promoted as an Update, not an Add. + /// /// /// /// @@ -1757,7 +1749,7 @@ public static IObservable> Or(this ICollection is . /// /// - /// Uses reference-counted equality comparison. An item is included when it first appears in any source and removed when it no longer exists in any source. + /// Item identity is determined by the default equality comparer for . Uses reference-counted equality: an item is included when it first appears in any source and removed when it no longer exists in any source. /// Moved changes are ignored by the set logic. /// /// @@ -1816,7 +1808,7 @@ public static IObservable> Or(this IObservableListAdd; items leaving produce Remove. A new page request triggers /// a full recalculation of the page contents. /// - /// Worth noting: The source should ideally be sorted before paging, as list order determines page contents. Duplicate items are removed from the result via Distinct(). + /// Worth noting: Duplicate items are removed from the result via Distinct() using the default equality comparer for , regardless of source order. The source should ideally be sorted before paging, since list order determines which items fall within each page window. /// /// /// @@ -1968,6 +1960,15 @@ public static IObservable> Reverse(this IObservableThe source to skip the initial changeset. /// A list changeset stream that omits the initial snapshot. /// is . + /// + /// + /// Warning: This operator assumes the initial changeset is empty. If the source emits a non-empty + /// initial snapshot, those items are silently dropped while downstream consumers remain unaware of them. + /// Any later Refresh, Replace, Remove, or Moved change targeting one of those + /// dropped items will throw because the downstream collection has no record of them. Only use this against + /// a source you know starts empty (for example, a that has not yet been populated). + /// + /// /// /// public static IObservable> SkipInitial(this IObservable> source) @@ -2002,7 +2003,7 @@ public static IObservable> SkipInitial(this IObservableRemove/RemoveRange/ClearRemoved from sorted list. /// RefreshSort position re-evaluated. If position changed, a Moved is emitted. /// Comparer changedFull re-sort of all items. - /// Resort signalFull re-sort using the current comparer. + /// Re-sort signalFull re-sort using the current comparer. /// /// Worth noting: is faster but requires that the values being sorted on never mutate. If they do, use the signal or . /// @@ -2023,6 +2024,9 @@ public static IObservable> Sort(this IObservable> /// /// Sorts the list using an observable comparer. The initial comparer is taken from the first emission; subsequent emissions trigger a full re-sort. /// + /// + /// Until emits its first comparer, items are sorted using . Downstream still receives changesets immediately; the initial ordering is whatever produces, then a full re-sort happens once the first comparer arrives. + /// /// The source to sort. /// An of that emits comparers. The first emission provides the initial sort order; subsequent emissions trigger re-sorts. /// for controlling sort behavior. @@ -2095,6 +2099,7 @@ public static IObservable> SuppressRefresh(this IObservable /// Subscribes to the latest inner , switching to each new source and clearing the result when switching. + /// This is the changeset-aware equivalent of Rx's , which cannot be applied directly to changeset streams. /// /// The type of the object. /// An observable that emits instances. Each emission triggers a switch to the new list. @@ -2417,9 +2422,6 @@ public static IObservable> Transform /// Projects each item using a transform function that also receives the item's index. /// - /// The source to transform. - /// A function receiving the source item and its index, returning the transformed item. - /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2435,9 +2437,6 @@ public static IObservable> Transform - /// The source to transform. - /// A function receiving the source item and the previous transformed value (as ), returning the new transformed item. - /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2453,9 +2452,6 @@ public static IObservable> Transform - /// The source to transform. - /// A function receiving the source item, previous transformed value, and index. - /// When , Refresh events re-invoke the factory. public static IObservable> Transform(this IObservable> source, Func, int, TDestination> transformFactory, bool transformOnRefresh = false) where TSource : notnull where TDestination : notnull @@ -2819,7 +2815,7 @@ public static IObservable> WhereReasonsAreNot(this IObservable< /// is . /// /// - /// Uses reference-counted equality. An item is included when it exists in exactly one source. + /// Item identity is determined by the default equality comparer for . Uses reference-counted equality: an item is included when it exists in exactly one source. /// If it appears in a second source, it is removed from the result. If it then leaves one source, /// it re-enters the result. Moved changes are ignored. ///