Tuesday, December 7, 2010

How To: Use interface types with data templates in WPF 4

The short story is, you cannot specify interface types as a value for DataType and this is an example I put together to demonstrate one way around this.

I was recently working on a user control in a resource library project that only had interfaces defined, and was crippled by this limitation in WPF.

Use of DataType is further described here.

Custom Template Selector Class:
public class CustomTemplateSelector : DataTemplateSelector
{
  public CustomTemplateSelector()
  {
    TemplateMappings = new Dictionary();
  }

  public Dictionary TemplateMappings { get; set; }

  public override DataTemplate SelectTemplate(object item, DependencyObject container)
  {
    var itemType = item.GetType();

    var matchingKey = TemplateMappings.Keys.FirstOrDefault(k => k.IsAssignableFrom(itemType));

    return matchingKey != null ? TemplateMappings[matchingKey] : null;
  }
}


Example Usage for ComboBox in XAML:

<ComboBox.ItemTemplateSelector>
<lib:CustomTemplateSelector>
<lib:CustomTemplateSelector.TemplateMappings>
<DataTemplate x:Key="{x:Type sys:String}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="DemoItemColumn" />
</Grid.ColumnDefinitions>
<!--bind with no path, item is a string-->
<TextBlock Text="{Binding }" />
</Grid>
</DataTemplate>
<!--IDemoItem data template, note we could specify the actual object type here, but if we were in a
class/resource library that only defined the interfaces, we wouldn't know the type to specify-->
<DataTemplate x:Key="{x:Type lib:IDemoItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="DemoItemColumn" />
</Grid.ColumnDefinitions>
<!--bind to description property of IDemoItem-->
<TextBlock Text="{Binding Description}" />
</Grid>
</DataTemplate>
</lib:CustomTemplateSelector.TemplateMappings>
</lib:CustomTemplateSelector>
</ComboBox.ItemTemplateSelector>

Full working demo can be downloaded here:
                          

No comments:

Post a Comment