图形用户界面应用程序较之控制台界面应用程序最大的好处就是界面友好、数据显示直观。CUI程序中数据只能以文本的形式线性显示,GUI程序则允许数据以文本、列表、图形等多种形式立体显示。
用户体验在GUI程序设计中起着举足轻重的作用-----用户界面设计成什么样看上去才足够的漂亮?控件如何安排才简单易用并且少犯错误?这些都是设计师需要考虑的问题。WPF系统不但支持传统的Winfrom编程的用户界面和用户体验设计,更支持使用专门的设计工具Blend进行专业设计,同时还推出了以模板为核心的新一代设计理念。
1.1 模板的内涵
从字面上看,模板就是“具有一定规格的样板”,有了它,就可以依照它制造很多一样是实例。我们常把看起来一样的东西称为“一个模子里面刻出来的。”就是这个道理。然而,WPF中的模板的内涵远比这个深刻。
Binding和基于Binding数据驱动UI是WPF的核心部分,WPF最精彩的部分是什么呢?依我看,既不是美轮美奂的3D图形,也不是炫目多彩的动画,而是默默无闻的模板(Template)。实际上,就连2D/3D绘图也常常是为它锦上添花。
Templdate究竟有什么能力能够使得它在WPF体系中获此殊荣呢?这还要从哲学谈起,“形而上者谓之道,形而下者谓之器”,这句话出自《易经》,大意是我们能够观察到的世间万物形象之上的抽象的结果就是思维,而形象之下掩盖的就是其本质。显然,古人已经注意到“形”是连接本质和思维的枢纽,让我们把这句话引入计算机世界。
软件之道并非本书研究的主要类容,本书研究的是WPF。WPF全称Windows Presentation Foundation,Presentation一词的意思就是外观,呈现,表现,也就是说,在WIndows GUI程序这个尺度上,WPF扮演的就是“形”的角色、是程序的外在形式,而程序的内容仍然是由数据和算法构成的业务逻辑。与WPF类似,Winform和Asp.net也都是内容的表现形式。
让我们把尺度缩小到WPF内部。这个系统与程序内容(业务逻辑)的边界是Binding,Binding把数据源源不断从程序内部送出来交由界面元素来显示,又把从界面元素搜集到的数据传回程序内部。界面元素间的沟通则依靠路由事件来完成。有时候路由事件和附加事件也会参与到数据的传输中。让我们思考一个问题:WPF作为Windows的表示方式,它究竟表示的是什么?换句话说,WPF作为一种“形式”,它表现的内容到底是什么?答案是程序的数据和算法----Binding传递的是数据,事件参数携带的也是数据;方法和委托的调用是算法,事件传递消息也是算法----数据在内存里就是一串串字符或字符。算法是一组组看不见摸不着的抽象逻辑,如何恰如其分的把它们展现给用户呢?
加入想表达一个bool类型,同时还想表达用户可以在这两个值之间自由切换这样一个算法,你会怎么做?你一定会想使用一个CheckBox控件来满足要求;再比如颜色值实际上是一串数字,用户基本上不可能只看数字就能想象出真正的颜色,而且用户也不希望只靠输入字符来表示颜色值,这时,颜色值这一“数据内容”的恰当表现形式就是一个填充着真实颜色的色块。,而用户即可以输入值又可以用取色吸管取色来设置值的“算法内容”恰当的表达方式是创建一个ColorPicker控件。相信你已经发现,控件(Control)是数据内容表现形式的双重载体。换句话说,控件即是数据的表现形式让用户可以直观的看到数据,又是算法的表现形式让用户方便的操作逻辑。
作为表现形式,每个控件都是为了实现某种用户操作算法和直观显示某种数据而生,一个控件看上去是什么样子由它的“算法内容”和“数据内容决定”,这就是内容决定形式,这里,我们引入两个概念:
<DataTemplate> <Grid> <StackPanel Orientation="Horizontal"> <Grid> <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding Price}"></Rectangle> <TextBlock Text="{Binding Year}"></TextBlock> </Grid> <TextBlock Text="{Binding Price}" Margin="5,0"></TextBlock> </StackPanel> </Grid> </DataTemplate>我想,尽管你还没有学习什么DataTempldate,但借助前面学习的基础一样可以看个八九不离十了。
public class Car { public string AutoMark { get; set; } public string Name { get; set; } public string Year { get; set; } public string TopSpeed { get; set; } }
<UserControl x:Class="WpfApplication1.CarListViewItem" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid Margin="2"> <StackPanel Orientation="Horizontal"> <Image x:Name="igLogo" Grid.RowSpan="3" Width="64" Height="64"></Image> <StackPanel Margin="5,10"> <TextBlock x:Name="txtBlockName" FontSize="16" FontWeight="Bold"></TextBlock> <TextBlock x:Name="txtBlockYear" FontSize="14"></TextBlock> </StackPanel> </StackPanel> </Grid> </UserControl>
/// <summary> /// CarListViewItem.xaml 的交互逻辑 /// </summary> public partial class CarListViewItem : UserControl { public CarListViewItem() { InitializeComponent(); } private Car car; public Car Car { get { return car; } set { car = value; this.txtBlockName.Text = car.Name; this.txtBlockYear.Text = car.Year; this.igLogo.Source = new BitmapImage(new Uri(@"Resource/Image/"+car.AutoMark+".png",UriKind.Relative)); } } }类似的原理,我们需要为Car类型准备一个详细信息视图。UserControl名称为CarDetailView,XAML部分代码如下:
<UserControl x:Class="WpfApplication1.CarDetailView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6"> <StackPanel> <Image x:Name="imgPhoto" Width="400" Height="250"></Image> <StackPanel Orientation="Horizontal" Margin="5,0"> <TextBlock Text="Name:" FontSize="20" FontWeight="Bold"></TextBlock> <TextBlock x:Name="txtBlockName" FontSize="20" Margin="5,0"></TextBlock> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5,0"> <TextBlock Text="AutoMark:" FontWeight="Bold"></TextBlock> <TextBlock x:Name="txtBlockAutoMark" Margin="5,0"></TextBlock> <TextBlock Text="Year:" FontWeight="Bold"> </TextBlock> <TextBlock x:Name="txtBlockYear" Margin="5,0"> </TextBlock> <TextBlock Text="Top Speed:" FontWeight="Bold"> </TextBlock> <TextBlock x:Name="txtTopSpeed" Margin="5,0"> </TextBlock> </StackPanel> </StackPanel> </Border> </UserControl>后台支持数据大同小异:
/// <summary> /// CarDetailView.xaml 的交互逻辑 /// </summary> public partial class CarDetailView : UserControl { public CarDetailView() { InitializeComponent(); } private Car car; public Car Car { get { return car; } set { car = value; this.txtBlockName.Text = car.Name; this.txtBlockAutoMark.Text = car.AutoMark; this.txtBlockYear.Text = car.Year; this.txtTopSpeed.Text = car.TopSpeed; this.imgPhoto.Source = new BitmapImage(new Uri(@"Resource/Image/" + car.Name + ".jpg", UriKind.Relative)); } } }最后把它们组装到窗体上:
<Window x:Class="WpfApplication1.Window35" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window35" Height="350" Width="623" xmlns:my="clr-namespace:WpfApplication1"> <StackPanel Orientation="Horizontal" Margin="5"> <my:CarDetailView x:Name="carDetailView1" /> <ListBox x:Name="listBoxCars" Width="180" Margin="5,0" SelectionChanged="listBoxCars_SelectionChanged"> </ListBox> </StackPanel> </Window>窗体的后台代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace WpfApplication1 { /// <summary> /// Window35.xaml 的交互逻辑 /// </summary> public partial class Window35 : Window { public Window35() { InitializeComponent(); InitialCarList(); } private void listBoxCars_SelectionChanged(object sender, SelectionChangedEventArgs e) { CarListViewItem viewItem = e.AddedItems[0] as CarListViewItem; if(viewItem!=null) { carDetailView1.Car = viewItem.Car; } } private void InitialCarList() { List<Car> infos = new List<Car>() { new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="200", Year="1990"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="250", Year="1998"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="300", Year="2002"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="350", Year="2011"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="500", Year="2020"} }; foreach (Car item in infos) { CarListViewItem viewItem = new CarListViewItem(); viewItem.Car = item; this.listBoxCars.Items.Add(viewItem); } } } public class Car { public string AutoMark { get; set; } public string Name { get; set; } public string Year { get; set; } public string TopSpeed { get; set; } } }
//厂商名称转换为Logo路径 public class AutoMarkToLogoPathConverter:IValueConverter { /// <summary> /// 正向转 /// </summary> /// <param name="value"></param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns></returns> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return new BitmapImage(new Uri(string.Format(@"Resource/Image/{0}.png",(string)value),UriKind.Relative)); } /// <summary> /// 逆向转未用到 /// </summary> /// <param name="value"></param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns></returns> public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
//汽车名称转换为照片路径 public class NameToPhotoPathConverter:IValueConverter { /// <summary> /// 正向转 /// </summary> /// <param name="value"></param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns></returns> public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return new BitmapImage(new Uri(string.Format(@"Resource/Image/{0}.jpg", (string)value), UriKind.Relative)); } /// <summary> /// 逆向转未用到 /// </summary> /// <param name="value"></param> /// <param name="targetType"></param> /// <param name="parameter"></param> /// <param name="culture"></param> /// <returns></returns> public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
<Window x:Class="WpfApplication1.Window36" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1.Model" Title="Window36" Height="350" Width="623"> <Window.Resources> <!--Converter--> <local:AutoMarkToLogoPathConverter x:Key="amp"/> <local:NameToPhotoPathConverter x:Key="npp"/> <!--DataTemplate For DatialView--> <DataTemplate x:Key="DatialViewTemplate"> <Border BorderBrush="Black" BorderThickness="1" CornerRadius="6"> <StackPanel> <Image x:Name="imgPhoto" Width="400" Height="250" Source="{Binding AutoMark,Converter={StaticResource npp}}"></Image> <StackPanel Orientation="Horizontal" Margin="5,0"> <TextBlock Text="Name:" FontSize="20" FontWeight="Bold"></TextBlock> <TextBlock FontSize="20" Margin="5,0" Text="{Binding Name}"></TextBlock> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5,0"> <TextBlock Text="AutoMark:" FontWeight="Bold"></TextBlock> <TextBlock Margin="5,0" Text="{Binding AutoMark}"></TextBlock> <TextBlock Text="Year:" FontWeight="Bold"> </TextBlock> <TextBlock Text="{Binding Year}" Margin="5,0"> </TextBlock> <TextBlock Text="Top Speed:" FontWeight="Bold"> </TextBlock> <TextBlock Text="{Binding TopSpeed}" Margin="5,0"> </TextBlock> </StackPanel> </StackPanel> </Border> </DataTemplate> <!--Data Template For ItemView--> <DataTemplate x:Key="ItemView"> <Grid Margin="2"> <StackPanel Orientation="Horizontal"> <Image x:Name="igLogo" Grid.RowSpan="3" Width="64" Height="64" Source="{Binding Name,Converter={StaticResource amp}}"></Image> <StackPanel Margin="5,10"> <TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Bold"></TextBlock> <TextBlock Text="{Binding Year}" FontSize="14"></TextBlock> </StackPanel> </StackPanel> </Grid> </DataTemplate> </Window.Resources> <!--窗体内容--> <StackPanel Orientation="Horizontal"> <UserControl ContentTemplate="{StaticResource DatialViewTemplate}" Content="{Binding Path=SelectedItem,ElementName=lbInfos}"></UserControl> <ListBox x:Name="lbInfos" ItemTemplate="{StaticResource ItemView}"></ListBox> </StackPanel> </Window>代码对于初学者来说有点长但是结构非常简单。其中最重要的有两句:
/// <summary> /// Window36.xaml 的交互逻辑 /// </summary> public partial class Window36 : Window { public Window36() { InitializeComponent(); InitialCarList(); } private void InitialCarList() { List<Car> infos = new List<Car>() { new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="200", Year="1990"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="250", Year="1998"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="300", Year="2002"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="350", Year="2011"}, new Car(){ AutoMark="Aodi", Name="Aodi", TopSpeed="500", Year="2020"} }; this.lbInfos.ItemsSource = infos; } }运行程序,效果如下图:
<Style x:Key="RoundCornerTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/> <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Padding" Value="1"/> <Setter Property="AllowDrop" Value="true"/> <Setter Property="FocusVisualStyle" Value="{x:Null}"/> <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/> <Setter Property="Stylus.IsFlicksEnabled" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TextBox}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true" CornerRadius="5"> <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>这段代码有以下几个看点:
// // button1 // this.button1.Location = new System.Drawing.Point(1100, 199); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "报表"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // printPreviewDialog1 // this.printPreviewDialog1.AutoScrollMargin = new System.Drawing.Size(0, 0); this.printPreviewDialog1.AutoScrollMinSize = new System.Drawing.Size(0, 0); this.printPreviewDialog1.ClientSize = new System.Drawing.Size(400, 300); this.printPreviewDialog1.Enabled = true; this.printPreviewDialog1.Icon = ((System.Drawing.Icon)(resources.GetObject("printPreviewDialog1.Icon"))); this.printPreviewDialog1.Name = "printPreviewDialog1"; this.printPreviewDialog1.Visible = false;同样的逻辑如果在XAML代码里出就变成了这样:
<Style x:Key="a"> <Setter Property="pName1" Value="value"></Setter> <Setter Property="pName2" Value="value"></Setter> <Setter Property="pName3"> <Setter.Value> <!--ObjectValue--> </Setter.Value> </Setter> <Setter Property="pName4"> <Setter.Value> <!--ObjectValue--> </Setter.Value> </Setter> </Style>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WPFApplication.MainWindow" x:Name="Window" Title="MainWindow" Width="385" Height="275"> <Window.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF4D91C6" Offset="0"/> <GradientStop Color="#FFD9DBF1" Offset="1"/> </LinearGradientBrush> </Window.Background> <Grid x:Name="LayoutRoot"> <TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Margin="57,49,0,0" Width="255.487" Style="{DynamicResource RoundCornerTextBoxStyle}"/> <TextBox TextWrapping="Wrap" Text="TextBox" Margin="57,106,56.513,109.163" d:LayoutOverrides="Height" Style="{DynamicResource RoundCornerTextBoxStyle}"/> <Button Content="Button" VerticalAlignment="Bottom" Margin="149,0,145,42.163"/> </Grid> </Window>程序运行效果如下图:
<Grid x:Name="LayoutRoot" Margin="5"> <ListBox> <TextBlock>Darren</TextBlock> <TextBlock>Andy</TextBlock> <TextBlock>Jacky</TextBlock> <TextBlock>T-Soft</TextBlock> </ListBox> </Grid>
<Grid x:Name="LayoutRoot" Margin="5"> <ListBox> <!--ItemsPanel--> <ListBox.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"></StackPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel> <!--条目--> <TextBlock>Darren</TextBlock> <TextBlock>Andy</TextBlock> <TextBlock>Jacky</TextBlock> <TextBlock>T-Soft</TextBlock> </ListBox> </Grid>
<DataTemplate> <Grid> <StackPanel Orientation="Horizontal"> <Grid> <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding Price}"></Rectangle> <TextBlock Text="{Binding Year}"></TextBlock> </Grid> <TextBlock Text="{Binding Price}" Margin="5,0"></TextBlock> </StackPanel> </Grid> </DataTemplate>
<Style BasedOn="{x:Null}" TargetType="{x:Type TextBox}"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/> <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Padding" Value="1"/> <Setter Property="AllowDrop" Value="true"/> <Setter Property="FocusVisualStyle" Value="{x:Null}"/> <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/> <Setter Property="Stylus.IsFlicksEnabled" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TextBox}"> <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true" CornerRadius="5"> <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WPFApplication" xmlns:c="clr-namespace:System.Collections;assembly=mscorlib" x:Class="WPFApplication.Window3" x:Name="Window" Title="Window3" Width="288" Height="181"> <Window.Resources> <!--DataTemplate--> <DataTemplate DataType="{x:Type local:Unit}"> <Grid> <StackPanel Orientation="Horizontal"> <Grid> <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding Price}"></Rectangle> <TextBlock Text="{Binding Year}"></TextBlock> </Grid> <TextBlock Text="{Binding Year}" Margin="5,0"></TextBlock> </StackPanel> </Grid> </DataTemplate> <!--数据源--> <c:ArrayList x:Key="ds"> <local:Unit Year="2001年" Price="100"></local:Unit> <local:Unit Year="2002年" Price="120"></local:Unit> <local:Unit Year="2003年" Price="140"></local:Unit> <local:Unit Year="2004年" Price="160"></local:Unit> <local:Unit Year="2005年" Price="180"></local:Unit> <local:Unit Year="2006年" Price="200"></local:Unit> </c:ArrayList> </Window.Resources> <StackPanel> <ListBox ItemsSource="{StaticResource ds}"></ListBox> <ComboBox ItemsSource="{StaticResource ds}" Margin="5"></ComboBox> </StackPanel> </Window>
public class Unit { public string Year{get;set;} public int Price{get;set;} }
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="WPFApplication.Window4" x:Name="Window" Title="Window4" Width="314" Height="210"> <Window.Resources> <!--DataTemplate--> <DataTemplate DataType="Unit"> <Grid> <StackPanel Orientation="Horizontal"> <Grid> <Rectangle Stroke="Yellow" Fill="Orange" Width="{Binding XPath=@Price}"></Rectangle> <TextBlock Text="{Binding XPath=@Year}"></TextBlock> </Grid> <TextBlock Text="{Binding XPath=@Year}" Margin="5,0"></TextBlock> </StackPanel> </Grid> </DataTemplate> <!--数据源--> <XmlDataProvider x:Key="ds" XPath="Units/Unit"> <x:XData> <Units xmlns=""> <Unit Price="100" Year="2001"></Unit> <Unit Price="120" Year="2002"></Unit> <Unit Price="140" Year="2003"></Unit> <Unit Price="160" Year="2004"></Unit> <Unit Price="180" Year="2005"></Unit> <Unit Price="200" Year="2006"></Unit> </Units> </x:XData> </XmlDataProvider> </Window.Resources> <StackPanel> <ListBox ItemsSource="{Binding Source={StaticResource ds}}"></ListBox> <ComboBox ItemsSource="{Binding Source={StaticResource ds}}" Margin="5"></ComboBox> </StackPanel> </Window>
<?xml version="1.0" encoding="utf-8" ?> <Data xmlns=""> <Grade Name="一年级"> <Class Name="甲班"> <Group Name="A组"> </Group> <Group Name="B组"> </Group> <Group Name="C组"> </Group> </Class> <Class Name="乙班"> <Group Name="A组"> </Group> <Group Name="B组"> </Group> <Group Name="C组"> </Group> </Class> </Grade> <Grade Name="二年级"> <Class Name="甲班"> <Group Name="A组"> </Group> <Group Name="B组"> </Group> <Group Name="C组"> </Group> </Class> <Class Name="乙班"> <Group Name="A组"> </Group> <Group Name="B组"> </Group> <Group Name="C组"> </Group> </Class> </Grade> </Data>
<Window x:Class="WPFApplication.Window6" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window6" Height="268" Width="362"> <Window.Resources> <!--数据源--> <XmlDataProvider x:Key="ds" Source="XMLStudent.xml" XPath="Data/Grade"></XmlDataProvider> <!--年级模板--> <HierarchicalDataTemplate DataType="Grade" ItemsSource="{Binding XPath=Class}"> <TextBlock Text="{Binding XPath=@Name}"></TextBlock> </HierarchicalDataTemplate> <!--班级模板--> <HierarchicalDataTemplate DataType="Class" ItemsSource="{Binding XPath=Group}"> <RadioButton Content="{Binding XPath=@Name}" GroupName="gn"></RadioButton> </HierarchicalDataTemplate> <!--小组模板--> <HierarchicalDataTemplate DataType="Group" ItemsSource="{Binding XPath=Student}"> <CheckBox Content="{Binding XPath=@Name}"></CheckBox> </HierarchicalDataTemplate> </Window.Resources> <Grid> <TreeView Margin="5" ItemsSource="{Binding Source={StaticResource ds}}"> </TreeView> </Grid> </Window>
<?xml version="1.0" encoding="utf-8" ?> <Data xmlns=""> <Operation Name="文件" Gesture="F"> <Operation Name="新建" Gesture="N"> <Operation Name="项目" Gesture="Ctr+P"/> <Operation Name="网站" Gesture="Ctr+W"/> <Operation Name="文档" Gesture="Ctr+D"/> </Operation> <Operation Name="保存" Gesture="S"/> <Operation Name="打印" Gesture="P"/> <Operation Name="退出" Gesture="X"/> </Operation> <Operation Name="编辑" Gesture="E"> <Operation Name="剪切" Gesture="Ctr+X"/> <Operation Name="复制" Gesture="Ctr+C"/> <Operation Name="粘贴" Gesture="Ctr+V"/> </Operation> </Data>程序XAML代码如下:
<Window x:Class="WPFApplication.Window7" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window7" Height="300" Width="300"> <Window.Resources> <!--数据源--> <XmlDataProvider x:Key="ds" Source="MenuXML.xml" XPath="Data/Operation"></XmlDataProvider> <!--Operation模板--> <HierarchicalDataTemplate DataType="Operation" ItemsSource="{Binding XPath=Operation}" > <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding XPath=@Name}" Margin="10,0"></TextBlock> <TextBlock Text="{Binding XPath=@Gesture}"></TextBlock> </StackPanel> </HierarchicalDataTemplate> </Window.Resources> <StackPanel> <Menu ItemsSource="{Binding Source={StaticResource ds}}"></Menu> </StackPanel> </Window>
<StackPanel MenuItem.Click="StackPanel_Click"> <Menu ItemsSource="{Binding Source={StaticResource ds}}"></Menu> </StackPanel>
private void StackPanel_Click(object sender, RoutedEventArgs e) { MenuItem item = e.OriginalSource as MenuItem; XmlElement xe = item.Header as XmlElement; MessageBox.Show(xe.Attributes["Name"].Value); }
<Window x:Class="WPFApplication.Window8" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window8" Height="300" Width="300"> <Window.Resources> <ControlTemplate x:Key="xtTemp"> <StackPanel Background="Orange"> <TextBox Margin="6" x:Name="textbox1"></TextBox> <TextBox Margin="6,0" x:Name="textbox2"></TextBox> <TextBox Margin="6" x:Name="textbox3"></TextBox> </StackPanel> </ControlTemplate> </Window.Resources> <StackPanel Background="Yellow"> <UserControl x:Name="uc" Template="{StaticResource xtTemp}" Margin="5"></UserControl> <Button Content="Find By Name" Width="120" Height="30" Click="Button_Click"></Button> </StackPanel> </Window>
private void Button_Click(object sender, RoutedEventArgs e) { 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 ControlTemplate"; (sp.Children[2] as TextBox).Text = "I Can Find YOU."; }
public class Student38 { public int Id { get; set; } public string Name { get; set; } public string Skill { get; set; } public bool HasJob { get; set; } }
<Window x:Class="WpfApplication1.Window38" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="Window38" Height="227" Width="269"> <Window.Resources> <!--数据对象--> <local:Student38 x:Key="stu" Id="1" Skill="WPF" Name="Timothy" HasJob="True"></local:Student38> <!--DataTemplate--> <DataTemplate x:Key="dtStu"> <Border BorderBrush="Orange" BorderThickness="2" CornerRadius="5"> <StackPanel> <TextBlock Text="{Binding Id}" Margin="5"></TextBlock> <TextBlock x:Name="txtBlockName" Text="{Binding Name}" Margin="5"></TextBlock> <TextBlock Text="{Binding Skill}" Margin="5"></TextBlock> </StackPanel> </Border> </DataTemplate> </Window.Resources> <!--主窗体布局--> <StackPanel> <ContentPresenter x:Name="cp" Content="{StaticResource stu}" ContentTemplate="{StaticResource dtStu}" Margin="5"> </ContentPresenter> <Button Content="Find" Margin="5,0" Click="Button_Click"> </Button> </StackPanel> </Window>
private void Button_Click(object sender, RoutedEventArgs e) { TextBlock tb = this.cp.ContentTemplate.FindName("txtBlockName", this.cp) as TextBlock; MessageBox.Show(tb.Text); //Student38 stu = this.cp.Content as Student38; //MessageBox.Show(stu.Name); }
public class Student39 { public int Id { get; set; } public string Name { get; set; } public string Skill { get; set; } public bool HasJob { get; set; } }
<Window x:Class="WpfApplication1.Window39" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:System.Collections;assembly=mscorlib" xmlns:local="clr-namespace:WpfApplication1" Title="Window39" Height="338" Width="446"> <Window.Resources> <!--数据集合--> <c:ArrayList x:Key="stuList"> <local:Student39 Id="1" Name="Timoty Liu" Skill="WPF" HasJob="True"></local:Student39> <local:Student39 Id="2" Name="Tom Chang" Skill="BI/SQL" HasJob="True"></local:Student39> <local:Student39 Id="3" Name="Guan Chong" Skill="Writing" HasJob="False"></local:Student39> <local:Student39 Id="4" Name="Shanshan" Skill="C#/Java" HasJob="False"></local:Student39> <local:Student39 Id="5" Name="Pingping Zhang" Skill="Writing" HasJob="False"></local:Student39> <local:Student39 Id="6" Name="kenny Tian" Skill="Asp.net" HasJob="False"></local:Student39> </c:ArrayList> <!--DataTemplate--> <DataTemplate x:Key="nameDT"> <TextBox x:Name="txtBoxName" Text="{Binding Name}"></TextBox> </DataTemplate> <DataTemplate x:Key="skillDT"> <TextBox x:Name="txtSkill" Text="{Binding Skill}"></TextBox> </DataTemplate> <DataTemplate x:Key="hasJobDT"> <CheckBox IsChecked="{Binding HasJob}"></CheckBox> </DataTemplate> </Window.Resources> <Grid Margin="5"> <ListView x:Name="lvStudent" ItemsSource="{StaticResource stuList}"> <ListView.View> <GridView> <GridViewColumn Header="ID" DisplayMemberBinding="{Binding Id}"></GridViewColumn> <GridViewColumn Header="姓名" CellTemplate="{StaticResource nameDT}"></GridViewColumn> <GridViewColumn Header="技术" CellTemplate="{StaticResource skillDT}"></GridViewColumn> <GridViewColumn Header="已工作" CellTemplate="{StaticResource hasJobDT}"></GridViewColumn> </GridView> </ListView.View> </ListView> </Grid> </Window>程序运行效果如下图:
<DataTemplate x:Key="nameDT"> <TextBox x:Name="txtBoxName" Text="{Binding Name}" GotFocus="txtBoxName_GotFocus"></TextBox> </DataTemplate>因为我们是在DataTemplate里面添加了事件处理器,所以界面上任何一个由此DataTemplate生成的TextBox都会在获得焦点的时候调用txtBoxName_GotFocus这个事件处理器。txtBoxName_GotFocus的代码如下:
private void txtBoxName_GotFocus(object sender, RoutedEventArgs e) { TextBox tb = e.OriginalSource as TextBox; //获取事件发起的源头 ContentPresenter cp = tb.TemplatedParent as ContentPresenter;//获取模板目标 Student39 stu = cp.Content as Student39;//获取业务逻辑数据 this.lvStudent.SelectedItem = stu;//设置ListView选中项 //访问界面元素 ListViewItem lvi = this.lvStudent.ItemContainerGenerator.ContainerFromItem(stu) as ListViewItem; CheckBox cb = this.FindVisualChild<CheckBox>(lvi); MessageBox.Show(cb.Name); } private ChildType FindVisualChild<ChildType>(DependencyObject obj) 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<ChildType>(child); if(childOfChild!=null) { return childOfChild; } } } return null; } }
<Window x:Class="WpfApplication1.Window40" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window40" Height="310" Width="426"> <Window.Resources> <Style TargetType="TextBlock"> <Setter Property="FontSize" Value="24"></Setter> <Setter Property="TextDecorations" Value="Underline"></Setter> <Setter Property="FontStyle" Value="Italic"></Setter> </Style> </Window.Resources> <StackPanel Margin="5"> <TextBlock Text="Hello WPF!"></TextBlock> <TextBlock Text="This is a sample for style!"></TextBlock> <TextBlock Text="by Time 2012-11-12!" Style="{x:Null}"></TextBlock> </StackPanel> </Window>
<Window x:Class="WpfApplication1.Window41" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window41" Height="258" Width="352"> <Window.Resources> <Style TargetType="CheckBox"> <Style.Triggers> <Trigger Property="IsChecked" Value="True"> <Trigger.Setters> <Setter Property="FontSize" Value="20"></Setter> <Setter Property="Foreground" Value="Orange"></Setter> </Trigger.Setters> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Window.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF4589D8" Offset="0" /> <GradientStop Color="White" Offset="1" /> </LinearGradientBrush> </Window.Background> <StackPanel> <CheckBox Content="锄禾日当午" Margin="5"></CheckBox> <CheckBox Content="汗滴禾下土" Margin="5,0"></CheckBox> <CheckBox Content="谁知盘中餐" Margin="5"></CheckBox> <CheckBox Content="粒粒皆辛苦" Margin="5,0"></CheckBox> </StackPanel> </Window>
<Style TargetType="CheckBox"> <Style.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsChecked" Value="True"></Condition> <Condition Property="Content" Value="粒粒皆辛苦"></Condition> </MultiTrigger.Conditions> <MultiTrigger.Setters> <Setter Property="FontSize" Value="20"></Setter> <Setter Property="Foreground" Value="Orange"></Setter> </MultiTrigger.Setters> </MultiTrigger> </Style.Triggers> </Style>运行效果如下图:
<Window x:Class="WpfApplication1.Window42" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="Window42" Height="184" Width="324"> <Window.Resources> <local:L2BConverter x:Key="cbtr"></local:L2BConverter> <Style TargetType="TextBox"> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self},Path=Text.Length,Converter={StaticResource cbtr}}" Value="false"> <Setter Property="BorderBrush" Value="Red"></Setter> <Setter Property="BorderThickness" Value="1"></Setter> </DataTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <TextBox Margin="5"></TextBox> <TextBox Margin="5,0"></TextBox> <TextBox Margin="5"></TextBox> </StackPanel> </Window>
public class L2BConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int textLength = (int)value; return textLength > 6 ? true : false; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
<Window x:Class="WpfApplication1.Window43" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window43" Height="262" Width="425"> <Window.Resources> <Style TargetType="ListBoxItem"> <!--使用Style设置Datatemplate--> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Id}" Width="60"></TextBlock> <TextBlock Text="{Binding Name}" Width="120"></TextBlock> <TextBlock Text="{Binding Skill}" Width="60"></TextBlock> </StackPanel> </DataTemplate> </Setter.Value> </Setter> <!--MultiDataTrigger--> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=Id}" Value="2"></Condition> <Condition Binding="{Binding Path=Name}" Value="Darren"></Condition> </MultiDataTrigger.Conditions> <MultiDataTrigger.Setters> <Setter Property="Background" Value="Orange"></Setter> </MultiDataTrigger.Setters> </MultiDataTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <ListBox x:Name="lbInfos" Margin="5"></ListBox> </StackPanel> </Window>后台代码如下:
public Window43() { InitializeComponent(); InitialInfo(); } private void InitialInfo() { List<Student38> infos = new List<Student38>() { new Student38(){ Id=2, Name="Darren", Skill="WPF"}, new Student38(){ Id=1, Name="Tom", Skill="Java"}, new Student38(){ Id=3, Name="Jacky", Skill="Asp.net"}, new Student38(){ Id=2, Name="Andy", Skill="C#"}, }; this.lbInfos.ItemsSource = infos; }
<Window x:Class="WpfApplication1.Window44" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window44" Height="258" Width="377"> <Window.Resources> <Style TargetType="Button"> <Style.Triggers> <!--鼠标进入--> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Width"></DoubleAnimation> <DoubleAnimation To="150" Duration="0:0:0.2" Storyboard.TargetProperty="Height"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> <!--鼠标离开--> <EventTrigger RoutedEvent="MouseLeave"> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Width"></DoubleAnimation> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height"></DoubleAnimation> </Storyboard> </BeginStoryboard> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <Button Width="40" Height="40" Content="OK"></Button> </Grid> </Window>