ControlTemplate
- ControlTemplate:用于定义控件的结构和外观,这样可以将控件外观与控件功能分离开. 在xaml中ControlTemplate通常配置到Style中,通过Style控制控件的结构和外观
-
如果控件继承自ContentControl类,其模板将包含一个ContentPresenter类成员,ContentPresenter用于指定添加内容的位置,下面是一个Button Style,ContentPresenter的标记表明Button的Content应在Grid内垂直且水平居中显示
> <!--Set to true to not get any properties from the themes.--> <Setter Property="OverridesDefaultStyle" Value="True"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid> <Ellipse Fill="{TemplateBinding Background}"/> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
-
ControlTemplate中也可以添加Trigger,当一个属性发生变化时用于控制一个或者多个属性的变化。如下代码,注意TargetName属性指定了control的名字,满足条件时就会修改该control的属性
> <Border Name="ItemBorder" BorderThickness="1" Margin="1" Background="{StaticResource TransparentBrush}"> <ContentPresenter /> </Border> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="ItemBorder" Property="Background" Value="{StaticResource TransparentBrush}" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="ItemBorder" Property="Background" Value="{StaticResource TransparentBrush}" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
- 如果控件继承自ItemsControl类,其模板将包含一个ItemsPresenter元素,指示何处放置列表项的模板
-
模板绑定:通过使用模板绑定,模板可以从应用模板的控件提取一个值,ContentPresenter之所以能显示Content,就是因为它有一个隐式的模板绑定将ContentPresenter.Content设置为Button.Content,如下代码则设置button content的内边距,如果不把Margin通过TemplateBinding绑定到Padding属性,Button的content 会与侧边重合
> <Border BorderBrush="Orange" BorderThickness="3" CornerRadius="2" Background="Red" TextBlock.Foreground="White"> <ContentPresenter RecognizeAccessKey="True" Margin="{TemplateBinding Padding}"> </ContentPresenter> </Border> </ControlTemplate>
- 模板与样式:两者都可以改变control的外观,但样式被限制在一定范围,它不能使用由不同子control组成的可视化数替换control的原有外观,如条目2中的椭圆形按钮,仅使用style无法实现.
-
WPF编程宝典中提供的能查看每个control的Template的工具,关键代码如下:
object sender, RoutedEventArgs e) { Type controlType = typeof(Control); List<Type> derivedTypes = new List<Type>(); Assembly assembly = Assembly.GetAssembly(typeof(Control)); foreach (Type type in assembly.GetTypes()) { if (type.IsSubclassOf(controlType) && !type.IsAbstract && type.IsPublic) { derivedTypes.Add(type); } } derivedTypes.Sort(delegate(Type x, Type y) { return x.FullName.CompareTo(y.FullName); }); lstTypes.ItemsSource = derivedTypes; } private void lstTypes_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { Type type = (Type)lstTypes.SelectedItem; ConstructorInfo info = type.GetConstructor(Type.EmptyTypes); Control control = (Control)info.Invoke(null); control.Visibility = Visibility.Collapsed; grid.Children.Add(control); ControlTemplate template = control.Template; XmlWriterSettings setting = new XmlWriterSettings(); setting.Indent = true; StringBuilder sb = new StringBuilder(); XmlWriter writer = XmlWriter.Create(sb, setting); System.Windows.Markup.XamlWriter.Save(template, writer); txtTemplate.Text= sb.ToString(); grid.Children.Remove(control); } catch (Exception ex) { txtTemplate.Text = string.Format("Error generating tempalte:{0}",ex); } }
DataTemplate
- DataTemplate支持对数据的表现形式进行自定义,它可以包含任何元素的组合,还应当包含一个或者多个数据绑定表达式,有两种类型的控件支持:
- 内容控件,通过ContentTemplate属性支持数据模板,内容模板用于显示任何放在Content属性中的内容
- 列表控件,继承自ItemsControl的控件,通过ItemTemplate属性支持数据模板,用于显示ItemsSource提供的集合中的每个项。也就是该模板会被用作列表中每个项的ContentTemplate模板,如对于ListBox控件,数据模板会作用与ListBoxItem元素,而对于ComboBox则会作用于ComboBoxItem元素
- DataTrigger:可以根据绑定的数据对象中的属性值使用触发器修改模板中的属性
> <DataTemplate.Triggers> <DataTrigger Binding="{Binding Path=CategoryName}" Value="Tools"> <Setter Property="ListBoxItem.Foreground" Value="Red"></Setter> </DataTrigger> </DataTemplate.Triggers> </DataTemplate>
- 使用值转换器:实现了IValueConverter接口的类,能够将一个值从绑定的对象转换为可用于设置模板中与格式化相关的属性的值
> <Image Source="{Binding path=imagePath}" Converters="{StaticResource ImagePathConverter}" /> </DataTemplate>
- 使用模板选择器:模板选择器检查绑定的数据对象,并在几个不同的模板之间进行选择。需要继承DataTemplateSelector类,重写SelectTemplate函数。如下代码自定义的SingleHighlightTemplateSelector类包含连个数据模板,并根据属性的值在SelectTemplate函数中选择相应的数据模板
> <ListBox.ItemTemplateSelector> <local:SingleHighlightTemplateSelector DefaultTemplate="{StaticResource DefaultTemplate}" HighlightTemplate="{StaticResource HighlighTemplate}" PropertyoEvaluate="CategoryName" PropertyValueToHighlight="Travel"></local:SingleHighlightTemplateSelector> </ListBox.ItemTemplateSelector> </ListBox>