Silverlight doesn’t have any DataTemplateSelectors, which is too bad. If you want to choose a different template based on certain properties of the object you’re binding to, you have to use a work-around. Jeremy Likness has a rather extensive solution, but I found Timmy Kokke’s way to be more light-weight.
Basically, just make a new class that inherits from ContentControl, override its OnContentChanged method and set its ContentTemplate property to the template you need:
public class PersonNameDataTemplateSelector : ContentControl { protected override void OnContentChanged(object oldContent, object newContent) { base.OnContentChanged(oldContent, newContent); var personViewModel = (PersonViewModel) newContent; if (string.IsNullOrEmpty(personViewModel.FirstName) && string.IsNullOrEmpty(patientViewModel.LastName)) ContentTemplate = (DataTemplate)Application.Current.Resources["UnknownPersonNameDataTemplate"]; else ContentTemplate = (DataTemplate)Application.Current.Resources["PersonNameDataTemplate"]; } }
All we’re doing here is checking if the object we’re databinding to (in our case a ViewModel, but that’s not important here) has a firstname or a lastname. If none of these is present, we load in the “UnknownPatientNameDataTemplate”. If there is a name, we use “PatientNameDataTemplate”.
These are just two different DataTemplates in our application’s resources.
Now just use this as the template of your control, i.e. for a listbox:
<listbox grid.column ="0" grid.row="1" itemssource="{binding people}"> <listbox.itemtemplate> <DataTemplate> <myapp:personnamedatatemplateselector content="{binding}"/> </DataTemplate> </listbox.itemtemplate> </listbox>
But if our PersonViewModel suddenly changes and it now does have a name, our template isn’t changed. This is normal behavior, as the Content of the control doesn’t change. It’s still the same viewmodel. This can easily be solved by exposing an event on your viewmodel (as is usual in an MVVM pattern). Now, everytime your viewmodel has a property that changes, your control will reevaluate what template to use:
public class PersonNameDataTemplateSelector : ContentControl { private PersonViewModel _personViewModel; protected override void OnContentChanged(object oldContent, object newContent) { base.OnContentChanged(oldContent, newContent); _personViewModel = (PersonViewModel) newContent; _personViewModel.PropertyChanged += (sender, e) => SelectTemplate(); SelectTemplate(); } private void SelectTemplate() { if (string .IsNullOrEmpty(_personViewModel.FirstName) && string.IsNullOrEmpty(_personViewModel.LastName)) ContentTemplate = (DataTemplate)Application.Current.Resources["UnknownPersonNameDataTemplate"]; else ContentTemplate = (DataTemplate)Application.Current.Resources["PersonNameDataTemplate"]; } }