Reputation: 561
I have an application with a tree of model objects which constitute a kind of schema. This might look like:
ElementSet
....ElementGroup
........ScalarElement
........BoolElement
....ElementGroup
........MatrixElement
........VectorElement
This tree is much more complex, but you get the idea. I will be displaying this tree in a WPF TreeView, allowing the user to not only select a particular node (master-detail style) but also add, remove and rearrange nodes.
My intention is to encapsulate each node in the tree in a ViewModel, where I will add commands, tooltip info and other ViewModel related fluff.
My problem comes in that I have a tree of models, and would really need a tree of ViewModels to go with it. I'm struggling to think of an elegant solution to this. How to I construct this? Keep them in sync? etc
One idea I'm toying with is binding the View directly to the graph of model objects, but using a ValueConverter to convert the Model to a ViewModel on each node. Each Model has a unique ID, so a having the converter maintain a queryable cache of ViewModels to return to the view wouldn't be out of the question.
What other effective strategies exist for creating view models for collections/trees of models?
Upvotes: 2
Views: 958
Reputation: 561
I ended up using a ValueConverter with a ViewModel cache. It actually works quite nicely. I set up my TreeView like this:
<TreeView ItemsSource="{Binding TreeRoot}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<ContentPresenter Content="{Binding Converter={StaticResource ModelToViewModelConverter}}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
...where TreeRoot is the root of a tree of model objects, each with a property "Children". And created my converter like this:
public class ModelToViewModelConverter : IValueConverter
{
private static Dictionary<Guid, ViewModelBase> _map = new Dictionary<Guid, ViewModelBase>();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var element = value as ElementBase;
if (!_map.ContainsKey(element.Id))
{
if (element is ElementSet)_map.Add(element.Id, new ElementSetViewModel(value as ElementSet));
if (element is ElementGroup) _map.Add(element.Id, new ElementGroupViewModel(value as ElementGroup));
if (element is StringElement) _map.Add(element.Id, new StringElementViewModel(value as StringElement));
if (element is ScalarElement) _map.Add(element.Id, new ScalarElementViewModel(value as ScalarElement));
}
return _map[element.Id];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//A change.sdfsdfdsff
throw new NotImplementedException();
}
}
This allows me to maintain just one tree of Model objects, but allows me to use ViewModels for the View to bind to.
Upvotes: 0
Reputation: 14334
Depending on the complexity of the data, I recommend a View model for each element and a constructor that will recursively build a tree from your model.
If you simply want to display strings and formatted doubles from your model, you may not even need a view model but it will make your system flexible in the long run.
Upvotes: 1