### Change Struct Example Source: https://github.com/reactivemarbles/dynamicdata/wiki/Sort-And-Bind-Operator An example of a Change struct, illustrating how index information is carried for downstream operators like Bind, Virtualise, and Page. Note: This is a simplified representation. ```cs // not the real implementation public readonly record struct Change( ChangeReason reason, TKey key, TObject current, // These are produced by Sort and only used by Bind, Virtualise and Page int CurrentIndex, int PreviousIndex); ``` -------------------------------- ### C#: StartWithItem for ChangeSet Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Extends IObservable> to start emitting a specific item before any other items from the source observable. This allows for seeding an observable sequence with an initial value. ```C# public static System.IObservable> StartWithItem(this System.IObservable> source, TObject item) where TObject : DynamicData.IKey where TKey : notnull { } ``` ```C# public static System.IObservable> StartWithItem(this System.IObservable> source, TObject item, TKey key) where TObject : notnull where TKey : notnull { } ``` -------------------------------- ### C#: StartWithItem for ChangeSet Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Extends IObservable> to start emitting a specific item before any other items from the source observable. This allows for seeding an observable sequence with an initial value. ```C# public static System.IObservable> StartWithItem(this System.IObservable> source, TObject item) where TObject : DynamicData.IKey where TKey : notnull { } ``` ```C# public static System.IObservable> StartWithItem(this System.IObservable> source, TObject item, TKey key) where TObject : notnull where TKey : notnull { } ``` -------------------------------- ### C# FileSystemObservable Example Source: https://github.com/reactivemarbles/dynamicdata/wiki/Custom-Observable-ChangeSets Demonstrates creating a FileSystemObservable to monitor directory changes. It subscribes to item added, removed, and updated events, showing how to handle initial files and subsequent modifications like creation, updates, and renames. ```csharp void Main() { var tempDir = Directory.CreateTempSubdirectory(); File.WriteAllText(Path.Join(tempDir.FullName, "ExistingFile.txt"), "Show Existing Files Show Up"); using var sub = FileSystemObservable.Create(tempDir.FullName, string.Empty, includeSubDirectories: true) .OnItemAdded(fso => Console.WriteLine($"Added: {fso} [{fso.GetType()}]")) .OnItemRemoved(fso => Console.WriteLine($"Removed: {fso} [{fso.GetType()}]")) .OnItemUpdated((fso, _) => Console.WriteLine($"Updated: {fso} [{fso.GetType()}]")) .Subscribe(); try { var subDir = tempDir.CreateSubdirectory(UniqueStr()); var files = Enumerable.Range(0, 10).Select(_ => Path.Join(subDir.FullName, UniqueStr() + ".temp")).ToList(); files.ForEach(path => File.WriteAllText(path, "Hello World")); files.ForEach(path => File.AppendAllText(path, "Hello Again")); files.ForEach(path => File.Move(path, path + ".temp2")); } finally { tempDir.Delete(recursive: true); } Thread.Yield(); static string UniqueStr() => $"{Guid.NewGuid():N}"; } ``` -------------------------------- ### Create and Connect Observable Collections Source: https://github.com/reactivemarbles/dynamicdata/wiki/Sql-style-joins Demonstrates the initial setup for combining data by creating two observable collections, `person` and `address`, using `SourceCache`. It then shows how to connect these caches to obtain observable streams for further processing. ```cs var person = new SourceCache(p => p.Id); var address = new SourceCache(a => a.Id); var personObservable = person.Connect(); var addressObservable = address.Connect(); ``` -------------------------------- ### C# Dynamic Data Collection Filtering, Transforming, and Sorting Example Source: https://github.com/reactivemarbles/dynamicdata/blob/main/README.md This C# example demonstrates how to use Dynamic Data to manage a collection. It filters trades based on status, transforms them into `TradeProxy` objects, sorts them by timestamp, and binds the results to an observable collection on the dispatcher thread. It also ensures disposable proxies are cleaned up using `DisposeMany()`. ```csharp ReadOnlyObservableCollection list; var myTradeCache = new SourceCache(trade => trade.Id); var myOperation = myTradeCache.Connect() .Filter(trade=>trade.Status == TradeStatus.Live) .Transform(trade => new TradeProxy(trade)) .Sort(SortExpressionComparer.Descending(t => t.Timestamp)) .ObserveOnDispatcher() .Bind(out list) .DisposeMany() .Subscribe() ``` -------------------------------- ### Start Observables with Empty Collection Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Extends observable sequences of collections or change sets to ensure they start with an empty collection if the source is null or empty. This prevents null reference exceptions and simplifies initial state handling. ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` -------------------------------- ### Start Observables with Empty Collection Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Extends observable sequences of collections or change sets to ensure they start with an empty collection if the source is null or empty. This prevents null reference exceptions and simplifies initial state handling. ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull { } ``` -------------------------------- ### StartWithEmpty Extension Method Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Ensures that an observable change set starts with an empty emission, even if the source observable does not immediately emit. This can be useful for initializing UI elements or state. Requires elements to be not null. ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where T : notnull { } ``` -------------------------------- ### StartWithEmpty Extension Method Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Ensures that an observable change set starts with an empty emission, even if the source observable does not immediately emit. This can be useful for initializing UI elements or state. Requires elements to be not null. ```csharp public static System.IObservable> StartWithEmpty(this System.IObservable> source) where T : notnull { } ``` -------------------------------- ### Convert ReactiveList to Filtered ObservableList Source: https://github.com/reactivemarbles/dynamicdata/wiki/Introduction-for-ReactiveUI-users Demonstrates converting an existing ReactiveList into an ObservableChangeSet using .ToObservableChangeSet(). It then applies a filter and converts the result to an ObservableList using .AsObservableList(). This is a quick way to start with DynamicData. ```cs var myDerivedList = myList.ToObservableChangeSet() .Filter(t => t.Status == "Something") .AsObservableList(); ``` -------------------------------- ### Setting up a SourceCache Source: https://github.com/reactivemarbles/dynamicdata/wiki/Chaining-collections-using-Populate-extension-methods Initializes a SourceCache and exposes it as an IObservableCache for external consumption. It also prepares a disposable to manage the subscription lifecycle. ```csharp private SourceCache _peopleCache; public IObservableCache PeopleCache { get; } //provide a reference to subscription for unsubscribing/switching sources private IDisposable _subscription; ... PeopleCache = _peopleCache.Connect().AsObservableCache(); ``` -------------------------------- ### Create SourceList and Connect to ObservableChangeSet Source: https://github.com/reactivemarbles/dynamicdata/wiki/Introduction-for-ReactiveUI-users Illustrates creating a new data source using SourceList and connecting to its observable change set. This approach allows operations to be performed on a background thread before binding. ```cs var myList = new SourceList() var myConnection = myList.Connect() //make the source an observable change set .//some other operation ``` -------------------------------- ### Create SourceCache and Connect to ObservableChangeSet Source: https://github.com/reactivemarbles/dynamicdata/wiki/Introduction-for-ReactiveUI-users Demonstrates creating a new data source using SourceCache and connecting to its observable change set. This is useful for managing collections with unique keys and performing operations on a background thread. ```cs var myCache = new SourceCache(t=>t.Id) var myConnection = myCache.Connect() //make the source an observable change set .//some other operation ``` -------------------------------- ### IIndexAware Interface Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt An interface for objects that have an index property. Implementers can get or set their integer index. ```C# public interface IIndexAware { int Index { get; set; } } ``` -------------------------------- ### IIndexAware Interface Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt An interface for objects that have an index property. Implementers can get or set their integer index. ```C# public interface IIndexAware { int Index { get; set; } } ``` -------------------------------- ### Create and Edit Observable List Source: https://github.com/reactivemarbles/dynamicdata/blob/main/README.md Demonstrates creating an `SourceList`, adding/removing elements, batch editing using `.Edit()`, and converting to a read-only `IObservableList`. It also shows how to connect to observe changes as an `IObservable>`. ```cs var myInts = new SourceList(); // Direct edit methods myInts.AddRange(Enumerable.Range(0, 10000)); myInts.Add(99999); myInts.Remove(99999); // Batch editing for efficiency myInts.Edit(innerList => { innerList.Clear(); innerList.AddRange(Enumerable.Range(0, 10000)); }); // Expose as read-only IObservableList readonlyInts = myInts.AsObservableList(); // Observe changes IObservable> myIntsObservable = myInts.Connect(); ``` -------------------------------- ### IVirtualRequest Interface Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Defines the contract for virtual requests, specifying the size and start index for data retrieval operations. It is a simple data contract. ```csharp public interface IVirtualRequest { int Size { get; } int StartIndex { get; } } ``` -------------------------------- ### IVirtualRequest Interface Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Defines the contract for virtual requests, specifying the size and start index for data retrieval operations. It is a simple data contract. ```csharp public interface IVirtualRequest { int Size { get; } int StartIndex { get; } } ``` -------------------------------- ### C# FileSystemObservable for File System Changes Source: https://github.com/reactivemarbles/dynamicdata/wiki/Custom-Observable-ChangeSets This C# class provides utilities to observe file system changes using `FileSystemWatcher`. It offers an extension method `AsObservableChangeSet` for existing `FileSystemWatcher` instances and a static `Create` method that manages the `FileSystemWatcher` internally. Both return an `IObservable>`, where the key is the full file path. It leverages Rx.NET for event handling and `System.IO` for file system interactions. ```csharp using System; using System.IO; using System.Reactive.Linq; using System.Reactive.Disposables; using DynamicData.Kernel; public static class FileSystemObservable { // Extension method to convert a FileSystemWatcher to an Observable ChangeSet public static IObservable> AsObservableChangeSet(this FileSystemWatcher fsw) { return ObservableChangeSet.Create(cache => { // Create an observable from the Changed event that updates the cache var observeChanged = Observable.FromEventPattern( o => fsw.Changed += o, o => fsw.Changed -= o) .Select(args => args.EventArgs) .Do(args => cache.AddOrUpdate(GetInfo(args.FullPath))); // Create an observable from the Created event that adds the file to the cache var observeCreated = Observable.FromEventPattern( o => fsw.Created += o, o => fsw.Created -= o) .Select(args => args.EventArgs) .Do(args => cache.AddOrUpdate(GetInfo(args.FullPath))); // Create an observable from the Deleted event that removes the file from the cache var observeDeleted = Observable.FromEventPattern( o => fsw.Deleted += o, o => fsw.Deleted -= o) .Select(args => args.EventArgs) .Do(args => cache.RemoveKey(args.FullPath)); // Create an observable from the Renamed event that removes the old name and adds the new name // Use Edit so both changes are emitted together as a single ChangeSet var observeRenamed = Observable.FromEventPattern( o => fsw.Renamed += o, o => fsw.Renamed -= o) .Select(args => args.EventArgs) .Do(args => cache.Edit(updater => { updater.RemoveKey(args.OldFullPath); updater.AddOrUpdate(GetInfo(args.FullPath)); })); // Subscribe to all the observables together var subscription = Observable.Merge(observeChanged, observeCreated, observeDeleted, observeRenamed).Subscribe(); // Ensure the events are flowing fsw.EnableRaisingEvents = true; // Add the initial files var initialFiles = Directory.EnumerateFileSystemEntries(fsw.Path, fsw.Filter, fsw.IncludeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly) .Select(p => GetInfo(p)); cache.AddOrUpdate(initialFiles); // Return the Disposable that controls the subscription return subscription; }, fsi => fsi.FullName); } // Helper function that manages the FileSystemWatcher instance automatically public static IObservable> Create(string path, string filter, bool includeSubdirectories) { return Observable.Using( () => new FileSystemWatcher(path, filter){ IncludeSubdirectories = includeSubdirectories }, fsw => fsw.AsObservableChangeSet()); } private static FileSystemInfo GetInfo(string fullPath) { return Directory.Exists(fullPath) ? new DirectoryInfo(fullPath) : new FileInfo(fullPath); } } ``` -------------------------------- ### Get Top N Items Source: https://github.com/reactivemarbles/dynamicdata/blob/main/README.md An overload of Virtualise() that returns items matching the first 'n' items. This is useful for fetching a limited number of initial elements from a data stream. ```csharp var topStream = someDynamicDataSource.Top(10) ``` -------------------------------- ### DynamicData RangeChange Class Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Represents a change that affects a range of items in a collection, often used in observable list updates. It can store items and their starting index, and supports enumeration. ```C# public sealed class RangeChange : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { public RangeChange(System.Collections.Generic.IEnumerable items, int index = -1) { } public int Count { get; } public int Index { get; } public static DynamicData.RangeChange Empty { get; } public void Add(T item) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } public void Insert(int index, T item) { } public void SetStartingIndex(int index) { } public override string ToString() { } } ``` -------------------------------- ### Create ObservableList using ObservableChangeSet Static Class Source: https://github.com/reactivemarbles/dynamicdata/blob/main/README.md Demonstrates creating an observable list using the static ObservableChangeSet.Create method. This involves providing a factory function that loads data and subscribes to updates, returning disposables for resource management. ```csharp var myObservableList = ObservableChangeSet.Create(observableList => { //some code to load data and subscribe var loader= myService.LoadMyDataObservable().Subscribe(observableList.Add); var subscriber = myService.GetMySubscriptionsObservable().Subscribe(observableList.Add); //dispose of resources return new CompositeDisposable(loader,subscriber ); }); ``` -------------------------------- ### DynamicData RangeChange Class Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Represents a change that affects a range of items in a collection, often used in observable list updates. It can store items and their starting index, and supports enumeration. ```C# public sealed class RangeChange : System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { public RangeChange(System.Collections.Generic.IEnumerable items, int index = -1) { } public int Count { get; } public int Index { get; } public static DynamicData.RangeChange Empty { get; } public void Add(T item) { } public System.Collections.Generic.IEnumerator GetEnumerator() { } public void Insert(int index, T item) { } public void SetStartingIndex(int index) { } public override string ToString() { } } ``` -------------------------------- ### BindingOptions Struct Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Defines configuration options for data binding, including reset thresholds, whether to use replace for updates, and if resets should fire on the first load. Includes default values and a factory method for specific configurations. ```C# public struct BindingOptions : System.IEquatable { public const bool DefaultResetOnFirstTimeLoad = true; public const int DefaultResetThreshold = 25; public const bool DefaultUseReplaceForUpdates = true; public BindingOptions(int ResetThreshold, bool UseReplaceForUpdates = true, bool ResetOnFirstTimeLoad = true) { } public bool ResetOnFirstTimeLoad { get; set; } public int ResetThreshold { get; set; } public bool UseReplaceForUpdates { get; set; } public static DynamicData.Binding.BindingOptions NeverFireReset(bool useReplaceForUpdates = true) { } ``` -------------------------------- ### VirtualRequest Class Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Defines a request for a specific range of data in a virtualized list, specifying the start index and the number of items (size). It includes equality comparison and string representation for requests. ```csharp public class VirtualRequest : DynamicData.IVirtualRequest, System.IEquatable { public static readonly DynamicData.VirtualRequest Default; public VirtualRequest() { } public VirtualRequest(int startIndex, int size) { } public int Size { get; } public int StartIndex { get; } public static System.Collections.Generic.IEqualityComparer StartIndexSizeComparer { get; } public bool Equals(DynamicData.IVirtualRequest? other) { } public override bool Equals(object? obj) { } public override int GetHashCode() { } public override string ToString() { } } ``` -------------------------------- ### BindingOptions Struct Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Defines configuration options for data binding, including reset thresholds, whether to use replace for updates, and if resets should fire on the first load. Includes default values and a factory method for specific configurations. ```C# public struct BindingOptions : System.IEquatable { public const bool DefaultResetOnFirstTimeLoad = true; public const int DefaultResetThreshold = 25; public const bool DefaultUseReplaceForUpdates = true; public BindingOptions(int ResetThreshold, bool UseReplaceForUpdates = true, bool ResetOnFirstTimeLoad = true) { } public bool ResetOnFirstTimeLoad { get; set; } public int ResetThreshold { get; set; } public bool UseReplaceForUpdates { get; set; } public static DynamicData.Binding.BindingOptions NeverFireReset(bool useReplaceForUpdates = true) { } ``` -------------------------------- ### SortAndVirtualizeOptions Struct Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Defines options for sorting and virtualizing data collections. It includes properties for initial capacity, reset threshold, and the use of binary search for optimization. ```C# public struct SortAndVirtualizeOptions : System.IEquatable { public SortAndVirtualizeOptions() { } public int InitialCapacity { get; init; } public int ResetThreshold { get; init; } public bool UseBinarySearch { get; init; } } ``` -------------------------------- ### VirtualRequest Class Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Defines a request for a specific range of data in a virtualized list, specifying the start index and the number of items (size). It includes equality comparison and string representation for requests. ```csharp public class VirtualRequest : DynamicData.IVirtualRequest, System.IEquatable { public static readonly DynamicData.VirtualRequest Default; public VirtualRequest() { } public VirtualRequest(int startIndex, int size) { } public int Size { get; } public int StartIndex { get; } public static System.Collections.Generic.IEqualityComparer StartIndexSizeComparer { get; } public bool Equals(DynamicData.IVirtualRequest? other) { } public override bool Equals(object? obj) { } public override int GetHashCode() { } public override string ToString() { } } ``` -------------------------------- ### SortAndVirtualizeOptions Struct Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Defines options for sorting and virtualizing data collections. It includes properties for initial capacity, reset threshold, and the use of binary search for optimization. ```C# public struct SortAndVirtualizeOptions : System.IEquatable { public SortAndVirtualizeOptions() { } public int InitialCapacity { get; init; } public int ResetThreshold { get; init; } public bool UseBinarySearch { get; init; } } ``` -------------------------------- ### Sort Observable Change Sets in C# Source: https://github.com/reactivemarbles/dynamicdata/blob/main/README.md Illustrates sorting observable change sets using the `Sort` operator. Examples include sorting with a static comparer and dynamically changing the sorting with an observable comparer. ```cs var myPeople = new SourceList(); var myPeopleObservable = myPeople.Connect(); var mySortedObservable = myPeopleObservable.Sort(SortExpressionComparer.Ascending(p => p.Age)); ``` ```cs IObservable> observableComparer=...; var mySortedObservable = myPeopleObservable.Sort(observableComparer); ``` -------------------------------- ### C#: StartWithEmpty for GroupChangeSet Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Extends IObservable> to start emitting an empty group change set before any other items. This is useful for ensuring an observable sequence always has an initial state. ```C# public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull where TGroupKey : notnull { } ``` ```C# public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull where TGroupKey : notnull { } ``` -------------------------------- ### C# SortAndBindOptions Configuration Source: https://github.com/reactivemarbles/dynamicdata/wiki/Sort-And-Bind-Operator Demonstrates how to configure `SortAndBindOptions` in C# for optimizing data binding operations. The options include `InitialCapacity` for pre-allocating memory, `UseBinarySearch` for faster lookups when applicable, `UseReplaceForUpdates` to optimize updates, and `ResetThreshold` to control when binding resets are triggered. ```cs // optionally apply any combination of the following. var options = new SortAndBindOptions { // Applied to ReadonlyObservableCollection only. // Can help speed up first time load if capacity is known InitialCapacity = 10_000, // Use binary search when the result of the comparer is a pure function. // This can work performance wonders but only is there are no inline mutations UseBinarySearch = true, // When possible, should replace be used instead of remove and add. // Some control suites do not support replace. UseReplaceForUpdates = false, // The number of changes before a reset is fired. // Adjusting this can speed up the binding ResetThreshold = 30 }; var newFastWay = myCache.SortAndBind(var our myList, comparer, options); ``` -------------------------------- ### Create and Edit Observable Cache Source: https://github.com/reactivemarbles/dynamicdata/blob/main/README.md Illustrates creating an `SourceCache`, performing direct edits like `Clear()` and `AddOrUpdate()`, and utilizing batch editing via `.Edit()` for efficiency. It also covers exposing the cache as read-only `IObservableCache` and connecting to observe changes. ```cs var myCache = new SourceCache(t => key); // Direct edit methods myCache.Clear(); myCache.AddOrUpdate(myItems); // Batch editing for efficiency myCache.Edit(innerCache => { innerCache.Clear(); innerCache.AddOrUpdate(myItems); }); // Expose as read-only IObservableCache readonlyCache = myCache.AsObservableCache(); // Observe changes IObservable> myCacheObservable = myCache.Connect(); ``` -------------------------------- ### C#: StartWithEmpty for GroupChangeSet Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Extends IObservable> to start emitting an empty group change set before any other items. This is useful for ensuring an observable sequence always has an initial state. ```C# public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull where TGroupKey : notnull { } ``` ```C# public static System.IObservable> StartWithEmpty(this System.IObservable> source) where TObject : notnull where TKey : notnull where TGroupKey : notnull { } ``` -------------------------------- ### DynamicData SortAndPageOptions Struct Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Configuration options for sorting and pagination operations. It allows setting initial capacity, reset thresholds, and whether to use binary search for performance. ```C# public struct SortAndPageOptions : System.IEquatable { public SortAndPageOptions() { } public int InitialCapacity { get; init; } public int ResetThreshold { get; init; } public bool UseBinarySearch { get; init; } } ``` -------------------------------- ### DynamicData SortAndPageOptions Struct Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Configuration options for sorting and pagination operations. It allows setting initial capacity, reset thresholds, and whether to use binary search for performance. ```C# public struct SortAndPageOptions : System.IEquatable { public SortAndPageOptions() { } public int InitialCapacity { get; init; } public int ResetThreshold { get; init; } public bool UseBinarySearch { get; init; } } ``` -------------------------------- ### Using Preview vs Connect for Change Notifications (C#) Source: https://github.com/reactivemarbles/dynamicdata/wiki/Preview-observable Demonstrates the difference between using the Connect and Preview observables for handling item removal notifications. Preview ensures that observers receive notifications when the collection is still in its previous state, preventing issues where derived data might be based on an already modified collection. ```csharp Issues.Connect().OnItemRemoved(issue => { foreach(var user in issue.AssignedUsers.Items){ user.NotifyIssueDeleted(); } }); ``` ```csharp Issues.Preview().OnItemRemoved(issue => { foreach(var user in issue.AssignedUsers.Items){ user.NotifyIssueDeleted(); } }); ``` -------------------------------- ### IPageResponse Interface Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Defines the structure for returning pagination metadata. It includes information about the current page, the number of items per page, the total number of pages, and the overall total size of the dataset. ```csharp namespace DynamicData.Operators { public interface IPageResponse { int Page { get; } int PageSize { get; } int Pages { get; } int TotalSize { get; } } } ``` -------------------------------- ### Resorting Observable List on Property Changes Source: https://github.com/reactivemarbles/dynamicdata/wiki/Sorting An example of using the 'resort' overload to handle property changes. It listens for property changes (e.g., 'Age'), throttles notifications, and signals the sort operator to re-evaluate the list's order. ```csharp var propertyChanges = list.Connect() .WhenPropertyChanged(p => p.Age) .Throttle(TimeSpan.FromMilliseconds(250)) .Select(_ => Unit.Default); var sorted = list.Connect().Sort(myComparer, resort: propertyChanges); ``` -------------------------------- ### DynamicData ObservableChangeSet Create Methods Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Provides factory methods for creating observable change sets from various subscription patterns. These methods allow users to define how data is loaded and managed, supporting different return types for subscription actions (Action, IDisposable, Task, Task, Task) and handling key selection for cached data. ```csharp namespace DynamicData { public static class ObservableChangeSet { public static System.IObservable> Create(System.Func, System.Action> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.IDisposable> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.CancellationToken, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.CancellationToken, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.CancellationToken, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Action> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.IDisposable> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } } } ``` -------------------------------- ### Buffer Observable ChangeSet with Conditions in C# Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet8_0.verified.txt Allows buffering of incoming changes from an observable change set based on a boolean observable selector or a time span. This is useful for controlling the flow of data updates, for example, pausing updates when a condition is met. ```csharp public static System.IObservable> BufferIf(this System.IObservable> source, System.IObservable pauseIfTrueSelector, System.Reactive.Concurrency.IScheduler? scheduler = null) where T : notnull { } public static System.IObservable> BufferIf(this System.IObservable> source, System.IObservable pauseIfTrueSelector, bool initialPauseState, System.Reactive.Concurrency.IScheduler? scheduler = null) where T : notnull { } public static System.IObservable> BufferIf(this System.IObservable> source, System.IObservable pauseIfTrueSelector, System.TimeSpan? timeOut, System.Reactive.Concurrency.IScheduler? scheduler = null) where T : notnull { } public static System.IObservable> BufferIf(this System.IObservable> source, System.IObservable pauseIfTrueSelector, bool initialPauseState, System.TimeSpan? timeOut, System.Reactive.Concurrency.IScheduler? scheduler = null) where T : notnull { } ``` -------------------------------- ### IPageResponse Interface Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Defines the structure for returning pagination metadata. It includes information about the current page, the number of items per page, the total number of pages, and the overall total size of the dataset. ```csharp namespace DynamicData.Operators { public interface IPageResponse { int Page { get; } int PageSize { get; } int Pages { get; } int TotalSize { get; } } } ``` -------------------------------- ### DynamicData ObservableChangeSet Create Methods Source: https://github.com/reactivemarbles/dynamicdata/blob/main/src/DynamicData.Tests/API/ApiApprovalTests.DynamicDataTests.DotNet9_0.verified.txt Provides factory methods for creating observable change sets from various subscription patterns. These methods allow users to define how data is loaded and managed, supporting different return types for subscription actions (Action, IDisposable, Task, Task, Task) and handling key selection for cached data. ```csharp namespace DynamicData { public static class ObservableChangeSet { public static System.IObservable> Create(System.Func, System.Action> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.IDisposable> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.CancellationToken, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.CancellationToken, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Threading.CancellationToken, System.Threading.Tasks.Task> subscribe) where T : notnull { } public static System.IObservable> Create(System.Func, System.Action> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.IDisposable> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } public static System.IObservable> Create(System.Func, System.Threading.Tasks.Task> subscribe, System.Func keySelector) where TObject : notnull where TKey : notnull { } } } ```