Control Templates 控制模板
简单控制模板
<Button Margin="0,0,2,2" Grid.Row="0" Grid.Column="0" Name="cell00" > <Button.Template> <ControlTemplate> <Grid> <Rectangle Fill="Orange"/> </Grid> </ControlTemplate> </Button.Template> </Button>
控件模板和样式
<Style TargetType="{x:Type Button}"> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Rectangle Fill="Green" /> </ControlTemplate> </Setter.Value> </Setter> </Style>
Template Binding 模板绑定
<Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Red"/> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Rectangle Fill="{TemplateBinding Property=Background}" /> </ControlTemplate> </Setter.Value> </Setter> </Style>
模板绑定类似于数据绑定,只是要绑定的属性来自您要替换其模板的控件(称为templatedparent)在我们的例子中, Button类的任何依赖属性都可以作为模板绑定源
完整绑定提供的扩展选项,可以在模板内使用Binding对象,其RelativeSource为TemplatedParent以指示如何解析路径
<Rectangle Fill="{Binding Path=Background, RelativeSource={RelativeSource TemplatedParent}}" />
将控件模板与样式完全分离到一个单独的资源中:
<ControlTemplate x:Key="ButtonTemplate"> <Grid> <Rectangle Fill="{TemplateBinding Property=Button.Background}"/> </Grid> </ControlTemplate>
<Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Yellow"/> <Setter Property="FontSize" Value="32pt"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/> </Style>
与样式一样,我们可以通过在ControlTemplate元素上设置TargetType属性来避免在模板绑定属性名称前加上类前缀:
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button"> <Grid> <Rectangle Fill="{TemplateBinding Property=Background}"/> </Grid> </ControlTemplate>
Content Presenters 内容展示器
内容展示器是 WPF 等同于“您的内容”,它允许在运行时插入由ContentControl持有的内容。
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button"> <Border Background="{TemplateBinding Property=Background}"> <!--<ContentPresenter Content="{TemplateBinding Property=Content}"/>--> <!--设置了TargetType属性,可以简化--> <ContentPresenter Margin="{TemplateBinding Property=Padding}"/> </Border> </ControlTemplate>
<Style TargetType="{x:Type Button}"> <Setter Property="Padding" Value="20"/> </Style>
将Padding从按钮内部映射到内容呈现器 Margin外部
就像Padding和Margin之间的映射一样,构建为您提供所需外观的元素并从模板化父级绑定适当
的属性将是创建您自己的控件模板的大量工作。
Template Triggers 模板触发器
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button"> <Grid> <Rectangle Fill="{TemplateBinding Property=Background}" Name="rect" /> <ContentPresenter Margin="{TemplateBinding Property=Padding}" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="rect" Property="BitmapEffect"> <Setter.Value> <OuterGlowBitmapEffect GlowColor="Blue" GlowSize="10" /> </Setter.Value> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
Repurposing an existing property 扩展模板
在构建控件模板时,通常情况下您想要公开的变量多于被“模板化”的控件上的属性
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button"> <Grid> <Rectangle Fill="{TemplateBinding Property=Background}" Name="rect" /> <ContentPresenter Margin="{TemplateBinding Property=Padding}" /> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="rect" Property="BitmapEffect" Value="{Binding Path=Tag,RelativeSource={RelativeSource TemplatedParent}}"> </Setter> </Trigger> </ControlTemplate.Triggers> </ControlTemplate>
<Style TargetType="{x:Type Button}"> <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/> <Setter Property="Tag"> <Setter.Value> <OuterGlowBitmapEffect GlowColor="Yellow" GlowSize="10"/> </Setter.Value> </Setter> </Style>
当IsMouseOver属性为True时,控件模板的触发器使用Tag属性的值。请注意,我们使用普通绑定(使用TemplatedParent RelativeSource)而不是模板绑定,因为普通绑定对象在运行时支持强制转
换,而模板绑定在编译时静态检查类型。正常绑定的使用使我们能够从对象类型的Tag属性中拉出BitmapEffect 。
当我们使用这种样式创建一个按钮时, Tag值充当默认值,我们可以用任何满足我们想象的位图效果来覆盖它(如示例 9‑6 中的中间按钮所示)。
<Button Margin="0,0,2,2" Grid.Row="0" Grid.Column="0" Name="cell00" > <Button.Tag> <BevelBitmapEffect BevelWidth="10"/> </Button.Tag> </Button>
请记住,控件的工作是提供行为。控件模板提供视觉效果。控件可以提供一组默认的视觉效果,但它应该允许替换这些视觉效果,以便提供与内置控件相同的灵活性。如果您需要同时提供自定义行为
和自定义视觉效果,请构建两个组件:一个控件和一个设计用于合并到控件模板中的元素。符合这种
当然,控件不可能完全独立于其视觉效果。如果控件要正确运行,任何控件都会强加一些模板必须满足的要求。这些要求的范围因控制而异。
任何控件类型与样式或模板之间都存在隐含的契约。
控件允许通过替换可视化树来自定义其外观,但树必须反过来代表控件提供某些功能。
以下部分描述了控件与其模板相关的各种方式。