WPF数据模板和控件模板
WPF中有控件模板和数据模板,控件模板可以让我们自定义控件的外观,而数据模板定义了数据的显示方式,也就是数据对象的可视结构,但是这里有一个问题需要考虑,数据是如何显示出来的?虽然数据模板定义了数据的可视结构,但是我们清楚的知道,只有控件才是可视的,数据一般是被控件承载,这里需要另外的一个对象ContentPresenter。
ContentPresenter继承自FrameworkElement,从字面意思可以知道该对象是用来显示Content,说道content我们应该不陌生,因为在WPF中有一类组件就因为该属性而划分。ContentControl控件,该类型的控件都具有content属性,是一个object,也就是说ContentControl 可以包含任意类型的CLR对象 (如string或 DateTime 对象) 或 UIElement 对象 (如 Rectangle 或 Panel),,这样我们便可以添加丰富内容到控件 (如 Button 和 CheckBox,例如给TextBox添加一个string对象作为水印内容)。 也就是说,像Button等的content属性是由ContentControl类定义的,目的是为了将Content的内容显示在窗体上,那么ContentControl类是如何工作的呢?这时就要去了解ContentPresenter类,ContentPresenter的作用就是显示内容,因为Control类没有Content属性,所以在Controls类上就实现了一个ContentControl类,然后ContentPresenter负责将ContentControl的Content属性显示出来。每个控件都有一个默认的ContentPresenter用于显示Content内容,这种控件被称为内容控件。在继承Control类的情况下,我们同时可以使用ContentPresenter类,不过需要自己准备一个属性与其Content属性绑定。
ContentControl是一个拥有ControlTemplate的控件,用来显示单个非集合数据,而该属性是DataTemlpate类型,通常使用DataTemplate 指定数据的直观表示,数据模板作用于所有继承自ContentControl的内容控件的ContentTemplate属性和所有继承自ItemsControl的列表控件的ItemTemplate属性,即用于设置控件的数据内容。当您将 ItemsControl(如 ListBox)绑定到整个集合时,DataTemplate 对象尤其有用。如果没有特殊说明,ListBox 将在集合中显示对象的字符串表示形式。在此情况下,可以使用 DataTemplate 定义数据对象的外观,(为了正常的显示也可以重写tostring方法)。DataTemplate 的内容变成数据对象的可视结构。
可以在 DataTemplate 中使用数据绑定。例如,假定 ListBox 绑定到 Customer 对象的集合,并且将 ItemTemplate 属性设置为 DataTemplate。创建 ListBox 时,将为集合中的每个 Customer 创建一个 ListBoxItem,并将 ListBoxItem 的 DataContext 设置为相应的客户。也就是说,第一个 ListBoxItem 的 DataContext 设置为第一个客户,第二个 ListBoxItem 的 DataContext 设置为第二个客户,依此类推。可以将 DataTemplate 中的元素绑定到 Customer 对象的属性。简单的说数据模板就是在不改变控件外观的情况下,对内容的修改。
<CheckBox Template="{StaticResource ResourceKey=rect}">
<CheckBox.ContentTemplate>
<DataTemplate>
<CheckBox Content="Hello" />
</DataTemplate>
</CheckBox.ContentTemplate>
</CheckBox>
下面来自微软的帮助
You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added. Every ContentControl type has a ContentPresenter in its default ControlTemplate.
When a ContentPresenter object is in a ControlTemplate of a ContentControl, the Content, ContentTemplate, and ContentTemplateSelector properties get their values from the properties of the same names of the ContentControl. You can have the ContentPresenter property get the values of these properties from other properties of the templated parent by setting the ContentSource property or binding to them.
The ContentPresenter uses the following logic to display the Content:
-
If the ContentTemplate property on the ContentPresenter is set, the ContentPresenter applies that DataTemplate to the Content property and the resulting UIElement and its child elements, if any, are displayed. For more information about DataTemplate objects, see Data Templating Overview.
-
If the ContentTemplateSelector property on the ContentPresenter is set, the ContentPresenter applies the appropriate DataTemplate to the Content property and the resulting UIElement and its child elements, if any, are displayed.
-
If there is a DataTemplate associated with the type of Content, the ContentPresenter applies that DataTemplate to the Content property and the resulting UIElement and its child elements, if any, are displayed.
-
If Content is a UIElement object, the UIElement is displayed. If the UIElement already has a parent, an exception occurs.
-
If there is a TypeConverter that converts the type of Content to a UIElement, the ContentPresenter uses that TypeConverter and the resulting UIElement is displayed.
-
If there is a TypeConverter that converts the type of Content to a string, the ContentPresenter uses that TypeConverter and creates a TextBlock to contain that string. The TextBlock is displayed.
-
If the content is an XmlElement, the value of the InnerText property is displayed in a TextBlock.
-
The ContentPresenter calls the ToString method on the Content and creates a TextBlock to contain the string returned by ToString. The TextBlock is displayed.