I've been working with MVVM for a while, and this problem (if it is a problem) has me stumped all the time.
I have an ItemsControl bound to a collection in my MainViewModel
ViewModel
public class MainViewModel : ViewModelBase
{
public ObservableCollection<string> Names { get; set; }
}
XAML
<ItemsControl ItemsSource="{Binding Names}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<view:NameView />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The DataContext property of each is of type string (bound directly to the Model), but what if I wanted the DataContext's to be bound to a ViewModel which is based on the property. How would I go about instantiating the ViewModel and feeding it the Model (string).
I hope that makes sense.
I think you're asking about data template matching.
If you want binding to select the data template it uses to present an object at runtime, the simplest way is by putting the templates in the resource dictionary and setting their
DataType
property, e.g.:Now if your view model, instead of a
Names
property, has aThings
property:you can populate the collection with
Thing1
andThing2
objects and theItemsControl
will present each with the appropriate template.If you want to choose a different template based on the value of a property, there are a couple of ways of accomplishing this as well. One is to write a DataTemplateSelector, which gives you very fine-grained control over what template gets selected, but requires you to actually code (and test, and document) something.
Another is to use styles to display and hide content based on a trigger. This doesn't actually select different templates per se, but it accomplishes more or less the same thing. Put this in your item template, and it will display one set of content when
Name
is "Thing1" and another whenName
is "Thing2".A very nice thing about this approach is that unlike template selection, this is dynamic: if the value of the
Name
property changes at runtime (and your view model implements property-change notification), so will what appears in the view.Finally, if what you're trying to do is actually create different view models in your collection based on the values of the string in the
Names
collection, you do that in the view model. You could do this:If the values in
Names
change at runtime, you have a substantially more complex problem: you'll need to implementViewModels
as anObservableCollection<object>
property, and you may need to go so far as to handle collection-change events on theNames
collection and update theViewModels
collection whenever an item inNames
is added, removed, or changed.Why not do the following?
This seems a bit odd, but AFAIK there isn't a specific prohibition against one VM knowing about others.
In a case where you use DI for VM resolution, obviously your design would have to be adjusted. For instance, you might create a
NamesView
which is a UserControl with a publicDependencyProperty
of typeIEnumerable<string>
. Then, theNamesView
's ViewModel is bound to this DP...