PS:
1、XAML文件的根对象元素必须指定至少一个XML命名空间,用于验证自己和子元素。你可以(在根元素或子元素上)声明额外的XML命名空间,但每一个命名空间下的标识符都 必须有一个唯一的前缀,例如,WPF的XAML文件都会使用第二个命名空间加上前缀x(记作xmlns:x而不仅仅是xmlns):
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
2、类型+命名空间+属性
3、属性示例:
属性元素语法:
- <Window x:Class="Wpftest.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">
- <Grid>
- <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
- <Button.Content>
- <Rectangle Height="40" Width="40" Fill="Black"/>
- </Button.Content>
- </Button>
- </Grid>
- </Window>
- <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
- <Button.Content>
- OK
- </Button.Content>
- <Button.Background>
- yellow
- </Button.Background>
- </Button>
4、类型转换器
WPF提供了许多常用数据类型的类型转换器,如Brush、Color、FontWeight、Point等,它们都是派生自TypeConverter的类(如
BrushConverter、ColorConverter等),你也可以为自定义的数据类型写类型转换器。与XAML语言不同,类型转换器通常支持不区分大小写的字符串。
如果没有Brush类型转换器,你就必须使用属性元素语法来设置XAML中的Background属性,如下所示:
- <Button xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Content="OK">
- <Button.Background>
- <SolidColorBrush>
- <SolidColorBrush.Color>
- <Color A="255" R="255" G="255" B="255"/>
- </SolidColorBrush.Color>
- </SolidColorBrush>
- <SolidColorBrush Color="White"/>
- </Button.Background>
- </Button>
5、标记扩展
只要特性值由花括号({})括起来,XAML编译器或解析器就会把它认作一个标记扩展值而不是一个普通的字符串(或其他一些需要进行类型转换的东西)
下面的按钮使用了3个不同的标记扩展类型,其中分别用到了3个不同的特性:
属性元素语法的表达形式:
- <Button xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns: x="http://schemas.microsoft.com/winfx/2006/xaml"
- Background="{x:Null}"
- Height="{x:Static SystemParameters.IconHeight}"
- Content="{Binding Path=Height, RelativeSource={RelativeSource Self}}"/>
- <Button xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- <Button.Background>
- <x:Null/>
- </Button.Background>
- <Button.Height>
- <x:Static Member="SystemParameters.IconHeight" />
- </Button.Height>
- <Button.Content>
- <Binding Path="Height">
- <Binding.RelativeSource>
- <RelativeSource Mode="Self"/>
- </Binding.RelativeSource>
- </Binding>
- </Button.Content>
- </Button>
每个花括号中的第一个识别符是标记扩展类的名称。按照惯例,这样的类都以Extension后缀结尾,但是当你在XAML中使用它时,可以不用该后缀。在这个例子中,NullExtension(我们看到的是x:Null)和StaticExtension(我们看到的是x:Static)是System.Windows.Markup命名空间的类, 因此必须使用前缀x来定位它们。Binding( 没有Extension后缀) 是在System.Windows.Data命名空间下的,因此在默认的XML命名空间下就可以找到它。
***如果你曾经需要设置一个属性特性值为字面值字符串(以左花括号开始),就必须摆脱它以免把它作为标记扩展。我们可以通过在其之前增加一对空花括号来实现。例如:
如在上例中,将Content改为 Content="{}{This is not a markup extension}"或者用属性元素语法
6、XAML扩展类型(对象元素的子元素)
WPF 程序集都被加上了XmlnsDefinitionAttribute属性,这样可以将.NET命名空间映射为XAML文件中的XML命名空间。
为了处理那些不是专门为XAML设计的程序集的类型,需要使用一个特殊的指令作为XML命名空间,例:
clr-namespace标记允许直接在XAML中放入一个.NET命名空间。仅当需要的类型不在相同的程序集(XAML编译后生成的)中时,最后的程序集规范才是必须的。一般使用程序集的简单名称(如mscorlib)。但你可以使用规范的呈现方式,它是由System.Reflection.Assembly.Load提供支持的(虽然不允许空格),该函数包含了额外的信息,如版本或公共密钥令牌。
- <collections:Hashtable
- xmlns:collections="clr-namespace:System.Collections;assembly=mscorLib"
- xmlns:sys="clr-namespace:System;assembly=mscorLib"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- <sys:Int32 x:Key="key1">7</sys:Int32>
- <sys:Int32 x:Key="key2">23</sys:Int32>
- </collections:Hashtable>
这个例子有两个关键点强调了不仅与.NET类型系统进行整合,也要与.NET Framework基类库中的特定类型进行整合。
子元素可以使用标准的XAML x:Key语法添加到父Hashtable中,因为Hashtable和.NETFramework中的其他集合类从1.0版本开始就实现了IDictionary接口。
之所以可以这么直接使用System.Int32,是因为类型转换器已经存在,且类型转换器是支持将字符串转换为整型的。因为XAML支持的类型转换器都是派生自System.ComponentModel.TypeConverter的类,这个类从.NET Framework 1.0开始就有了。这其实也是Windows Forms使用的类型转换机制(例如,允许在Visual Studio的属性格中输入字符串,并将它们转换为适当的类型)。
规则:
(1) 如果该类型实现了IList接口,就为每个子元素调用IList.Add。
(2) 否则,如果该类型实现了IDictionary,就为每个子元素调用IDictionary.Add,在该值的键和元素中使用x:Key特性值。
(3) 否则,如果父元素支持内容属性(由System.Windows.Markup.ContentPropertyAttribute表示),而且子元素的类型与该内容属性是兼容的,就把子元素作为它的值。
(4) 否则,如果子对象是普通文本,且有类型转换器将子对象转换为父类型(没有在父元素上设置属性),则把子元素作为类型转换器的输入,将输出作为父对象的实例。
(5) 其他情况下,则抛出一个错误。
可以通过类的方式来添加XAML成员:
注意 不要忘记在代码隐藏类的构造函数中调用InitializeComponent!
如果你忘记了,那么根元素将不会包含你在XAML中定义的任何内容(因为对应的BAML没有被加载),任何表示已命名对象元素的成员都将变成null。
二。 XAML关键字
- <pre name="code" class="html"><Window x:Class="Wpftest.MyWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- ……
- </Window></pre><br>
- <pre></pre>
- <p></p>
- <pre></pre>
- 在同一个项目中创建一个独立的源文件,添加自己想添加的成员
- <p></p>
- <p></p>
- <pre name="code" class="html">namespace Wpftest
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MyWindow : Window
- {
- public MyWindow()
- {
- InitializeComponent();
- }
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- }
- <span style="white-space:pre"> </span>Any other members can go here....
- }
- }</pre>通常我们把这样的文件叫作代码隐藏文件。如果你引用XAML中的任何一个事件处理程序(通过事件特性,如Button的Click特性),这里就是我们定义这些事件处理程序的地方。<br>
- <br>
- 如果你使用的.NET语言无法支持部分类(如C++/CLI和J#),XAML文件就必须在根元素中定义一个Subclass关键字,如下所示:
- <p></p>
- <p></p>
- <pre name="code" class="html"><Window x:Class="Wpftest.MyWindow" x:Subclass="Wpftest.MyWindow2"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- ……
- </Window></pre><br>
- 改完后,这个XAML文件就完整定义了一个Subclass(本例中是MyWindow2),但是在代码隐藏文件中要把这个类(MyWindow)作为MyWindow2的基类。这样,我们依靠继承模拟了把代码分散在两个文件中的能力。<br>
- <p><br>
- </p>
- <p>当在Visual Studio中创建一个基于WPF的C#或者Visual Basic项目,或者当使用“Add New Item…”来添加某个WPF项目时,Visual Studio会自动创建一个XAML文件,并把x:Class作为根元素,同时创建一个具有部分类定义的代码隐藏源文件,最后把两者连接起来,这样代码构建(build)才能顺利进行。</p>
- <pre name="code" class="html"><pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre>
XAML语言命名空间中的关键字,采用习惯性的x作为命名空间的前缀 关 键 字 何处有效 含义/描述 x:Class 根元素的特性 为根元素定义一个派生自元素类型的类,可以在前面加上.NET命名空间作为前缀(可选) x:ClassModifier 根元素的特性,必须与x:Class一起使用 定义由x:Class指定的类的可见性(该类默认是可见的)。该特性值必须根据使用的过程
语言指定(如,C#中的public或internal)x:Code XAML中任何位置的元素,但是必须与x:Class一起使用 嵌入过程式代码,会被插入由x:Class指定的类中 x:FieldModifier 非 根元素上的特性, 但必须与
x:Name(或者等效关键字)一起使用定义生成的元素(默认是内部元素)字段的可见性,与x:ClassModifier一样,该值必须根据过程语言来指定。(如C#中的public、private等) x:Key 父元素实现了IDictionary的元素的特性 当被添加到父元素的字典里时,请为该项指定键名 x:Name 非根元素上的特性, 但必须与x:Class一起使用 为给元素生成的字段选择一个名称,这样它就可以在过程式代码中被引用 x:Shared Resource-Dictionary对象中的元素特性,但只有在XAML编译后才可使用 可以被设置为false来避免在多个地方共享同资源实例 x:Subclass 根元素的特性,必须与x:Class一起使用 为保存XAML内容的x:Class类指定一个子类,可以用.NET命名空间作为可选前缀
(用于那些没有提供部分类支持的语言)x:TypeArguments 根元素的特性,必须与x:Class一起使用 使根类成为泛型(如List<T>)且带指定的范型参数实例(如List<Int32>或List<String>),可以设置一个用逗号分割的泛型参数代码清单,如果某类型不在默认的命名空间里,需要加上XML命名空间前缀 x:Uid 元素的特性 为元素添加一个本地化ID x:XData 用于某个IXmlSerializable类型属性的值的元素 对XAML解析器透明的任一个XML数据岛
三、依赖属性和附加属性示例
XAML语言命名空间中的标记扩展,采用习惯性的x作为命名空间的前缀 扩 展 含 义 x:Array 代表一个.NET数组。x:Array元素的子元素都是数组元素。它必须与x:Type一起使用,用于定义数组类型 x:Null 表示一个空引用 x:Static 引用在过程式代码中定义的任何一个静态的属性、常量或枚举值。在XAML编译后,这也可以是同一个程序集中的一个非公共成员。如果在默认的命名空间中没有该类型,Member字符串必须有XML命名空间前缀 x:Type 表示System.Type的一个实例,就像C#中的typeof操作符。如果在默认的命名空间中没有该类型,TypeName字符串必须有XML命名空间前缀
- public class Button : ButtonBase
- {
- // 依赖属性
- public static readonly DependencyProperty IsDefaultProperty;
- static Button()
- {
- // 注册属性
- Button.IsDefaultProperty = DependencyProperty.Register("IsDefault",
- typeof(bool), typeof(Button),
- new FrameworkPropertyMetadata(false,
- new PropertyChangedCallback(OnIsDefaultChanged)));
- ……
- }
- // .net属性包装器(可选)
- public bool IsDefalut
- {
- get { return (bool)GetValue(Button.IsDefaultProperty); }
- set { SetValue(Button.IsDefaultProperty, value); }
- }
- // 属性改变的回调(可选)
- private static void OnIsDefaultChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
- {
- ……
- }
- }
IsDefaultProperty静态成员是真正的依赖属性,类型为System.Windows.DependencyProperty。按规则,所有的DependencyProperty成员都必须是public、static,并且有一个Property作为后缀。依赖属性通常是通过调用DependencyProperty.Register静态方法创建的,这样的方法需要一个名称(IsDefault)、一个属性类型(bool)以及拥有这个属性的类(Button类)。。通过不同的Register方法重载,你可以传入metadata(元数据)来告诉WPF如何处理该属性、如何处理属性值改变的回调、如何处理强制值转,以及如何验证值。Button会在它的静态构造函数中调用Register的重载,给依赖属性一个默认值false,并为变更通知添加一个委托。
最后,那个叫作IsDefault的传统.NET属性会调用继承自System.Windows.Dependency-Object的GetValue和SetValue方法来实现自己的访问器,System.Windows.DependencyObject是底层基类,这是拥有依赖属性的类必须继承的。GetValue返回最后一次由SetValue设置的值,如果SetValue从未被调用过,那么就是该属性注册时的默认值。IsDefault .NET属性(有时叫作此上下文中的属性包装器)并不是必需的,Button的使用者可能会直接调用GetValue/ SetValue方法,因为它们是公开的。但是.NET属性会让以编程方式读写属性变得更加自然,它还允许通过XAML设置属性。
附加属性:
附加属性能够启用一些我们所盼望的属性值(被添加的元素并没有该属性值)继承特性,是依赖属性的一种特殊形式,可以被有效地添加到任何对象中。
四、属性触发器
无论何时,只要依赖属性的值改变了,WPF就会自动根据属性的元数据(metadata)触发一系列动作。这些动作可以重新呈现适当的元素、更新当前布局、刷新数据绑定等。内建的变更通知最有趣的特性之一是属性触发器,它可以在属性值改变时执行自定义动作,而不用更改任何过程式代码。
例:为一个按钮设置属性:在鼠标指针移上去时按钮上的字变为蓝色。
五、路由事件如果没有属性触发器的话,你得为每个Button添加两个事件处理程序,一个是为MouseEvent事件准备的,一个是为MouseLeave事件准备的。
在相应的隐藏代码中添加如下事件处理:
- <Button MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave" MinWidth="75" Margin="10">Help</Button>
- // 当鼠标进入按钮区域时,改变foreground为蓝色
- void Button_MouseEnter(object sender, MouseEventArgs e)
- {
- Button b = sender as Button;
- if (b != null)
- {
- b.Foreground = Brushes.Blue;
- }
- }
- // 当鼠标离开按钮区域时,恢复foreground为黑色
- void Button_MouseLeave(object sender, MouseEventArgs e)
- {
- Button b = sender as Button;
- if (b != null)
- {
- b.Foreground = Brushes.Black;
- }
- }
然而,有了属性触发器,你可以完全在XAML中完成相同的行为。下面Trigger对象就是需要写的所有代码:(红色部位为将该该属性触发器通过style对象应用到Button上去)
- <pre name="code" class="html"><Button MinWidth="75" Margin="10">
- Help
- <Button.Style>
- <Style TargetType="{x:Type Button}">
- <Style.Triggers>
- <Trigger Property="IsMouseOver" Value="True">
- <Setter Property="Foreground" Value="Blue"/>
- </Trigger>
- </Style.Triggers>
- </Style>
- </Button.Style>
- </Button></pre>
- <pre></pre>
- 这个触发器能够基于Button的IsMouseOver属性工作,当MouseEnter触发时,IsMouseOver属性会变为true;在MouseLeave触发时,它又变为false。注意,当IsMouseOver变为false时,不用把Foregound变为黑色,这是WPF自动完成的!<br>
- <p></p>
路由事件是由公共的静态RoutedEvent成员加上一个约定的Event后缀名构成的。路由事件的注册:它会定义一个普通的.NET事件或者一个事件包装器(event wrapper),这样可以保证在过程式代码中使用起来更加熟悉,并且可以在XAML中用事件特性语法(event attribute syntax)添加一个事件处理程序。事件包装器在访问器中只能调用AddHandler和RemoveHandler,而不应该做其他事情。
路由策略(优先级递减):
所谓路由策略就是事件触发遍历整棵元素树的方式,这些策略由RoutingStrategy枚举值提供。
1、Tunneling(管道传递)——事件首先在根元素上被触发,然后从每一个元素向下沿着树传递,直到到达源元素为止(或者直到处理程序把事件标记为已处理为止。它们的名字中都有一个Preview前缀。例如,PreviewMouseMove
2、Bubbling(冒泡)——事件首先在源元素上被触发,然后从每一个元素向上沿着树传递,直到到达根元素为止(或者直到处理程序把事件标记为已处理为止)。
3、Direct(直接)——事件仅在源元素上触发。这与普通.NET事件的行为相同,不同的是这样的事件仍然会参与一些路由事件的特定机制,如事件触发器。
事件处理程序:
路由事件的事件处理程序有一个签名,它与通用.NET事件处理程序的模式匹配:第一个参数是一个System.Object对象,名为sender,第二个参数(一般命名为e)是一个派生自System.EventArgs的类。传递给事件处理程序的sender参数就是该处理程序被添加到的元素。参数e是RoutedEventArgs的一个实例(或者派生自RoutedEventArgs),RoutedEventArgs是EventArgs的一个子类,它提供了4个有用的属性:
1、Source——逻辑树中一开始触发该事件的元素。
2、OriginalSource——可视树中一开始触发该事件的元素(例如,TextBlock或者标准Button元素的ButtonChrome子元素)。
3、Handled——布尔值,设置为true表示标记事件为已处理,这就是用于停止Tunneling或Bubbling的标记。
4、RoutedEvent——真正的路由事件对象(如Button.ClickEvent),当一个事件处理程序同时被用于多个路由事件时,它可以有效地识别被触发的事件。
例:
- <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- Title="About WPF Unleashed" SizeToContent="WidthAndHeight"
- Background="OrangeRed"
- x:Class="AboutDialog" MouseRightButtonDown="AboutDialog_MouseRightButtonDown">
在Window根元素上添加了一个事件处理程序AboutDialog_MouseRightButtonDown,对应代码:
- void AboutDialog_MouseRightButtonDown(object sender, MouseEventArgs e)
- {
- // 显示这个事件的信息
- this.Title = "Source = " + e.Source.GetType().Name + ", OriginalSource = " +
- e.OriginalSource.GetType().Name + " @ " + e.Timestamp;
- // 该示例中,所有可能从Control派生而来的源
- Control source = e.Source as Control;
- // 调整源控件的边框宽度
- if (source.BorderThickness != new Thickness(2))
- {
- source.BorderThickness = new Thickness(2);
- source.BorderBrush = Brushes.Yellow;
- }
- else
- {
- source.BorderThickness = new Thickness(0);
- }
- }
每当鼠标右击产生一个冒泡事件传递给Window,AboutDialog_MouseRightButtonDown事件处理程序会执行两个动作:首先它会把事件的信息打印到Window的标题栏
中,然后会在逻辑树中的被右击的这个元素周围添加(最终会移除)一个较厚的黑边框
六、命令
命令特性:
1、WPF定义了许多内建命令
2、命令自动支持输入手势(input gesture),如键盘快捷方式
3、有些WPF控件有一些与不同命令关联的内建行为
1、内建命令:
命令是任何一个实现了ICommand接口(位于System.Windows.Input命名空间)的对象,每个对象定义了3个简单的成员:
1、Execute——执行特定命令的逻辑的方法。
2、CanExecute——如果命令允许被执行,则该方法返回true;如果不允许执行,则返回false。
3、CanExecuteChanged——无论何时,只要CanExecute的值改变,该事件就会触发。
七、
WPF核心类
这10个类有以下一些显著的特点:
1、Object类——所有.NET类的基类。
2、DispatcherObject类——只能在创建它的线程上访问的对象的基类。大多数WPF类派生自DispatcherObject,因此都继承了非线程安全特性。这里名字中的Dispatcher是指WPF中类似Win32的消息循环的东西。
3、DependencyObject类——支持依赖属性的任何一个对象的基类。DependencyObject定义了GetValue和SetValue方法,是依赖属性运作的中心方块。
4、Freezable类——出于性能原因,可以被“冻结”为一个只读状态对象的基类。一旦被冻结,Freezable对象可以在多个线程中安全共享,这与其他DispatcherObject对象是不同的。冻结的对象就不能被解冻,但是可以复制这些冻结对象来创建一个非冻结的副本。
5、Visual类——拥有自己的可视呈现的对象的基类。
6、UIElement类——支持路由事件、命令绑定、布局和焦点的可视对象的基类。
7、ContentElement类——类似于UIElement的基类,但是它是为那些没有呈现行为的内容准备的。ContentElement寄宿于派生自Visual的类中,然后呈现在屏幕上。
8、FrameworkElement类——支持样式、数据绑定、资源和一些通用机制的Windows控件的基类,如tooltips(工具提示)和context menus(上下文菜单)。
9、FrameworkContentElement类——类似于FrameworkElement的类,用于表示内容。
10、Control类——一些耳熟能详的控件的基类,如Button、ListBox和StatusBar.Control类,在FrameworkElement基类的基础上添加了很多属性,例如Foreground、Background和FontSize。Controls也支持一些模板,可以完全替代它们的可视树。
八、基础控件
WPF 控件
§按钮:Button 和 RepeatButton 。§对话框: OpenFileDialog 、 PrintDialog和 SaveFileDialog。§数字墨迹: SaveFileDialog和 InkPresenter。§文档:DocumentViewer、FlowDocumentPageViewer、FlowDocumentReader、FlowDocumentScrollViewer 和 StickyNoteControl。§输入:TextBox、RichTextBox 和 PasswordBox。§布局:Border、BulletDecorator、Canvas、DockPanel、Expander、Grid、GridView、GridSplitter、GroupBox、Panel、ResizeGrip、Separator、ScrollBar、ScrollViewer、StackPanel、Thumb、Viewbox、VirtualizingStackPanel、Window 和 WrapPanel。§媒体:Image、MediaElement 和 SoundPlayerAction。§菜单:ContextMenu、Menu 和 ToolBar。§导航:Frame、Hyperlink、Page、NavigationWindow 和 TabControl。§选择:CheckBox、ComboBox、ListBox、TreeView、RadioButton 和 Slider。§用户信息:AccessText、Label、Popup、ProgressBar、StatusBar、TextBlock 和 ToolTip。§自定义控件:UserControl
1、内容控件:
内容控件是只允许包含单一项(item)的简单控件。内容控件都继承自System.Windows.Controls.ContentControl,它们拥有只含有一项的Object 类型的Content 属性。
主要类型:按钮、简单容器、带头的容器
2、Items控件:
Items 控件包含了一个拥有许多Item 的集合而不是只是一条内容。所有的Items 控件都是继承自ItemsControl抽象类的,它们是Control类的直系子类。
每个Item 可以是任意类型的对象,它会以在内容控件中一样的方式被渲染。
由于Items 是一个内容属性,所以子元素将被隐式地添加到Items 集合中。
Control 有一个ItemsSource 属性,通过它可以把一个任意类型的集合赋给Items 集合。
HasItems——它是一个只读的Boolean 属性,它使那些在XAML 中声明的出于空状态的控件操作上变得简单。从C#中,你可以使用这个属性或者检查一下Items.Count 值。
IsGrouping——它是另一个只读的Boolean 属性,它告诉你控件的Items 是否被分为顶层组(top-levelgroup)。该分组直接在ItemCollection 中完成,ItemsCollection 类包含几个用来管理和命名Items 组的属性。
DisplayMemberPath——它是一个字符串属性,可以把它设置为每一个项上 (或者更复杂的表达式)的一个属性的名字,这样会改变每一个对象被渲染的方式。
主要类型:选择器、菜单、其他所有控件
3、Range控件
4、文本和墨水控件
九、按钮
- Cancel 被设置成了True,你点击了那个按钮,这个对话框会自动关闭。如果Button.IsDefault 被设置成了true,除非焦点不在这个按钮上,否则按回车就会触发这个按钮的Click 事件。
- IsDefault 属性是一种可读写属性,可以决定按钮是否应该是默认的。
- IsDefaulted是只读属性,表示按钮的某一状态,比如按回车键会使它处于点击状态。
- 以编程方式来点击一个按钮:有一个属于System.Windows.Automation.Peers 命名空间的peer 类来支持
UI Automat ion:ButtonAutomat ionPeer。实现代码如下:
- ButtonAutomationPeer bap = new ButtonAutomationPeer(mybutton);
- IInvokeProvider iip = bap.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
- iip.Invoke(); // 点击该按钮
2、RepeatButton
- RepeatButton 的行为基本和Button 一样,除了它会在按钮一直被按着的情况下触发点击事件(它没有Button 的取消和默认这两种行为,因为它直接继承自ButtonBase)。
- 产生点击事件的频率主要由RepeatButton的Delay 以及Interval 这两个属性的值决定;这两个属性的默认值分别是SystemParameters.KeyboardDelay以及SystemParameters.KeyboardSpeed
- RepeatButton 属于System.Windows.Controls.- Primit ives 命名空间,你应该会把它和其他成熟的控件一起使用,而不是单独使用它。
3、ToggleButton
- ToggleButton 是一种在点击时可以保留其状态的“粘性”按钮(它也没有Button 控件的取消行为以及默认行为),第1 次点击它的时候,IsChecked 属性会被设为true;再点击一次,就被设为了false。
- IsThreeState 属性,如果把它设为true 的话,IsChecked 就会有3 种值:true、false或者null。IsChecked 是Nullable<Boolean>类型的。第1 次点击ToggleButton 会把IsChecked 设为true,第2 次则把它设为null,第3 次把它设为false,依此类推。
- ToggleButton 分别为每一个IsChecked 的值定义了不同的事件:true 对应Checked 事件,false 对应Unchecked 事件,null 对应Indeterminate 事件。
- ToggleButton 属于System.Windows.Controls.Primitives 命名空间。
4、CheckBox
- 拥有由外部提供的内容
- 可以区分是被鼠标点击还是被键盘点击。
- 可以在被点击时记录选中(checked)或者未选中(unchecked)状态。
- 支持3 种状态模式,分别为选中(checked)、不确定(indeterminate)、未选中(unche- cked)。
- CheckBox除了在继承ToggleButton 时重写了控件默认样式以及视觉外观以外,其他都与ToggleButton 完全一样。
5、RadioButton十、简单容器
- 支持互斥性。当多个RadioButton被放在一个组里,一次只有一个可以被选中,把一个RadioButton 选中就会自动把组中其他所有的RadioButton 设为不选中。
- 默认情况下,任何RadioButton 被自动分成一个组,共享同一个逻辑父元素。如果需要用自定义的方法对RadioButton 作分组,那么可以用它的GroupName 属性,这个属性是字符串类型的,任何拥有相同GroupName 的RadioButton 会被分在同个组里(只要它们在逻辑上属于同一个源)。因此可以把属于不同父元素的RadioButton 放在一个组中。
1、Label
- 只对文本有用。
- 支持访问键(access key)。有了访问键,可以在用户按下Alt 键和某一个字母键时,对Lable文本中的某个字母做特殊处理。当用户按下Alt 键和某一个字母键时,Label 允许你指定哪个元素获得焦点。在字母之前增加一条下划线就可以指派某个字母(该字母下出现的下划线是由Windows 的设置决定),然后用Label 的Target 属性(UIElement 类型)来选择目标元素。
2、ToolTip
- ToolTip 控件把它的内容放在一个浮动框中,当把鼠标移过与之关联的控件时,就会显示ToolTip 的内容,鼠标移开以后内容会消失。例,在按钮上绑定ToolTip:
- <Button MinWidth="75" Margin="10">
- Help
- <Button.ToolTip>
- Show help!
- </Button.ToolTip>
- </Button>
- ToolTip 类绝对不能被直接放在UI 元素树中,它必须被赋给另一个元素的ToolTip 属性。
- ToolTip 定义了Open 和Closed 事件。
- ToolTipService 定义了一些附加属性,它能够被设置在任何一个使用ToolTip 的元素上(而不是在ToolTip本身设置)。它有几个与ToolTip 一样的属性(因为ToolTip 的值可能有冲突,所以它优先级更高),但是比ToolTip 多了几个属性。例如,ShowDuration 控制鼠标指针悬停在一个元素上多久应该显示ToolTip;InitialShowDelay 控制停止和ToolTip 第1 次被显示之间的时间间隔。你可以把ShowDuration 添加到第1 个ToolTip 的示例中,如下所示:
- <Button MinWidth="75" Margin="10" ToolTipService.ShowDuration="3000">
- Help
- <Button.ToolTip>
- Show help!
- </Button.ToolTip>
- </Button>
3、Frame
- Frame 控件也可以包含任何内容,但是它是把内容从其余的UI 中分离了出来。
- 例: <Frame Source="http://www.csdn.net"/>则显示了网页
- Frame 是一种有Content 属性的内容控件,但是从XAML 角度来看,它并不把Content 当作一种属性。换句话说,XAML 中的Frame 元素不支持子元素。你必须显式地以如下方式使用Content 属性:
如果你同时设置了Source 和Content 属性,Content 优先!
- <Frame>
- <Frame.Content>
- Show Frame.Content
- </Frame.Content>
- </Frame>
十一、带头的容器
1、GroupBox
2、Expander
- 用来组织各种控件的控件。把GroupBox 的内容属性设置为一个可以包含多个子内容的中间控件(intermediate control)
- 与Content 属性一样,Header 属性可以被设置为任意类型的对象。
- 包含了一个按钮,可以展开或者折叠它所包含的内容。(默认情况下,Expander 处于折叠状态。)
- Expander 定义了IsExpanded 属性以及Expanded/Collapsed 事件。
- 可以用ExpandDirection 属性控制扩展的方向(Up、Down、Left 或者Right)。
- 不但可以被索引而且可以被选择。
- Selector 抽象类继承自ItemsControl。
- SelectedIndex——非负的整型数,它表示哪个Item 被选择了,如果没有东西被选择,则用1 表示。Item是根据被添加到集合中的顺序来计数的。
- SelectedItem——当前被选中的Item 的实例。
- SelectedValue——当前被选中的Item 的值。默认情况下这个值是Item 本身,这时Selec- tedValue 与SelectedItem 是一样的。通过设置SelectedValuePath 去选择任意的属性或者表达式,用来表示每个Item 的值(SelectedValuePath 与DisplayMemberPath 工作原理一样)。
- IsSelected——可以用来判断选择或者未被选择的Boolean 变量 (也可以用来获得当前选择的状态)。
- IsSelectionActive—— 说明选择的Item 是否拥有焦点的Boolean 变量。
- 定义了SelectionChanced 事件,它会监听当前选择内容是否被改变。
继承自Selector 的控件:ComboBox、ListBox、ListView、TabControl
1、ComboBox
- 允许用户从一个列表中选择一个Item。
- 下拉框可以使用鼠标点击或者Alt+Up、Alt+Down、F4 键来打开和关闭。
- 定义了两个事件:DropDownOpened 和DropDownClosed,以及一个IsDropDownOpen 属性,它们允许你在下拉框被打开或者关闭时进行操作。IsDropDownOpen 是一个可读写属性,所以可以设置它来改变下拉框的状态。
- ComboBox 允许用户在选择框里输入任何文字。
- 把IsEditable 设置为true 就等于把ComboBox 的选择框变为一个文本框。当选择框是一个文本框时,被选择的Item 只能以简单字符串来显示。
- 默认情况下,把IsEditable 设置为true,则以ToString 方式渲染选择框。
- TextSearch.TextPath 属性能被附加到ComboBox 上,把每个项的属性(或者子属性)作为选择框的文字使用。
- TextSearch 的另一个附加属性是Text 属性,它更加灵活。但是必须被应用到ComboBox 的某个Item 上。可以在选择框内把每一个项的Text 设置为想显示的文字。如附件
- <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
- <ComboBox Width="206" IsEditable="True">
- <!-- Item #1 -->
- <StackPanel TextSearch.Text="Text1" Orientation="Horizontal" Margin="5">
- <Image Source="CurtainCall.bmp"/>
- <StackPanel Width="200">
- <TextBlock Margin="5,0" FontSize="14" FontWeight="Bold"
- VerticalAlignment="center">Curtain Call</TextBlock>
- <TextBlock Margin="5" VerticalAlignment="center" TextWrapping="Wrap">
- Whimsical, with a red curtain background that represents a stage.
- </TextBlock>
- </StackPanel>
- </StackPanel>
- <!-- Item #2 -->
- <StackPanel TextSearch.Text="text2" Orientation="Horizontal" Margin="5">
- <Image Source="Fireworks.bmp"/>
- <StackPanel Width="200">
- <TextBlock Margin="5,0" FontSize="14" FontWeight="Bold"
- VerticalAlignment="center">Fireworks</TextBlock>
- <TextBlock Margin="5" VerticalAlignment="center" TextWrapping="Wrap">
- Sleek, with a black sky containing fireworks. When you need to
- celebrate PowerPoint-style, this design is for you!
- </TextBlock>
- </StackPanel>
- </StackPanel>
- </ComboBox>
- </Canvas>
- SelectionChanged 事件:传给事件处理程序的SelectionChangedEventArgs 类型有两个IList 类型的属性:AddedItems 和
RemovedItems。AddedItems 包含新的选择,而RemovedItems 包含老的选择。
- ComboBoxItem:ComboBoxItem 是一个内容控件。ComboBoxItem 提供了一些有用的属性(IsSelected 与IsHighlighted)和一些有用的事件(Selected 与Unselected)。
2、ListBox
- ListBox 所有的项都直接在控件的边界以内显示(如果它们没有都被显示的话,也可以用滚动条去查看没有显示出来的项)。
- 对于同时发生的选择操作的支持。通过SelectionMode 属性可以控制这个特性,这个属性接受3 个值(来自于SelectionMode 枚举):
·Single(默认)——一次只能选择一项,就像ComboBox 一样。
·Mulle——可以同时选择任何数目的项,点击一个未选中的项将把它添加到ListBox 的Sel- ectedItems集合,而点击一个选中的项会把它从集合里移除。
·Extended——任何数量的项可以被同时选中,但是这一行为是为单选情况所优化的。如果在这种模式下选择多个项,点击的时候必须按住Shift (连续的项)或者Ctrl(不连续的项)。该行为和Win32 ListBox控件一样。
- ListBoxItem:定义了IsSelected 属性以及Selected/Unselected 事件。
- TextSearch 技术
- 使ListBox 平稳地滚动:把ListBox 上的ScrollViewer.CanContentScroll 附加属性设为false,同时会失去ListBox 的虚拟化(Virtualizat ion)功能。可能对数据绑定的性能产生负面影响。
- 在一个ListBox(或者其他的ItemControl)中排序:可以通过ItemsCollection 对象上的一种机制来完成排序,所以它也可以应用在所有ItemsControl 上。ItemsCollection 有一个SortDescriptions 属性能保存任何数量的System.- ComponentModel.SortDescription 实例。每个SortDescription 描述哪一个属性应该被用来排序,是升序还是降序。
3、ListView
- 从ListBox 继承而来。
- ListView 添加一个叫作View 的属性,它允许你把视图定义为比选择一个自定义的ItemsPanel 更丰富的样子。
- View 属性是ViewBase 类型,它是个抽象类。。WPF 有一个具体子类(concrete subclass),名字叫GridView,它和资源管理器的详细视图非常类似。自动支持一些资源管理器中详细视图(Detail view)的高级特性:
·通过拖拉列对列重新排序。
·拖动列的分隔器(separator)可以改变列尺寸。
·通过双击列的分隔器后,GridView 会根据当前内容来自动调整列尺寸。
4、TabControl
- 它可以在多个页面之间进行切换。
- 通过使用TabControl 的TabStripPlacement 属性(Dock 类型),可以把它的位置设为左边、右边或者下边。
- TabItem:
- TabControl 的第1 个项默认是被选中的。你也可以用编程的方式把SelectedItem 设为null(或者把SelectedIndex 设置为1),这样就可以取消选择所有的标签页。
十三、菜单
1、Menu
- Menu 是水平放置它的项的,默认情况下把灰色栏作为背景。
- 把Menu 添加到它的ItemsControl 基类的唯一公开的API 是IsMainMenu 属性。当为true(默认的)时,用户按下Alt 或者F10 键,菜单获得焦点。
- MenuItem 是带头的Items 控件(继承自HeaderedItemControl),它的头实际上是主对象。如果Items 是子元素的话就会被作为
子菜单显示。MenuItem 使用下划线前缀来支持访问键(access key)。
- Separator(分隔线)是一种简单控件。
- Icon——允许把任意类型的对象添加到Header 旁边。Icon 对象会像Header 一样被渲染,尽管它通常是一幅小图片。
- IsCheckable——让MenuItem 的行为像一个CheckBox 控件。
- InputGestureText——用一个相关的手势(gesture)来标识一个项(最常见的就是键盘快捷方式,比如Ctrl+O)。
- 5个事件:Checked、Unchecked、SubmenuOpened、SubmenuClosed 和Click。
- 要为MenuItem 设置一个键盘快捷键,你应该用它的Command 属性。
2、ContextMenu(上下文菜单)
- 是一种保存MenuItem 和Separator 的简单容器。但不能直接把ContextMenu 嵌入到一个元素树中,必须通过一个适当的属性把它加载到控件上。
- IsOpen 属性以及Opened/Closed 事件。
- 默认情况下,菜单左上角位于鼠标指针处,但是可以把它的Placement 改成一个非MousePoint 的值(如Absolute),或者设置它的HorizontalOffset 以及VerticalOffset 属性,来调整这个行为。
- ContextMenuService 静态类,它包含了许多附加属性,分别对应那些由ContextMenu 直接定义的属性。
3、其他Items 控件
A、TreeView
- 用可展开和折叠的节点来分层显示数据。
- 在TreeView 中一定要显式地用TreeViewItem 包装Item,用TreeViewItem来填充,TreeViewItem 就像MenuItem 一样,是一种带有头的控件,它的Header 属性包含着当前的项,而它的Items 集合中保存着子项(子项也是TreeViewItem)。
- TreeViewItem 有两个方便的属性IsExpanded 和IsSelected。还有4 个事件,分别对应于这两个属性的4种状态:Expanded、Collapsed、Selected 和Unselected。
- 同样支持富键盘导航,加号和减号键可以展开或折叠一个项,箭头方向键、Page Up、Page Down、Home 和End 键可以从一个项向另一个项移动焦点。
B、ToolBar
- 对许多小的按钮(或者其他控件)进行分组。
- ToolBar 可以被放在元素树的任何地方,但是通常把它们放在一个叫作ToolBarTray 的FrameworkElement 中。
- 用户就可以拖曳ToolBar 或重新定义ToolBar,。除非ToolBarTray的IsLocked 属性被设置为true。
- ToolBarTray 有一个Orientation 属性,可以把它设置为Vertical 使其所有的ToolBar 垂直排列项。
- 默认都是最后一个元素第一个被移到溢出区域,但是你能通过OverflowMode 附加属性来控制每个项的溢出行为。有了这个属性,你就可以把一个项标记为AsNeeded(默认,按需要溢出)、Always 或Never。
- System.Windows.Input 命名空间中的KeyboardNavigat ion 类定义了一些用来自定义键盘行为的附加属性。
- ToolBar 实际上是一个带有头的Item 控件(就像MenuItem 和TreeViewItem)。它的Header 属性从来不会被显示,但是它可以被用来实现ToolBarTray 的其他特性。
C、StatusBar
- StatusBar 的行为就像Menu,它只是水平排列放它的项,通常用在窗口底部,以显示状态信息。
- StatusBar 为Separator 提供了一个控件模板,Separator 是作为垂直线被渲染的。
- StatusBar 中的项(除了Separator)是被隐式地包装在一个StatusBarItem 中,但是你依然能显式地进行包装。
十四、Range 控件
在一个指定的范围内存储并且显示数值。Range 控件的核心功能来自于一个叫作RangeBase 的抽象类。这个类定义了浮点数类型的属性来存储当前的值以及范围的端点:Value、Minimum 和Maximum。它还定义了一个简单的ValueChanged 事件。
1、ProgressBar
- 是当面对长时间运行的操作时,为用户显示一个ProgressBar 可以帮助他们了解具体的进度情况。
- ProgressBar 有一个默认的Minimum 属性0,和一个默认的Maximum 属性100。
- IsIndeterminate —— 当把它设置为true 时,ProgressBar 会显示一段通用的动画(这样,Minimum、Maximum 以及Value 的值不会影响这段动画)。
- Orientation —— 默认为Horizontal,但是也可以被设置为Vertical,可以使进度从下走到上而不是从左走到右。
2、Slider
- 使用户能够通过在刻度尺移动手指光标来改变当前的值。
- 有一个默认的Minimum 属性值0 和一个默认的Maximum 属性值10。
- 定义了Orientation属性(默认是Horizontal)。
- 包含了几个属性,用于调整刻度的位置和频率、ToolTip 的位置和精度(这个ToolTip 是用来显示手指光标移动到了哪个当前值)、决定手指光标是自动贴近刻度值还是平滑地移动到任何值。
- 对于键盘导航来说,Slider 包含了Delay 以及Interval 属性,它们与RepeatButton 的同名属性一致。
- 要启用刻度,可以把TickPlacement 设定为TopLeft、BottomRight 或者Both。包含了Slider 的方向。
- 支持在当前的范围内显示一个更小的范围。
- IsSelctionRangeEnabled 被设置为true,可以把SelectionStart 和SelectionEnd 设置为这个“子范围”(subrange)的期望值。
十五、文本和墨水控件
用来显示和编辑文字的控件,无论文本输入是来自于键盘还是指示笔,这些控件有:
·TextBox
·RichTextBox
·PasswordBox
·InkCanvas
1、TextBox
- 从TextBoxBase继承。
- 使用户能够输入一行或者多行文字。
- 内建了各种功能支持:与Cut、Copy、Paste、Undo和Redo 命令的绑定(就像在之前章节所看到的),甚至还可以与拼写检测绑定。
- 除非TextBox 的尺寸被它的周边内容(或者给定的显式尺寸)所限制,否则它会随着内部文字的增长而增长。当TextBox 的宽被限制时,通过设定TextWrapping 属性为Wrap 或者WrapWithOverflow,可以将文字换行形成额外的行。
- 用户通过把AcceptReturn 设置为true 就能在输入时使用回车键来换行。
- 拼写检查:可以设置SpellCheck.IsEnabled 属性为true。
- TextBox 提供了简单的整数属性,如CaretIndex、SelectionStart 和SelectionEnd
2、RichTextBox
- 从TextBoxBase继承。
- 能包含格式化的文字(以及嵌在文字当中的任意对象)。
- 提供了一个TextPointer 类型的CaretPosition 属性。
- 提供了TextSelection 类型的Selection 属性。
- RichTextBox 的内容存在一个Document 属性里(类型是FlowDocument),而不是存在一个简单的字符串类型的Text 属性里。
3、PasswordBox
- 不会显示输入的文字,而是显示小圆点,可以设置PasswordChar 属性来选择一个新的样式。
- PasswordBox 的文本保存在一个叫作Password 的字符串属性里。
- 定义了一个Password- Changed 事件。
4、InkCanvas
- 主要目的是(通过鼠标或者和指示笔)捕捉笔迹。
- 从FrameworkElement 继承。
- 默认模式下,InkCanvas 允许在它的表面上进行简单的书写和画图。当使用指示笔时,笔尖用来写、笔端用来擦。、
- 通过使用InkCanvas 的DefaultDrawingAttributes 属性,可以改变以后输入的笔画外观(宽度、颜色等)。
- 利用EditingMode 属性被独立地应用到指示笔尖(或鼠标),并通过Edit ingModeInverted 属性来应用于指示笔的末端(back end)。只读的ActiveEdit ingMode 属性可以告诉你哪一个属性当前正在被使用。所有这3 个属性都是InkCanvasEdit ingMode 类型的,它有以下几种值:
·Ink(Edit ingMode 的默认值)—— 通过鼠标或者指示笔来绘制笔画。
·InkAndGesture —— 和Ink 一样,但同样可以识别用户的手势。手势的列表(Up、Down、Circle、
ScratchOut 和Tap)保存在System.Windows.Ink.Applicat ionGesture 枚举类型中。
·GestureOnly —— 只识别手势,不会绘制用户输入的笔画。
·EraseByStroke (Edit ingModeInverted 的默认值)—— 当笔画被触及时将笔画擦掉。
·EraseByPoint —— 只擦掉直接碰及到的笔画部分(就像传统的铅笔橡皮)。
·Select —— 当被触及时,选择笔画或者任何UIElement,使它们能被删除、移动或者在InkCanvas 范
围内被调整尺寸。
·None —— 对于鼠标或者指示笔不做任何响应。
- 定义了15 种事件,其中包括改变编辑模式、改变/移动/调整选择、收集或者擦除笔画,以及执行手势。