Content模型表示当前元素可以直接使用其他元素作为其子元素创建需要的用户的界面。这种套嵌关系中并没有恒定的包含关系,更没有Content模型的最主要特征是Content属性这一说法。
ContentControl类,首先包含一个Content属性,用以记录该控件需要显示的信息。该属性的类型为Object,即属于该类模型的各个空进可以也只可以有一个子元素。与Content属性相关的属性,是HasContent属性,C#模拟代码如下:
public bool HasContent
{
get{ return Content==null?false:true;}
}
而XAML无法表达Content==null对应的逻辑,因为在需要以Content属性是否被设置为判读条件的请控制,该属性十分有用,并不冗余。
ContentPresenter是Content控件用以显示其Content属性记录心得外观界面元素,可以对所有派生自Object类的实例进行显示。ContentPresenter的显示有一下几个属性辅助完成:Content、ContentSource、ContentTemplate、ContentTemplateSelector:
- 若Content属性属于UIElement类的派生类,则直接将他加到视觉树;
- 若ContentTemplate属性被设置,那么根据ContentTemplate记录的模板创建一个用来显示Content的界面元素实例并将它添加到视觉树;
- 若ContentTemplateSelector属性被设置,那么根据其记录的模板选择一个适当的模板,并根据此模板按照2创建Content属性的视觉树;
- 若Content属性记录的数据类型具有一个数据模板(DateTemplate),那么使用它作为Content属性创建界面元素;
- 若Content属性记录的数据类型附加了一个类型转换器(TypeConverter),WPF直接使用该转换器为Content属性创建一个UIElement类实例,并将它加入到视觉树;
- 若5中类型转换器最终将Content属性转换wie字符串,则WPF使用TextBlock对该字符串进行包装,并将此TextBlock实例添加到视觉树;
- 若上述条件均不符合,则WPF内部使用ToString将Content属性转化为字符串,包装到TextBlock后添加到视觉树。
<Button Name="button1" Content="button1" Click="OnButton1Click"/>
<Button Name="button2" Content="button2"/>
<Button Name="button3" Content="button3"/>
<Button Name="button4" Content="button4"/>
public Window1()
{
InitializeComponent();
//以下3句等价
button2.Click += OnButton2Click;
button3.Click += new RoutedEventHandler(OnButton3Click);
button4.AddHandler(Button.ClickEvent, new RoutedEventHandler(OnButton4Click));
}
需要注意的是,由于按钮控件对Click高级事件的引入,Button类对MouseLeftButtonDown事件的监听不再有效。这是因为该事件的响应函数OnMouseLeftButtonDown通过更改带入参数的Handled成员为true将该事件标记为已处理。如果程序仍需对该事件进行响应,则需要使用AddHandler标识对已响应函数的处理:
button.AddHandler(Button.MouseRightButtonDownEvent, new RoutedEventHandler(OnLeftButtonDownCSharp),true);//监听右键点击
Button类较基类增加了IsCancel、IsDefault、IsDefaulted三个属性:
- IsCancel=“true”时,按下Esc键将触发该按钮的Click事件;
- IsDefault=“true”,该按钮在默认情况下具有输入焦点,并在当前焦点不在其他响应回车键的空间上时,对用户敲击回车键进行响应;
- IsDefaulted是一个只读属性,当前按钮是默认按钮且不具有当前输入焦点时其值为true,否则为false。
<StackPanel Width="100" FocusManager.FocusedElement="{Binding ElementName=defaultButton}">
<TextBox />
<Button Content="Default" IsDefault="True" Name="defaultButton" Click="OnDefault"/>
<Button Content="Cancel" IsCancel="True" Name="cancelButton" Click="OnCancel"/>
<Button Content="Empty"/>
</StackPanel>
public void OnDefault(object sender, RoutedEventArgs args)
{
if (defaultButton.IsDefaulted)
MessageBox.Show("Default Button Clicked!");
}
public void OnCancel(object sender, RoutedEventArgs args)
{
Close();
}
仅输入焦点在TextBox时,回车触发显示“Default Button Clicked!”;单击Cancel按钮或按Esc退出。
<StackPanel DockPanel.Dock="Top" HorizontalAlignment="Stretch" Height="45">
<RadioButton IsChecked="True">Radio1</RadioButton>
<RadioButton IsChecked="True">Radio2</RadioButton>
<RadioButton>Radio3</RadioButton>
</StackPanel>
而当指定了GroupName后,具有相关该属性的RadioButton互斥,与是否为同一节点的同级孩子无关。
Label和TextBlock不同:
功能上来说,Label较TextBlock最大额不同是拥有焦点设置功能。而且TextBlock中承载字符的属性是Text,该属性为String类型;而Label中承载字符的属性为Content,接受所有派生自Object的实例。
从视觉树的组成来看,Label对字符的显示是通过TextBlock来完成的,因此其运行时速度较慢。
ToolTip:
ToolTip用来完成界面显示功能,该类可以在鼠标移到控件上时显示,提供相关信息,且在鼠标离开界面元素后自动消失。
GroupBox常用来将多个相似的元素归类到同一个组里以显示他们之间的关联。GroupBox的Header可以接受任何自Object派生的类实例,因此可以将Header设置成任何UIElement派生出的类。
由于GroupBox使用Content承载需要的内容而不是一个集合类型的属性,因此它只能承载单一的Object类或其派生类的实例。在需要显示多个对象时,要通过某种布局控件将他们组织在一起,如StackPanel、DockPanel。
Expander:
Expander与GroupBox类似,只是包含了一个控制它所记录的信息显示或隐藏的按钮,其打开方向由属性ExpandDirection设置,其值为Left、Right、Up、Down。ExpandDirectionLeft、Right时,不能设置Expander的Width、MaxWidth等属性,同样当该值为Up、Down时不能设置Hight、MaxHight。当属性IsExpanded变化时,触发Expanded和Collapse事件。