-
Notifications
You must be signed in to change notification settings - Fork 0
TransformingObservableReadOnlyList
Representing tree-like Model-sided structures at the ViewModel-side.
Let's assume that we have a Directory Model, a directory has subdirectories. So in Directory there would be an ObservableCollection. In the old way you would have a ObservableCollection in the DirectoryViewModel, if you would want it to show it in a TreeView, because HierarchicalDataTemplates require an ItemsSource. This means that you would have to subscribe to the CollectionChanged event and react to it, if you need to keep the ViewModels in sync with the Models. But you would need to write it all yourself.
I have done the old way before and that is the reason why I started the MuVaViMo project. If you have several tree-like classes on Model-side, then the old way feels tedious, repetitive, like duplicating code and is most likely error prone as you might miss something. That is why I wanted to have one generic collection, which does this for me. This is how the idea for the TransformingObservableReadOnlyList was born.
Basically, this class is so generic that it is not limited to transforming Models into ViewModels. You could transform any Type into another Type, because the actual transformation logic has to be given as a Func-object (so you can use a lambda-expression) by the user (see in Example). So if you find another interesting use case, then feel free to try it with this class.
The purpose of this class is to represent an ObservableCollection or an IObservableReadOnlyList of one type as an IObservableReadOnlyList of another. To use it, there is a constraint: The user has to deliver the transformation logic from the source type to the result type himself. In the MVVM scenario usually the ViewModel is a kind of wrapper for the Model, which means that on an examplary constructor signature might look like:
ViewModel(Model model)
Given that, the lambda expression representing the transformation would look simply like:
model => new ViewModel(model)
Note that, this class has a private backing list of transformed objects unlike the ConcatenatingObservableReadOnlyList, which just references the source collections/lists. This is needed for direct read only accesses to the list, as it would not be possible to just delegate the accesses to the untransformed source collection/list.
Also, don't worry if the source collection already has some items before you put it into one TransformingObservableReadOnlyList. On construction it transforms and puts all existing items of the source collection/list into the backing list.
public IObservableReadOnlyList<DirectoryViewModel> SubDirectories { get; private set; }
public DirectoryViewModel(Directory directory)
{
SubDirectories = TransformingObservableReadOnlyList<Directory, DirectoryViewModel>(directory.SubDirectorie, directory => new DirectoryViewModel(directory));
}
Please note that in this particular example you would only need to construct a ViewModel of the root Directory Model yourself somewhere in your code. All other ViewModels will be constructed by the TransformingObservableReadOnlyLists, because the transforming logic in this example is naturally recursive.