模板就是“具有一定规格的样板”,有了模板,就可以依据它制造出很多一样的实例。
模板分为三大类:
DataTemplate 数据外衣
ControlTemplate 控件外衣
ItemsPanelTemplate 项布局(如:ListBox的item)
效果:
代码:
public class Car
{
public string Automake { get; set; }
public string Name { get; set; }
public string Year { get; set; }
public string TopSpeed { get; set; }
}
//厂商名称转换成Logo图片路径
public class AutomakerTologoPathConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string uriStr = string.Format(@"/Resources/Images/{0}.jpg", (string)value);
return new BitmapImage(new Uri(uriStr, UriKind.Relative));
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
ContentTemplate="{StaticResource carDetailViewTemplate}" 给用户控件添加外衣
ItemTemplate="{StaticResource carListItemViewTemplate}" 给ListBox每个Item项添加外衣
public partial class Window15 : Window
{
public Window15()
{
InitializeComponent();
InitialCarList();
}
private void InitialCarList()
{
List carList = new List()
{
new Car(){Automake="4",Name="name1",Year="1999",TopSpeed="300"},
new Car(){Automake="5",Name="name2",Year="1990",TopSpeed="150"},
new Car(){Automake="4",Name="name3",Year="1991",TopSpeed="350"},
new Car(){Automake="5",Name="name4",Year="1995",TopSpeed="400"},
};
listboxCars.ItemsSource = carList;
}
}
注意:TemplateBinding 将自己的属性关联到目标控件的某个属性上。
第二步:样式绑定模板
控制 ItemControl条目容器
<ItemsPanelTemplate>
决定控件外观的是 ControlTemplate, 是控件 Template 属性的值。决定数据外观的是 DataTemplate , 是控件 ContentTemplate 属性的值。
ContentPresenter(内容content,内容位置,内容模板 contentTemplate) 控件是ControlTemplate控件树的一个结点。DataTemplate 控件树是 ControlTemplae控件树的一颗子树。
效果:
代码:
创建数据类型
public class Unit
{
public int Price { get; set; }
public string Year { get; set; }
}
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication"
xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
Title="Window17" Height="300" Width="300">
<local:Unit Year="2001年" Price="100"/>
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication"
xmlns:c="clr-namespace:System.Collections;assembly=mscorlib">
使用层级数据模板 HierarchicalDataTemplate
xml数据
只设计一个 HierarchicalDataTemplate ,会自动产生迭代效果。
效果:
private void StackPanel_Click(object sender, RoutedEventArgs e)
{
MenuItem mi = e.OriginalSource as MenuItem;
//HierarchicalDataTemplate 作用的目标是MenuItem.Header
XmlElement xe = mi.Header as XmlElement;
MessageBox.Show(xe.Attributes["Name"].Value);
}
DataTemplate 和 ControlTemplate 两个类均派生自 FrameWorkTemplate类。这个类有个 FindName方法 供我们查询内部控件。
ControlTemplate 对象: 访问其目标控件 Template . FindName就能拿到。
DataTemplate 对象: 直接使用低层数据(如果想获得控件长度、宽度 Template . FindName)。
效果:
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window5" Height="300" Width="300">
事件
private void Button_Click(object sender, RoutedEventArgs e)
{
//Template.FindName
TextBox tb= uc.Template.FindName("textbox1", this.uc) as TextBox;
tb.Text = "textbox1";
StackPanel sp = tb.Parent as StackPanel;
(sp.Children[1] as TextBox).Text = "textbox2";
(sp.Children[2] as TextBox).Text = "textbox3";
}
如果获得与用户界面相关的数据(比如控件的宽度、高度)ContentTemplate.FindName("")。
如果获得与业务相关的数据,直接访问底层(WPF采用数据驱动UI逻辑)Content
效果:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Skill { get; set; }
public bool HasJob { get; set; }
}
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AutomaticConfigurationAPP"
Title="Window6" Height="300" Width="300">
ContentTemplate="{StaticResource stuDT}"
Margin="5"/>
C#
//内容模板查找控件
TextBlock tb= this.cp.ContentTemplate.FindName("textblockname", this.cp) as TextBlock;
MessageBox.Show(tb.Text);
//直接使用底层数据
Student stu = this.cp.Content as Student;
MessageBox.Show(stu.Name);
界面:
XAML
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:System.Collections;assembly=mscorlib"
xmlns:local="clr-namespace:AutomaticConfigurationAPP"
Title="Window2" Height="300" Width="300">
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}"/>
c#
private void textboxname_GotFocus(object sender, RoutedEventArgs e)
{
//访问业务逻辑数据
TextBox tb = e.OriginalSource as TextBox;//获得事件的源头(TextBox)
//沿UI元素树上溯到DataTemplate的目标控件(ContentPresenter),并获取它内容,它内容一定是个Student
ContentPresenter cp = tb.TemplatedParent as ContentPresenter;
Student stu = cp.Content as Student;//一行
//MessageBox.Show(stu.HasJob.ToString());
this.listviewStudent.SelectedItem = stu;
//访问界面逻辑数据
//查找包含的ListViewItem
ListViewItem lvi = this.listviewStudent.ItemContainerGenerator.ContainerFromItem(stu) as ListViewItem;
CheckBox chb = this.FindVisualChild
MessageBox.Show(chb.Name);
}
private ChildType FindVisualChild
where ChildType:DependencyObject
{
//可视化对象包含的子集个数
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
//返回指定父可视对象中位于指定集合索引位置的子可视对象
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is ChildType)
{
return child as ChildType;
}
else
{
ChildType childofChild = FindVisualChild
if (childofChild != null)
return childofChild;
}
}
return null;
}
Style样式包含两种元素:
Setter类 设置控件静态的外观。
Trigger类 设置控件行为的风格。
实例一:模板绑定Padding属性的值,并使用属性值在ContentPresenter 元素周围创建外边距。
实例二:动画按钮
CornerRadius="2"
Background="Red"
TextBlock.Foreground="White"
Name="Border">
Stroke="Black"
StrokeThickness="1"
StrokeDashArray="1 2"
SnapsToDevicePixels="True" >
实例三:修改LIstBox样式(嵌套模板)。
步骤:
1、ItemsPresenter 外观(ListBox)
2、ContentPresenter 外观(ListBoxItem)
3、ScrollBar外观