- ControlTemplate:用于定义控件的结构和外观,这样可以将控件外观与控件功能分离开. 在xaml中ControlTemplate通常配置到Style中,通过Style控制控件的结构和外观
- 如果控件继承自ContentControl类,其模板将包含一个ContentPresenter类成员,ContentPresenter用于指定添加内容的位置,下面是一个Button Style,ContentPresenter的标记表明Button的Content应在Grid内垂直且水平居中显示
ContentPresenter example<Style TargetType="Button">
<!--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的属性
ControlTemplate example<ControlTemplate TargetType="ListBoxItem">
<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 会与侧边重合
TemplateBinding example<ControlTemplate x:key="ButtonTemplate" TargetType="{x:Type Button}">
<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的工具,关键代码如下:
TemplateBinding exampleprivate void Window_Loaded(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);
}
}