d## WPF中的模板Template ##
WPF中通过引入模板将数据和算法的内容和形式解耦
ControlTemplate 是算法的内容的表现形式,决定了控件长成什么样子,让程序员在控件原有的内部逻辑基础上扩展自己的逻辑
DataTemplate 是数据的内容的表现形式,数据显示成什么形式,外观
DataTemplate
常用在三处:
ContentControl的ContentTemplate属性,
ItemsControl的ItemTemplate属性,
GridViewColumn的CellTemplate属性
public class AutomakerToLogoPathConverter:IValueConverter{
public object Convert(object value,Type targetType,object parameter,CultureInfo culture){
string uriStr = string.Format(@"/Resources/Logos/{0}.png",(stringvalue));
return new BitmapImage(new Uri(uriStr,UriKind.Relative));
}
publiuc ConvertBack(object value,Type targetType,object parameter,CultureInfo culture){
throw new NotImplementedException();
}
}
public class NameToPhotoPathConverter:IValueConverter{
public object Convert(object value,Type targetType,object parameter,CultureInfo culture){
string uriStr = string.Format(@"/Resources/Images/{0}.png",(stringvalue));
return new BitmapImage(new Uri(uriStr,UriKind.Relative));
}
publiuc ConvertBack(object value,Type targetType,object parameter,CultureInfo culture){
throw new NotImplementedException();
}
}
...
<Window
...>
<Window.Resources>
<local:AutomakerToLogoPathConverter x:Key = "a2l"/>
<local:NameToPhotoPathConverter x:Key = "n2p"/>
<DataTemplate x:Key = "carDetailViewTemplate"
<Stackpanel>
....
<Image Width = "400" Height = "250"
Source = "{Binding Name,Converter{StaticResource n2p}}"/>
...
</Stackpanel>
...
</DataTemplate>
<DataTemplate x:Key = "carListViewTemplate"
...
</DataTemplate>
</Window.Resources>
<StackPanel Orientation = "Horizontal" Margin = "5">
<UserControl ContentTemplate = "{StaticResource carDetailViewTemplate}"
Content = "{Binding SelectedItem,ElementName = listBoxCars}"/>
<ListBox x:Name = "listBoxCars" Width = "180" margin= “5,0”
ItemTemplate = "{StaticResource0 carListViewTemplate}"/>
</StackPanel >
</Window>
...
private void InitialCarList(){
List<Car> carList = new List<Car>(){
new Car{Automaker = "tfewaf",Name = "fase",Year = "1964",TopSpeed = "131"},
new Car{Automaker = "tfewaf",Name = "fase",Year = "1964",TopSpeed = "131"},
new Car{Automaker = "tfewaf",Name = "fase",Year = "1964",TopSpeed = "131"},
new Car{Automaker = "tfewaf",Name = "fase",Year = "1964",TopSpeed = "131"},
new Car{Automaker = "tfewaf",Name = "fase",Year = "1964",TopSpeed = "131"}
}
this.lisrBoxCars.ItemsSource = carList;
}
ControlTemplate
用处:
更换ControlTemplate改变控件外观,使之具有更优的用户体验及外观。
借助ControlTemplate让程序员和设计师并行工作。
打开Blend开始编辑
组件上右键,编辑模板,编辑副本
ControlTemplate可以放在三个地方Application的资源字典中,界面元素的资源字典中,外部XMAL文件中。
ControlTemplate 在Blend中通过可视化界面编辑模板即可。
ControlTemplate 和DataTemplate 的区别
ControlTemplate :决定控件的外观
DataTemplate : 决定数据的外观。与具体数据相关的控件,比如需要Binding数据的控件,数据转换Converter。
DataTemplate 是 ControlTemplate 的一颗子树。
如何找控件树根:
控件的TemplateParent属性的值就是应用了模板的控件。
控件的TemplateBinding的数据源就是应用类这个模板的目标控件。
Template的应用
1. 逐个设置控件的Template/ContentTemplate/ItemsTemplate/CellTemplate 等属性。
2. 把Template应用在某个类型的控件或数据上。
例:
<Window.Resources>
<DataTemplate DataType = "{x:Type local:Unit}">
<StackPanel>
<TextBlock Text = "{Binding Price}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
...
public class Unit{
public int Price{get;set;}
public string Year{get;set;}
}
DataTemplate的目标数据类型和ListBox的条目类型都是Unit
DataTemplate会自动加载到所有Unit类型对象上
<Window.Resources>
<DataTemplate DataType = "Unit">
<StackPanel>
<TextBlock Text = "{Binding XPath = @Price}"/>
<TextBlock Text = "{Binding XPath = @Year}"/>
</StackPanel>
</DataTemplate>
...
<XmlDataProvider x:Key = "ds" XPath="Unites/Unit">
<x:XData>
<Units xmlns = "">
<Unit Year = "2001" Price = "100"/>
...
</Units>
</x:XData>
</XmlDataProvider>
</Window.Resources>
...
<ListBox ItemSource="{Binding Source = {StaticResource de}}"/>
<ComboBox ItemSource="{Binding Source = {StaticResource de}}"/>
将XML作为数据源
<HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath = Student}">
<TextBlock Text="{Binding XPath=@Name}"
</HierarchicalDataTemplate>
找到Template中的组件
ControlTemplate
TextBox tb = this.uc.Template.FindName("textBox1",this.uc) as Textbox;
tb.Text="Hello Wpf";
StackPanel sp = tb.Parent as StackPanel;
(sp.children[1] as TextBox).Text = "Hello Template";
(sp.children[1] as TextBox).Text = "Hello Template";
DataTemplate
例1:
<ContentPresenter ContentTemplate="{StaticResource stuDT}"/>
...
TextBox tb = this.uc.ContentTemplate.FindName("textBox1",this.cp) as Textbox;
MessageBox.Show(tb.Text);
例2:
private void TextBoxNAme_GotFocus(object sender,RoutedEventArgs e){
TextBox tb = e.OriginalSource as TextBox;//获取事件发起的源头
ContentPresenter cp = tb.TemplatedParent as ContentPresenter;//获取模板目标
Student stu = cp.Content as Student;//获取业务逻辑
this.listViewStudent.SelectedItem = stu;//设置ListView的选中项
//访问界面元素
ListViewItem lvi = this.listViewStudent.
ItemContainerGenerator.ContainerFromItem(stu) as ListViewItem;
CheckBox chb = this.FindVisualChild<CheckBox>(lvi);
MessageBox.Show(chb.Name);
}
private ChildType FindVisualChild<ChildType>(DependencyObject obj)where ChildType:DependencyObject {
for(int i=0;i<VisualTreeHelper.GetChildrenCount(obj);i++){
DependencyObject child = VisualTreeHelper.Get(obj,i);
if(child !=null && child is ChildType){
return child as ChildType;
}else{
ChildType childOfChild = FindVisualChild<ChildType>(child);
if(childOfChild !=null) return childOfChild ;
}
}
return null;
}
Style样式
style包括setter和trigger,分别表示控件的静态外观风格和行为风格。
Setter 设置属性值
例:
<Setter Property = "FontSize" Value="24"/>
<Setter Property = "FontStyle" Value="Italic"/>
<Setter Property = "Template" Value="ControlTemplate"/>
Trigger 触发器
一般由用户操作触发。
事件触发型EventTrigger,数据变化触发型Trigger/DataTrigger,多条件触发型MultiTrigger/MultiDataTrigger。
1.基本触发器
Property 检测的属性,Value 触发的条件
Setters触发后执行的动作,比如换肤
例:
<Style Targettype = "CheckBox">
<Style.Triggers>
<Trigger Property = "IsChecked" Value="true">
<Trigger.Setters>
<Setter Property="FontSize" value="20"/>
<Setter Property="Foreground" value="Orange"/>
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
...
<StackPanle>
<CheckBox Content="check1"/>
<CheckBox Content="check2"/>
<CheckBox Content="check3"/>
<CheckBox Content="check4"/>
</StackPanle>
2.MultiTrigger 多条件同时成立才触发,比Trigger多一个Conditions属性,需要成立的条件就存储在此集合中。
...
<MultiTrigger.Conditions>
<Coadition Property="isChecked" Value="true"/>
<Coadition Property="Content" Value="Hello"/>
</MultiTrigger.Conditions>
...
3.DataTrigger Binding属性的值与Value的值一样触发
<DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.Length,Converter={StaticResource cvt2r}}"
Value="false">
//在cvtr中进行判断操作
<Setter.../>
<Setter.../>
<Setter.../>
</DataTrigger>
4.MultiDataTrigger 多数据条件同时满足时触发
...
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=ID}" Value="2"/>
<Condition Binding="{Binding Path=Name}" Value="Tom"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
...
</MultiDataTrigger.Setters>
</MultiDataTrigger>
5.EventTrigger
事件触发,比较特殊。它由事件触发,而且触发后不是应用一组setter而是执行一段动画。
UI层的动画效果往往与EventTrigger关联。
例如Button的MouseEnter和MouseLeave的事件触发器。
例:
<EventTrigger RoutedEvent = "MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="150" Duration= "0:0:0.2" Storyboard.TargetProperty="Width"/>
<DoubleAnimation To="150" Duration= "0:0:0.2" Storyboard.TargetProperty="Width"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>