CommunityToolkit / CommunityToolkit/dotnet
[Feature] Add Helper Extension `IList<T>.SyncWith(IList<T> another, IEqualityComparer<T> comparer = null)`
- Dominant language
- C#
- Stars
- 3.8k
- Forks
- 400
- PR merge metrics
- No merged PRs in 30d
Description
### Describe the problem
This might not be quite requiring, but it will indeed help a lot in some cases where we need to update the entire list `ListViewBase.ItemSource` without blinking the UI.
For example:
```csharp
var data = await SomeDataService.FetchDataAsync() // IList;
var oc = new ObservableCollection(data);
MyListView.ItemSource = oc; // Update the entire list.
```
Each time we update the entire data list (with data binding or not), the UI will blink, this is not terrible but it would be better if we can have an auto diff tool to make it visually updated with only different elements.
### Describe the solution
A helper extension `IList.SyncWith(IList another, IEqualityComparer comparer = null)` could be an initial idea:
```csharp
// Implementation
public static IList SyncWith(
this IList source,
IList another,
IEqualityComparer comparer = null)
{
// Step 1: Remove redundant items, if any.
source.Except(another).ToList().ForEach(x => _ = source.Remove(x));
// Step 2: Update the list, index by index.
for (var index = 0; index < another.Count; index++)
{
var newItem = another[index];
if (index < source.Count)
{
var oldItem = source[index];
if (comparer?.Equals(newItem, oldItem) ?? Equals(newItem, oldItem))
{
continue;
}
// Step 2-1: remove the old item, if it's been changed at the current position.
source.RemoveAt(index);
}
// Step 2-2: insert the new item at the current position.
source.Insert(index, newItem);
}
// Step 3: (last but not least) assertive verification.
Debug.Assert(source.SequenceEqual(another, comparer));
return source;
}
// Use Case
var data = await SomeDataService.FetchDataAsync(); // IList
var oc = new ObservableCollection(data);
MyListView.ItemSource = oc; // Initializes the entire list.
// When we need to update the entire list
data = await SomeDataService.FetchDataAsync(); // IList
_ = oc.SyncWith(data); // The UI won't blink and will apply the corresponding update animations.
```
### Alternatives
_No response_
### Additional info
_No response_
### Help us help you
Yes, I'd like to be assigned to work on this item.
Contributor guide
Assessment
This issue has not been assessed yet.