Is there a way to get notified when CompositeCollection\'s current location changes?
I need to have the CompositeCollection monitored by a CollectionView, any ideas
I ran into the same problem: I needed sorting of a CompositeCollection. I wrote the following class that solves the problem, at least for ObservableCollections of the same type.
The idea is to maintain the composite collection as an ordinary observable collection, and update it as the underlying collections change. Then the resulting collection (AllNodes) can be used in the user interface, and it supports CollectionView just fine.
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
namespace Util {
public class ObservableCollectionCollector {
private class ReplacableObservableCollection : ObservableCollection {
public void Replace(int idx, T v) {
SetItem(idx, v);
}
}
private readonly ReplacableObservableCollection allNodes;
private readonly ObservableCollection[] colls;
private readonly int[] lens;
public ObservableCollectionCollector(params ObservableCollection[] colls) {
this.colls = colls;
allNodes = new ReplacableObservableCollection();
foreach (var l in colls) {
foreach (var e in l)
allNodes.Add(e);
l.CollectionChanged += HandleCollectionChanged;
}
lens = colls.Select(c => c.Count).ToArray();
}
public ReadOnlyObservableCollection AllNodes {
get { return new ReadOnlyObservableCollection(allNodes); }
}
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
int i0 = 0;
int ci = 0;
foreach (var l in colls) {
if (l == sender)
break;
i0 += l.Count;
++ci;
}
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
for (int i = 0; i < e.NewItems.Count; ++i)
allNodes.Insert(i0 + e.NewStartingIndex + i, (T)e.NewItems[i]);
break;
case NotifyCollectionChangedAction.Move:
for (int i = 0; i < e.OldItems.Count; ++i)
allNodes.Move(i0 + e.OldStartingIndex + i, i0 + e.NewStartingIndex + i);
break;
case NotifyCollectionChangedAction.Remove:
for (int i = 0; i < e.OldItems.Count; ++i)
allNodes.RemoveAt(i0 + e.OldStartingIndex);
break;
case NotifyCollectionChangedAction.Replace:
for (int i = 0; i < e.NewItems.Count; ++i)
allNodes.Replace(i0 + e.OldStartingIndex + i, (T)e.NewItems[i]);
break;
case NotifyCollectionChangedAction.Reset:
for (int i = 0; i < lens[ci]; ++i)
allNodes.RemoveAt(i0);
break;
}
lens[ci] = ((ObservableCollection)sender).Count;
}
}
}