Pokud pracujete s technologií WPF, jistě víte, že disponuje sympatickým systémem pro vytváření šablon (Templates). Jejich účelem je usnadnit psaní komponent, kterým půjde změnit způsob zobrazování bez nutnosti měnit kód komponenty samotné. Ve WPF existují víceméně 3 základní typy šablon: ControlTemplate (změna vzhledu celé komponenty), ItemsPanelTemplate (změna vzhledu objektu, který zobrazuje další objekty) a DataTemplate (změna vzhledu zobrazování datových objektů). V tomto krátkém příspěvku se budu věnovat šablonám DataTemplates. Ty určují, jakým způsobem se zobrazí například položky v ItemsControl komponentách. Tedy například ListBox, ComboBox a podobně.
Existují i případy, kdy chceme používat více šablon pro jednu komponentu. V tu chvíli je potřeba naimplementovat DataTemplateSelector, který se postará o výběr vhodné šablony pro každou ze zobrazovaných položek.
Abych si usnadnil práci a nemusel psát pro každý takový seznam nový DataTemplateSelector, naimplementovat jsem jeden univerzální, kterému můžete přidat více šablon a typy datových položek, pro které je má využít. Pojmenoval jsem ho TypeTemplateSelector.
Podívejte se na ukázku použití. Mám dvě ViewModel třídy, jednu pro zobrazení zaměstnance a druhou pro zobrazení hardwaru a zobrazuji je v jenom seznamu, každý s jinou šablonou:
XAML kód:
<ItemsControl ItemsSource="{Binding Items}" HorizontalContentAlignment="Stretch">
<ItemsControl.ItemTemplateSelector>
<c:TypeTemplateSelector>
<!-- template for PersonViewModel -->
<c:TemplateDefinition Type="models:PersonViewModel">
<DataTemplate>
<Border Margin="5" Padding="5" Background="LightBlue">
<TextBlock Text="{Binding FullName}" Background="LightBlue" />
</Border>
</DataTemplate>
</c:TemplateDefinition>
<!-- template for ComputerViewModel -->
<c:TemplateDefinition Type="models:ComputerViewModel">
<DataTemplate>
<Border Margin="5" Padding="5" Background="Orange">
<TextBlock>
<Run Text="{Binding IdNumber}" />
<Run Text=" " />
<Hyperlink>
<Run Text="Show status" />
</Hyperlink>
</TextBlock>
</Border>
</DataTemplate>
</c:TemplateDefinition>
</c:TypeTemplateSelector>
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
Datové objekty a získání dat:
// sample data source (place to component/window constructor)
this.DataContext = new
{
Items = new object[] {
new PersonViewModel() { FullName = "Tomáš Jecha" },
new PersonViewModel() { FullName = "Karel Novák" },
new ComputerViewModel() { IdNumber = "IC14/65435808" },
new ComputerViewModel() { IdNumber = "IC14/65435809" },
new PersonViewModel() { FullName = "Some other guy" },
new ComputerViewModel() { IdNumber = "IC14/65435810" }
}
};
// sample data classes
public class PersonViewModel
{
public string FullName { get; set; }
}
public class ComputerViewModel
{
public string IdNumber { get; set; }
}
A konečně kód komponenty:
[ContentProperty("Templates")]
public class TypeTemplateSelector : DataTemplateSelector
{
public TypeTemplateSelector()
{
this.Templates = new TemplateDictionary();
}
public TemplateDictionary Templates { get; set; }
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
var templateDef = this.Templates.FindTemplateForType(item.GetType());
if (templateDef == null || templateDef.Template == null)
{
// not found / template not specified - use base selector
return base.SelectTemplate(item, container);
}
return templateDef.Template;
}
}
public class TemplateDictionary : List<TemplateDefinition>
{
public TemplateDefinition FindTemplateForType(Type type)
{
TemplateDefinition resultItem;
// try to find by type
resultItem = this.FirstOrDefault(t => t.Type != null && t.Type.IsAssignableFrom(type));
// try to find fallback value
if(resultItem == null)
resultItem = this.FirstOrDefault(t => t.Type == null);
return resultItem;
}
}
[ContentProperty("Template")]
public class TemplateDefinition : DependencyObject
{
public Type Type
{
get { return (Type)GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register("Type", typeof(Type), typeof(TemplateDefinition), new PropertyMetadata(null));
public DataTemplate Template
{
get { return (DataTemplate)GetValue(TemplateProperty); }
set { SetValue(TemplateProperty, value); }
}
public static readonly DependencyProperty TemplateProperty =
DependencyProperty.Register("Template", typeof(DataTemplate), typeof(TemplateDefinition), new PropertyMetadata(null));
}
Kód samozřejmě užívejte a upravujte, jak jen uznáte za vhodné.