Reputation: 2146
I have 2 ObservableCollection<T>
objects. Let's call them A and B. I want to replicate the changes broadcasted by A (via INotifyCollectionChanged
) to B.
In other words, when A changes, B must replicate the same change:
The problem comes with the complexity of NotifyCollectionChangedEventArgs
.
I'd like to avoid writing the code that checks for all operation combinations.
(add + remove + reset + move + replace) x (single-item + multi-item) - (invalid combinations)
My assumption (and hope) is that this logic already exists in .Net (I'm on .Net 6).
Here's some code that demonstrates my vision.
ObservableCollection<int> A = new ObservableCollection<int>();
ObservableCollection<int> B = new ObservableCollection<int>();
A.CollectionChanged += (s, args) =>
{
// This line doesn't build. It's just to show my intent.
B.Apply(args);
};
A.Add(1);
A.Add(2);
// At this point B should contain 1 and 2 because they were added to A.
Is there an existing .Net solution for this problem?
If the recipe doesn't exist, any pointers on how to properly implement it are appreciated.
Upvotes: 1
Views: 124
Reputation: 11
I'm not entirely sure what you are trying to achieve - but if A and B are always going to be equivalent, why not just find an abstraction that allows the use of A and remove the B collection? But if B is going to be modified independently of A then the operations - such as move - won't work in B given the difference in collections and indices.
If there is no possibility of removing one instance of the collection then you could always write a class that makes the code of your handler simpler.
var A = new ObservableCollection<int>();
var B = new ObservableCollection<int>();
var evts = new ObservableCollectionEvents<int>(A);
evts.Added += (i, x) => B.Insert(i, x);
evts.Removed += (i, x) => B.RemoveAt(i);
A.Add(1);
A.Add(2);
Console.WriteLine(string.Join(", ", B));
class ObservableCollectionEvents<T>
{
public event Action<int, T>? Added;
public event Action<int, T>? Removed;
public ObservableCollectionEvents(ObservableCollection<T> collection)
{
collection.CollectionChanged += OnCollectionChanged;
}
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
for (var i = e.NewStartingIndex; i < e.NewStartingIndex + e.NewItems!.Count; ++i)
Added?.Invoke(i, (T)e.NewItems[i - e.NewStartingIndex]!);
break;
case NotifyCollectionChangedAction.Remove:
for (var i = e.OldStartingIndex; i < e.OldStartingIndex + e.OldItems!.Count; ++i)
Removed?.Invoke(i, (T)e.OldItems[i - e.OldStartingIndex]!);
break;
// ...
}
}
}
This would also allow you to simplify the amount of operations you need to support. A replace could be modelled with a remove followed by an add at the same index - with a similar process for the move operations.
Upvotes: 1