一、什么是控件呢?
控件要满足三个条件:
- 它是相对独立的模块,这些模块可以通过一定的方式(通常是排版)像堆积木似的组合起来;
- 它具有对用户输入反应的能力,用户输入经由Windows操作系统的消息机制而转换为控件事项;
- 每个控件具有特定的图形表现形式,由于WPF把控件的特性和控件的显示方式分开,过去由显示方式区分控件的界限有时候不是很清晰的。
WPF空间类继承图:
控件都是从Control类中派生出来的,基本上可以分为4类:
● 内容控件(Content Controls)
● 条目控件(Items Controls)
● 文本控件(Text Controls)
● 范围控件(Range Controls)
二、内容控件(Content Controls)
内容控件是WPF控件中的一大类,ContentControl直接从Control类中派生出来。
内容控件的最大特征是这类控件都含有一个Content属性,即它只能有一个直接的子控件,这个Content属性的类型为Object。
1.框架控件(Frame)
框架控件的主要作用是把其中的内容和界面上其他部分分开,它里面可以含有任何东西,但只能有一个直接的子控件。虽然Frame可以是其他控件的子控件,但是其宿主包容器的相关属性不会传递到Frame中,即起到隔离的作用,即Frame控件“阻断”了相关属性的传递。
这个控件有个好玩的地方,可以嵌入一个网址。
通常使用Frame控件的目的是要在其中嵌入HTML内容;
在Frame中加入HTML非常简单,只要设定Source属性就可以了。
2.WPF按钮(Button)
WPF中的按钮都是从ButtonBase抽象类中派生出来的。
ButtonBase中定义了四个属性
以ButtonBase为基类的有四个类:Button、GridViewColumnHeader、RepeatButton和ToggleButton。其中GridViewColumnHeader控件,笔者将在讨论GridView控件时一并讨论;从ToggleButton中派生出两个著名的按钮控件:RadioButton和CheckBox。
按钮Button
按钮是Windows用户界面程序中最常用的控件。
3.拨动按钮(ToggleButton)
拨动按钮的特性就像拨动开关一样,把开关拨到一个位置,灯亮了;把开关拨到另一个位置,灯灭了。拨动按钮也是这样,按一下拨动按钮,其IsChecked属性变为True;再按一下拨动按钮,其IsChecked属性变为False。
有时,我们需要拨动按钮维持三个状态,这时我们把IsThreeeState属性设为True。在IsThreeeState属性设为True时,IsChecked的属性值可能取三个值:True,False和Null,ToggleButton中的事件。
一般并不直接创建ToggleButton实例,而是使用其派生类:CheckBox和RadioButton。
4.CheckBox控件
CheckBox控件用在可以有多个选项,而又可以同时选择两个或两个以上选项的情况下。比如说,某个专业一学期开了八门课,其中有两门是必修课,其余都是选修课,那么这个时候就可以把这六门选修课用CheckBox表现出来,供同学们选择。
CheckBox并没有增加任何属性,它为ToggleButton提供外观。
5.RadioButton控件
RadioButton控件若在一组选项里面,你必须而且只能选择一个选项,需要使用RadioButton。比如,要调查某一类消费者使用你的产品,就需要知道消费者的性别、年龄组等,这时RadioButton就是最好的选择。因为一个人要么是男的,要么是女的。
就像前面所说的“你必须选择一个”,RadioButton并不提供“不选”操作,要去掉某个选项的方法是选择另一个选项。所以,需要把相关选项放到一个组里。WPF的RadioButton增加了一个属性:GroupName,其类型为字符串string。
6.重复按钮(RepeatButton)
重复按钮是WPF新增的一个控件,和一般的按钮不同,重复按钮可以在按下鼠标左键时,不停地发出单击Click事件。这种特性在某些情况下是很有用的,比如DVD机上的快进或快退键。在按下快进键的时候,DVD中的内容会快速地播放出来,还可以选择以2倍、4倍、8倍或更高速率播放,从而更快地找到所要找的内容。
重复按钮实现了这种功能,它增加了两个属性:Delay和Interval。
● Delay这个属性设置从用户按下鼠标左键到开始重复发送Click事件的延迟时间。单位为毫秒(ms),Delay的数值必须大于等于0。
● Interval这个属性设置当用户按下鼠标左键时,每次发出Click事件的时间间隔。单位为毫秒(ms),Interval的数值必须大于等于0。
7.带有标题栏的内容控件(HeaderedContentControl)
带有标题的内容控件(HeaderedContentControl)除了具有内容控件的Content属性之外,加入了一个新的标题属性(Header)。Header的类型和Content一样,都是Object,换句话说,任何.NET对象都可以成为标题Header。当然最常用的标题是字符串,但也可以是任何其他控件或控件的组合。
若不用标题内容控件HeaderedContentControl,也可以很容易用其他控件的组合来达到同样的效果。确实,通常使用的不是HeaderedContentControl控件本身,而是它的两个派生类:分组框和伸展控件。
8.分组框(GroupBox)
分组框(GroupBox)是一个常用的控件,在Win32里就有这样的控件。其用法是把一些意义相近的控件放在一起,同时用一个带标题的边框把它们组合起来。
9.伸展控件(Expander)
伸展控件是Win 32中没有的一个控件,它在压缩时,只显示标题;在展开时才显示其中的内容。所以,使用这个控件可以在很小的版面上显示更多的内容。现在很多网页已经使用了这种控件,WPF对这一控件进行了标准化。
伸展控件增加了两个相关属性,一个是ExpandDirection,其类型为枚举类型,可取Up、Down、Left、Right四个值;另一个是IsExpanded,其类型为布尔值,当该值为True时表明伸展控件处在展开状态。
10.标签控件(Label)
标签控件也是一个常用的控件,这个控件就是在窗口的某个地方显示字符串,这里的某个地方通常是由控制版面控件安排的。
标签控件是一个内容控件,与所有的内容控件一样,可以把它设为任何WPF控件及其组合,但我们最常用的标签控件的功能是显示字符串。在WPF里,Text-Block和TextBox等都可以用来显示字符串。
标签控件区别于TextBlock和TextBox的功能主要有两点:
1.在默认的情况下,标签控件是只读的,颜色是灰色的;
2.标签控件内置了一个AccessText控件,可以直接设定热键到目标控件。
11.为按钮设置热键
使用AccessText设置热键非常简单,即在字母前加一下画线即可。
<AccessText>我有热键P(_P)</AccessText>
在使用中文时,一般不会遇到字母前用到下画线的情况,但在英文里会遇到字符串本身有下画线,而不是热键的情况。这时,我们需要加两个
下画线:
<AccessText>This _is Really cool!</AccessText>
12.ToolTip
ToolTip通常是程序员在某些用户界面元素上加入的帮助信息,过去常用在工具条上。
例如,在Microsoft Word软件中,当把鼠标移到工具条的某个按钮上时,在按钮的下面会显示一个矩形框,矩形框里显示该按钮的功能提示信息。当鼠标离开该按钮时,这个矩形框会自然消失,这就是我们常说的ToolTip。过去ToolTip控件相对简单,通常只能显示简单的文字信息,MFC里的CtoolTipCtrl就是这样的控件。
而WPF中的ToolTip控件功能则强大灵活得多:首先,ToolTip属性是定义在FrameworkElement类和FrameworkContent中的,这意味着不仅WPF中的所有控件都可以使用ToolTip,而且图形和文档也可以有ToolTip。其次,ToolTip和其他WPF内容控件一样,其中可以含有其他任何WPF控件及其组合。
使用ToolTip需要注意下述两点:
- ToolTip虽然是一个控件,但其本身不具备接收用户输入的功能。比如上面的例子中,在ToolTip中使用了ListBox,你就无法像通常ListBox那样选择其中的条目。
- ToolTip虽然是一个控件,但它不能像其他控件那样作为其他控件的子控件,它必须和某个控件的ToolTip属性相连。当鼠标离开控件时,其ToolTip会自动隐藏。
有时候,你希望控制ToolTip的显示时间,ToolTipService类就是为此设计的,该类含有控制ToolTip的附加属性,如控制ToolTip水平或竖直方向位移的属性HorizontalOffset、VerticalOffset;控制ToolTip显示时间的ShowDuration属性;控制是否在未使能的控件上显示ToolTip的ShowOnDisabled属性等。
13.ScrollViewer
当窗口中的内容比窗口的大小要大时,通常要在窗口中显示滚动条。在WPF中显示滚动条要用到ScrollViewer类,这是一个内容控件,和所有的内容控件一样,它只能含有一个子控件。
使用LineBreak控制句子的分行。
三、条目控件(Items Controls)
ItemsControl,它是直接从Control类中派生出来的。与内容控件中只能含有一个控件不同,ItemsControl中含有Items属性,这个属性具有ItemCollection类型。
在内容控件中,其内容可以是任何一个Object类型的对象;在Items属性中则可以加入任何一个Object类型的对象。
WPF在显示Items属性中的对象时,如果这个对象是UI元素,就直接调用UI元素的OnRender方法;如果这个对象不是UI元素,WPF会创建一个TextBlock,并在TextBox中显示该对象的ToString方法所返回的结果(由于在.NET中所有的类都从Object类中派生出来,而Object类中含有ToString方法,所以,调用ToString方法是不会有什么问题的)。
除了可以加入任何.NET对象的Items属性之外,ItemsControl类中还有一个重要的属性ItemsSource,这个属性是用来作数据绑定的。需要注意的是,一旦我们使用了ItemsSource属性,Items属性就会被自动设置为null。这表明只能使用ItemsSource和Items两个属性当中的一个,而且ItemsSource具有更高的优先级。
1.菜单(Menu)
菜单是一个常用的控件,常位于应用程序窗口的顶部。每个菜单里面含有菜单条目(MenuItem),MenuItem是一个带有标题的条目控件,它从HeaderedItemControl类中派生出来。HeaderedItemControl类中有一个类型为Object的属性:Header,在菜单条目中通常把它设为字符串。有时候菜单条目下会有子菜单,子菜单的条目下还会有下一层的子菜单,等等。
这里的InputGestureText只负责显示热键信息,要是热键工作,需要用到命令Command属性。
为方便程序员快速开发界面,WPF定义了一个ApplicationCommands的类。ApplicationCommands类中定义了编辑软件常用的命令,这些命令有:Close、Copy、Cut、Delete、Find、Help、New、Open、Paste、Print、PrintPreview、Redo、Replace、Save、SaveAs, SelectAll、Stop、Undo等。当ApplicationCommands和菜单相连,它还具有自动Enable/Disable菜单条目的功能。
弹出菜单(ContextMenu)
与下拉菜单和排版类相连不同,弹出菜单则要附加在UI元素的ContextMenu属性上。FrameworkElement里面有一个ContextMenu属性,程序员所要做的就是构建弹出菜单,并在相应的UI元素上设置ContextMenu属性。由于FrameworkElement是所有UI元素的基类,所以,WPF在广泛的范围内支持弹出菜单。
ColorBox类从ListBox中派生出来,首先用UniformGrid作为ListBox的ItemsPanel。再在ListBox的Items属性中加入矩形,矩形的颜色是预定义的。这样,ColorBox就会显示预定义的颜色供用户选择。
2.工具条(ToolBar)
过去工具条和菜单常常一起用在应用程序中,比如Microsoft Office软件,位于视窗标题栏下面的是菜单,菜单下面就是工具条。有时候,工具条位于一个浮动窗口内,这样用户可以把工具条停靠在屏幕的任何位置。与菜单相比,通常只要在工具条上单击鼠标一次就可以完成某个功能,而菜单通常要单击两次或以上;工具条使用图标加ToolTip的方式,在屏幕上要占据较大的位置,所以只适合把常用的菜单功能放在工具条上。
3.Selector
Selector类是下面三个条目控件的基类:
● ComboBox
● ListBox
● TabControl
这三个控件共同的特点是:其中包含一个或多个条目供用户选择。而这个共同的特点,自然地就移植在它们的基类——Selector类中。ListBox控件还有一个派生类——ListView,它自然地继承了Selector类中所移植的特性。Selector类是一个抽象类,不可以直接创建Selector对象。Selector类属性,在ComboBox、ListBox、TabControl以及ListView中都会用到这些属性。
4.组合框(ComboBox)
组合框主要由字符框(TextBlock)、拨动按钮(ToggleButton)和Popup几个控件组成,如果使用前面我用过的Snoop工具,会发现其中还有其他的一些控件,但其基本功能是由这三个控件组成的。TextBlock用于显示所选中的条目,ToggleButton给用户提供按键操作,当用户按下ComboBox右边的按钮时,Popup控件显示ComboBox中的条目内容。
有时需要组合框支持用户在输入字符串时自动选择组合框中的条目的特性,用户输入的字符串可以不在组合框的条目中;有时候又需要限制用户输入字符串。当需要选择合适的组合框特性时,要设置IsEditable和IsReadOnly两个属性,下图列出了这两个属性的值及其对组合框属性的影响。
5.TabControl
TabControl在Win32中就有了,不过过去常用在会话框上。它就像一个文件夹,每个文件夹里含有特定的文件,用一个标签贴在文件夹的侧面,然后把文件夹叠起来。这样,比把文件铺开在桌面上要省地方,这就是设计TabControl的最初目的。
6.列表框(ListBox)
ListBox中含有至少一个ListBoxItem。ListBoxItem从内容控件(ContentControl)中派生出来,因此具有内容控件的特征。ListBox中有一个SelectionMode属性,该属性为枚举类型。可以取Single、Multiple和Extended三个值,当SelectionMode设为Single时,用户只能选择ListBox中一个条目;当SelectionMode设为Multiple时,用户可以选择ListBox中多个条目;当SelectionMode设为Extended时,用户需要按下“SHIFT”键,才能选择ListBox中的多个条目;由于ListBox允许用户选择多个ListBoxItem,所以它有一个SelectedItems。这是一个集合,其中含有用户选择的多个条目。
7.ListView
ListView也是一个老的控件,它和ListBox非常类似,所以它是ListBox的派生类。ListView和ListBox不同的地方在于,ListView有多列,而且每列都有头。ListView默认的SelectionMode为Extended。
8.状态条(StatusBar)
状态条用于显示应用程序的当前状态信息,一般放在窗口的底部。如Office Word主窗口下面的状态条,Word在其中显示文档的当前页、字数等相关信息。StatusBar是一个条目控件,它是ItemsControl的派生类。
9.树形控件TreeView和TreeViewItem
TreeView是一个非常重要的控件,微软在Windows 95中首先引入树形控件。TreeView用来显示具有树形结构的信息,在现实生活中,有很多树形结构的例子。如家族树始于某个祖宗,随着一代代繁衍,家族树越来越庞大,但没个家族分支,都可以在树形图上找到其来源即“树根”。中国的家谱就是对家族树的描述,我们名字中的中间那个字表示辈分(这就是为什么三个字的名字要比两个字好,两个字的名字我们无法获知辈分信息),你可以很容易地从中识别你在家族书中的分支。树枝分叉的交接处叫做节点,节点有两个状态:展开和关闭,一般用两个不同的图标来表示这两种不同的状态。树形图可以直观地描述节点间的父与子和兄与弟这类关系。
TreeView中的相关属性
TreeViewItem中的相关属性
四、文本控件(Text Controls)
文本控件共有4个类,这4个类是:
- 用于用户输入口令的PasswordBox;
- 提供基本字符输入的TextBox;
- 用于增强字符输入的RichTextBox;
- TextBoxBase是TextBox和RichTextBox的基类,它是一个不能实例化的抽象类
1.口令输入框(PasswordBox)
为了避免软件系统不被不相关的人使用,通常需要对用户进行身份认证,并根据用户的级别赋予用户相应的功能。这个过程称作Authentication和Authorization。
最常用的Authentication方法就是要求用户输入用户名和口令。用户输入口令通常不能显示出来,以防站在用户边上的人偷看密码,所以需要把用户输入的字符掩藏起来。过去在MFC中,程序员要对TextBox做一些工作,以满足上述要求。WPF提供了用于输入用户口令的控件——口令输入框(PasswordBox)。
2.文字输入框(TextBox)
文字输入框(TextBox)是一个非常常用的控件,在前面的程序中已经多次用过。TextBox看似简单,其实它是由多个控件组成的,如果你用Snoop工具检查TextBox,会看到其中含有Border、ScrollViewer、Grid、Rectangle、TextView、ScrollBar等一些控件。
3.RichTextBox
TextBox中的字符只能有一种格式,若你需要用多种方式显示字符,或在字符中插入其他的图像、声音等对象时,就需要使用RichTextBox。
RichTextBox中的大部分属性和TextBox相同,都是继承TextBoxBase中的属性。RichTextBox中有一个Document属性,其类型为FlowDocument。正是由于这个属性,使得RichTextBox中的内容丰富了起来。
五、范围控件(Range Controls)
ScrollBar、ProgressBar和SlideBar这三个控件统称为范围控件,它们都是从同一个基类RangeBase中派生出来的。
RangeBase是一个抽象类,它定义了最大(Maximum),最小(Minimum)值;范围控件的当前值(Value ),SmallChange和LargeChange两个属性则定义了每次变化的单位。范围控件的取值一定在Minimum和Maximum之间。
1.滚动条(ScrollBar)
滚动条是一个常用的控件,使用起来非常简单。自己去看属性参数。
2.滑动条(Slider)
滑动条是一个边上带有刻度的范围控件,在某些情况下使用滑动条很直观,如多媒体播放器,用户可以直接通过拉动滑动条上的滑块来选择要看的视频位置。
刻度的位置由TickPlacement属性确定,其类型为TickPlacement,是一个枚举类型。它可以取两个值:TopLeft和BottomRight。当滑动条是水平放置时,若TickPlacement为TopLeft,这是刻度位于滑动条的上方;若TickPlacement为BottomRight时,刻度位于滑动条的下方。当滑动条为垂直放置,TickPlacement控制刻度位于滑动条的左边或右边。设定滑动条的刻度有两种方法,方法之一是设置滑动条的Ticks属性,这是一个浮点数集合,滑动条会在你设定的浮点数的位置显示刻度。方法之二是设置TickFrequency,滑动条会在Maximum和Mimimum值之间,根据TickFrequency自动设置相应的刻度。例如,滑动条的最大值为100,最小值为0,TickFrequency为10,那么,活动条刻度的值会自动设为0,10,20,……
当设置IsSelectRangeEnabled为True,并设置SelectionStart和SelectionEnd的值后,滑动条上就会出现选择范围的标识。需要注意的是SelectionStart应小于SelectionEnd;并且这两个值应在Maximum和Minimum之间。
滑动条还可以在鼠标单击滑块时,用ToolTip的方式显示当前滑块的值。这时要用到AutoToolTipPlacement和AutoToolTipPrecision两个属性。
AutoToolTipPrecision用来定义显示的精度,其值为小数点位数。
3. 进展条(ProgressBar)
当某个任务需要较长时间才能完成时,需要在用户界面上显示一个任务进行到什么程度的控件,否则,若什么都不显示,用户会认为程序不能运行了。这个控件就是进展条(ProgressBar)。
进展条的默认Minimum值为0,默认Maximum的值为100。使用进展条通常要用到动画。若不想使用动画,而又不在乎什么时候任务会结束,可以把IsIndeterminate属性设为true,直到任务执行完时,再把它设为false。这样,你会看到进展条中的小矩形一直在动。
注:本文内容整理自《WPF专业编程指南-李应保著》,仅用于笔记学习。