标准WPF控件在不同的Windows支持的主题下有不同的外观。如果WPF遇到了一些求知的新主题,WPF会自动把它当作Classic主题来对待。

内容控件

  内容控件是只允许包含单一项的简单控件。内容控件都继承自System.Windows.Controls.ContentControl,它们拥有只含一项的Object类型的Content属性。

  因为内容控件的单一项可能是任意对象,所以它可能包含一个很大的对象树。它只能有一个直接子节点。除了Content以外,ContentControl类另外一个有趣成员是HasContent布尔型属性。如果Content为空(Content == null),它返回false,否则返回true。

  从C#语言角度来看,HasContent属性是冗余的,但从XAML语言来看,它却非常有用。比如说,当HasContent属性为true时,使用属性触发器去设置不同的属性值会变得非常容易。

Content和任意对象

  如果你给ContentControl控件的Content指定派生自WPF的UIElement类, 它会调用UIElement的OnRender方法来绘制自己;否则,如果在控件中使用了一个数据模板,这个模板会提供一个相应的渲染自己的行为;如果前两个条件都不满足,内容的ToString方法将会被调用,并返回一串在TextBlock里面渲染过的文本。

  WPF自带的内容控件有3大种类

  • 按钮
  • 简单容器
  • 带头(header)的容器

  Window类也是一种内容控件。

按钮

  按钮基类(ButtonBase)控件是一个可以被单击但不能被双击的内容控件。

  可能你想在按钮按下时做些什么(当鼠标左键或空格键被按下,但还没有被释放时),为此ButtonBase类定义了布尔类型的IsPressed属性。

  ButtonBase最有意思的特点是ClickMode属性。通过使用ClickMode枚举值来修改该属性值,可以准确控制何时触发Click事件。这个枚举类型的值为:Release(默认)、Press和Hover。尽管设置标准按钮的ClickMode属性会让用户很困惑,但这个属性对于那些拥有自定义样式的,看起来完全不像标准按钮的按钮却是一个福音。在这种情况下,按下一个对象和点击一个对象会产生相同的结果。

  有些控件完全继承自ButtonBase类,这些控件是:Button、RepeatButton、ToggleButton、CheckBox、RadioButton。

Button

  WPF的按钮类只在ButtonBase现有基础上加了个简单的概念:是一个取消按钮还是一个默认按钮。这种机制对于对话框来说是一种捷径。如果对话框上的一个按钮的Button.IsCancel被设置成了True,点击该按钮,对话框将自动关闭。如果Button.IsDefault被设置成了True,按回车就会触发该按钮的Click事件。

  按钮控件的IsDefault和IsDefaulted属性差别:

  IsDefault是一个可读写属性,决定按钮是否为默认按钮。IsDefaulted是只读属性,表示按钮的某一状态,比如按回车键会使它处于点击状态。也就是说当Default是True的时候,IsDefaulted只能是true,且不管是默认按钮还是TextBox获得了焦点。这个特性使你可以通过按回车键来触发默认按钮的点击事件,即使这时焦点在TextBox上。

  如何才能以编程方式点击一个按钮?

  按钮和其他WPF控件一样,有一个属性System.Windows.Automation.Peers命名空间的peer类来支持UI Atuomation:ButtonAutomationPeer,可以这样使用它:

ButtonAutomationPeer bap = new ButtonAutomationPeer(myButton);
IInvokeProvider iip = bap.GetPattern(PatternInterface.Invoke) as IInvokerProvider;
iip.Invoke(); //点击该按钮

  UI Automation类有许多对于自动测试相当有用的成员。

RepeatButton

  RepeatButton的行为基本和Button一样,并且它会在按钮一直被按着的情况下触发点击事件。产生点击事件的频率主要由RepeatButton的Delay及Interval这两个属性的值决定;这两个属性的默认值分别是SystemParameters.KeyboardDelay及SystemParameters.KeyboardSpeed。

  RepeatButton属于System.Windows.Controls.Primitives命名空间,你应该把它和其它成熟的控件一起使用,而不是单独使用它。

ToggleButton

  ToggleButton是一种在点击时可以保留其状态的“粘性”按钮。第1次点击它时,IsChecked属性会被设为true,再点击一次,就被设为了false。它还有一个Is-ThreeState属性,如果把它设为true的话,IsChecked会有3种值:true、false、null。事实上,IsChecked是Nullable<Boolean>类型的。

  ToggleButton分别为每一个IsChecked的值定义了不同的事件:true对应于Checked事件;false对应于Unchecked事件,null对应于Indeterminated事件。它没有单独的IsCheckedChanged事件。

  ToggleButton和RepeatButton属于同一命名空间。

CheckBox

  CheckBox和ToggleButton只有外观上的差别。CheckBox除了在继承ToggleButton时重写了控件默认样式及视觉外观外,其他都与ToggleButton完全一样。

RadioButton

  RadioButton是另一种从ToggleButton继承过来的控件,但它的特殊性在于支持互斥性。如果需要用自定义的方法对RadioButton作分组,那么可以用它的GroupName属性。

简单容器

  WPF包含了许多内建的内容控件,它们没有类似Button控件的可被点击的概念,但却有它们自己存在的独特性。

Label

  Label是经典控件,和以前的应用一样。作为一种WPF的内容控件,它可以用Content属性存储任何内容----Button、Menu等,但Label只对文本有用。

  可以使用WPF中不同的方法把文字放在屏幕上,比如可使用一个TextBlock元素,但Label的独到之处是它支持访问键(access key)。有了访问键,可以在用户按下Alt键和某一个字母键时对Label中的某个字母做特殊处理。当用户按下Alt键和某一个字母键时,Label允许你指定哪个元素获得焦点。在字母之前增加一条下划线就可以指派某个字母,然后用Label的Target属性(UIElement类型)来选择目标元素。

  要在另一个控件中使用Label控件的访问键支持,可以把它和TextBox控件配合使用。如下例当Alt+U键被按下时焦点转到userNameBox控件:

