在WPF中,ControlTemplate
和DataTemplate
有什么区别?
Button
并不会绑定到业务对象——它只是为了能够被点击而出现。然而,ContentControl
或ListBox
通常会出现,以便为用户呈现数据。DataTemplate
用于为底层数据提供视觉结构,而ControlTemplate
与底层数据无关,仅为控件本身提供视觉布局。
ControlTemplate
通常只包含TemplateBinding
表达式,将其绑定回控件本身的属性,而DataTemplate
将包含标准的绑定表达式,将其绑定到其DataContext
(业务/域对象或视图模型)的属性。简单来说,ControlTemplate
描述如何显示一个控件,而 DataTemplate
描述如何显示数据。
例如:
Label
是一个控件,它包含一个 ControlTemplate
,该模板指定了应该使用一个围绕某些内容(DataTemplate
或另一个控件)的 Border
来显示这个 Label
。
Customer
类是数据,并且将使用一个 DataTemplate
来显示。该模板可以指定将 Customer
类型显示为一个包含两个 TextBlocks
的 StackPanel
,其中一个显示姓名,另一个显示电话号码。值得注意的是,所有类都使用 DataTemplates
显示,通常会使用默认模板,即一个带有对象的 ToString
方法返回值的 TextBlock
。
Troels Larsen在MSDN论坛上有一个很好的解释。
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="ButtonContentTemplate">
<StackPanel Orientation="Horizontal">
<Grid Height="8" Width="8">
<Path HorizontalAlignment="Stretch"
Margin="0,0,1.8,1.8"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FF000000"
Data="M0.5,5.7 L0.5,0.5 L5.7,0.5"/>
<Path HorizontalAlignment="Stretch"
Margin="2,3,0,0"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FFFFFFFF"
Data="M3.2,7.5 L7.5,7.5 L7.5,3.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1.2,1.4,0.7,0.7"
VerticalAlignment="Stretch" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000"
Data="M2.5,2.5 L7.5,7.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1.7,2.0,1,1"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FF000000"
Data="M3,7.5 L7.5,7.5 L7.5,3.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1,1,1,1"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FFFFFFFF"
Data="M1.5,6.5 L1.5,1 L6.5,1.5"/>
</Grid>
<ContentPresenter Content="{Binding}"/>
</StackPanel>
</DataTemplate>
<ControlTemplate TargetType="Button" x:Key="ButtonControlTemplate">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="1"/>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="2"/>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="3"/>
</StackPanel>
</Window>
(模板明显是从http://msdn.microsoft.com/en-us/library/system.windows.controls.controltemplate.aspx和http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.contenttemplate%28VS.95%29.aspx中抄袭的)
无论如何,ControlTemplate决定了按钮本身的外观,而ContentTemplate决定了按钮内容的外观。因此,您可以将内容绑定到您的数据类之一,并使其以任何您想要的方式呈现。
ControlTemplate
: 表示控件的样式。
DataTemplate
: 表示数据的样式(您希望如何显示数据)。
所有控件都使用默认的控件模板,您可以通过模板属性覆盖它。
例如
Button
模板是控件模板。
Button
内容模板是数据模板。
<Button VerticalAlignment="Top" >
<Button.Template>
<ControlTemplate >
<Grid>
<Rectangle Fill="Blue" RadiusX="20" RadiusY="20"/>
<Ellipse Fill="Red" />
<ContentPresenter Content="{Binding}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="50">
<TextBlock Text="Name" Margin="5"/>
<TextBox Text="{Binding UserName, Mode=TwoWay}" Margin="5" Width="100"/>
<Button Content="Show Name" Click="OnClickShowName" />
</StackPanel>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
public String UserName
{
get { return userName; }
set
{
userName = value;
this.NotifyPropertyChanged("UserName");
}
}
ControlTemplate
- 改变元素的外观。例如,Button
可以包含图像和文本。
DataTemplate
- 使用元素表示底层数据。
ControlTemplate
定义了控件的视觉外观,DataTemplate
替换数据项的视觉外观。
例如:我想将按钮从矩形变为圆形 => 使用 Control Template。
如果您有复杂的对象传递给控件,它只会调用并显示 ToString()
方法,而使用 DataTemplate
可以获取数据对象的各种成员并显示和更改它们的值。
ItemTemplate
属性:
DataTemplate
用于提供为您提供ItemTemplate属性的元素,以便您根据之前定义的DataTemplate
和通过您提供的选择器绑定数据来替换其项的内容。
但是,如果您的控件没有为您提供此功能,则仍然可以使用ContentView
,该控件可以从预定义的ControlTemplate
中显示其内容。有趣的是,您可以在运行时更改ContentView
的ControlTemplate
属性。还有一件需要注意的事情是,与具有ItemTemplate
属性的控件不同,您无法为此(ContentView)控件创建TemplateSelector
。但是,您仍然可以创建触发器以在运行时更改ControlTemplate
。