When creating ViewModels in WPF it's sometimes necessary to transform data that is available in an ObservableCollection
(the source collection) into a collection of wrapper elements that extend/restrict/project the original elements (the target collection), while the number and order of the elements always mirror the original collection.
Just like the Select extension method, except that it is continuously updated and can therefore be used for WPF bindings.
If an element is added to the source at index x, the Wrapper of the same element is added at the same index x in the target collection. If the element at index y is removed in the source collection, the element at index y is removed in the target collection.
Say there is an ObservableCollection<ClassA>
, but what I need to bind to is an ReadOnlyObservableCollection<ClassB>
(or equivalent), where ClassB
-> ClassA
as follows:
class ClassB : INotifyPropertyChanged, IDisposable
{
public ClassB(ClassA a)
{
Wrapped = a;
(Wrapped as INotifyPropertyChanged).PropertyChanged+=WrappedChanged;
}
public ClassA Wrapped { get; private set; }
public int SomeOtherProperty { get { return SomeFunction(Wrapped); }
WrappedChanged(object s, NotifyPropertyChangedArgs a) { ... }
...
}
I can write my own TemplatedTransformCollectionWrapper
, where I can write this:
ObservableCollection<ClassA> source;
TemplatedTransformCollectionWrapper theCollectionThatWillBeUsedInABinding
= TemplatedTransformCollectionWrapper(source, classA => new ClassB(classA));
TemplatedTransformCollectionWrapper ideally wraps all collections that implement INotifyCollectionChanged
and correctly handles all possible add, remove, replace operations of the original, wrapped, collection.
It's not trivial to write TemplatedTransformCollectionWrapper
correctly and it seems to be the kind of thing that someone else has already done, maybe it's even part of the core framework. But I can't find it.
IEnumerable<System.Dynamic.DynamicObject>
that basically Proxies all Property gets and sets to the underlying model. – Nettlevar newcollection = new ReadOnlyCollection(col.Select(x => new ClassB(x));
– NettleReadOnlyObservableCollection
[msdn.microsoft.com/en-us/library/ms668620.aspx] wraps anObservableCollection
and notifies it's subscribers of any changes that happen in the sourceObservableCollection
. – Demireliefvar readonly col = new ReadOnlyObservableCollection<TItems>(yourCol.Select(x => new TNewItem(){Item = x}));
– NettleyourCol.Add(something)
would not update the target collection. – DemireliefCollectionView
supports filter and sort, but I do not see how it supports element-wise transform. If it does support transform and I missed how, then that would be the answer to my question. Updated the question to make it clearer that the target collection needs to mirror the source even after the source updates. – Demirelief