<Label Target="{Binding ElementName=userNameBox}">_User Name:</Label>
<TextBox x:Name="userNameBox"/>

  在C#中,可使用下面的代码把它设置为TextBox控件的实例(假设Label控件的名字是userNameLabel):

userNameLabel.Target = userNameBox;

ToolTip

  ToolTip控件把它的内容放在一个浮动框中,当把鼠标移过与之关联的控件时,就会显示ToolTip的内容,鼠标移开后内容会消失。

<Button>
OK
<Button.ToolTip>
<ToolTip>
Clicking this will submit your request.
</ToolTip>
</Button.ToolTip>
</Button>

  ToolTip类绝对不能被直接放在UI元素中,它必须被赋给另一个元素的ToolTip属性。

  当设置元素的ToolTip属性时,基础不需要使用ToolTip控件。这个属性是Object类型,如果把它设为任何一个非ToolTip对象,这个属性的实现会自动创建一个ToolTip,并使用这个属性的值作为ToolTip的内容。因此,上例可被简化为:

<Button>
OK
<Button.ToolTip>
Clicking this will submit your request.
</Button.ToolTip>
</Button>

<!--或更简单-->

<Button Content="OK" ToolTip="Clicking this will submit your request."/>

  你可能想在ToolTip出现和消失时做些事件,为此ToolTip定义了Open和Closed事件。

  有时候你可能想在多个控件上应用相同的ToolTip,尽管你希望不同控件上的ToolTip行为有所不同。对于这些情况,ToolTipService静态类可以满足你的需求。

  ToolTipService定义了一些附加属性,它能够被设置在任何一个使用ToolTip的元素上(而不是在ToolTip本身设置)。它有几个与ToolTip一样的属性(因为ToolTip的值可能有冲突,所以它的优先级更高),但它比ToolTip多了几个属性。如,ShowDuration控件鼠标指针悬停在一个元素上多久应该显示ToolTip。

<Button ToolTipService.ShowDuration="3000">
...
</Button>

  当鼠标滑过一个被禁用的元素时,怎样才能让ToolTip显示?

  只需使用ToolTipService类的ShowOnDisabled附加属性:

<Button ToolTipService.ShowOnDisabled="True">
...
</Button>

  或在C#中,可以调用附加属性相对应的静态方法:

ToolTipService.SetShowOnDisabled(myButton, true);

Frame

  就像所有其他内容控件一样,Frame控件也可以包含任何内容,担它把内容从其他的UI中分离了出来。例如,当属性在Frame中时,它们将不从元素树继承。从很多方面来看,WPF的Frame行为很像HTML的Frame。

  谈到HTML,Frame的要求是除了渲染WPF内容外还要可以渲染HTML内容。Frame的Source属性是System.Uri类型的,可以被设置为任何一个HTML(或XAML)页面,如:

<Frame Source="http://www.pinvoke.net" />

  Frame内建WPF导航跟踪支持,它既可以应用到HTML上,又可以应用到XAML内容上。

  所以,你可以把Frame控件当作一个功能更强大的“Microsoft Web Browser”ActiveX控件或Windows Forms WebBrowser控件。

  虽然Frame是一种有Content属性的内容控件,但从XAML角度来看,它并不把Content当作一种属性。换句话说,XAML中的Frame元素不支持子元素,你必须显式地以如下方式使用Content属性:

<Frame>
<Frame.Content>
...
</Frame.Content>
</Frame>

  为了达到这种效果,Frame通过使用空的ContentPropertyAttribute来标记自己,这样可以覆盖ContentControl基类中的[ContentProperty("Content")]。

  WPF的设计者之所以实现它,是因为把Source属性设置为一个外部文件的作法是Frame的标准使用方法,这样可以弱化Frame的Content属性。Frame作为ContentControl的唯一原因是为了与NavigationWindow保持一致性。注意,如果同时设置了Source和Content属性,Content优先。

带头(header)的容器

  带头的容器与前面的控件不同之处在于:它们在主内容上添加了一处自定义header,这种控件从ContentControl的HeaderedContentControl子类继承而来,该子类添加了一个Object类型的Header属性。

GroupBox

  GroupBox是一种常见的用来组织各种控件的控件,通常被用来包含多个项。因此,你需要把GroupBox的内容属性设置为一个可包含多个子内容的中间控件。

  与Content属性一样,Header属性可以被设置为任意类型的对象。

<GroupBox>
<GroupBox.Header>
<Button>Grammer</Button>
</GroupBox.Header>
<StackPanel>
<CheckBox>Check grammer as you type</CheckBox>
<CheckBox>Hide grammatical errors in this document</CheckBox>
<CheckBox>Check grammer with spelling</CheckBox>
</StackPanel>
</GroupBox>

Expander

  Expander是不基于Win32 UI技术的控件。

  Expander和GroupBox非常像,但它包含了一个按钮,可以展开或折叠它所包含的内容。

  Expander定义了IsExpanded属性及Expanded/Collapsed事件。你还可以用ExpandDirection属性控件扩展的方向。

  Expander中的按钮实际上是被重新设定样式的ToggleButton。像ToggleButton和RepeatButton这类更简单的控件总是被更复杂的控件使用。

posted on 2011-11-13 15:43  辛勤的代码工  阅读(3850)  评论(0编辑  收藏  举报