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"];
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.