这一章介绍Control 控件。
本章共计51个示例,全都在VS2008下.NET3.5测试通过,点击这里下载: Controls.rar
关于在VS2008新建WPF类库时,有Custom Control和User Control两个选择。
User Control类库会在工程中建立一个XAML文件及其绑定后台代码,前者以<UserControl开头,后者是一个派生自UserControl的类。
Custom Control类库则在工程中创建派生自Control基类的CustomControl1控件,并在构造函数中为CustomControl1指定依赖属性DefaultStyleKeyProperty:Custom Control类库还会在Theme目录下生成Generic.xaml,这是一个以<ResourceDictionary开头的文件,里面存放着CustomControl1的控件模板。
{
static CustomControl1()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
}
此外,
1.AccessText
这个例子介绍了AccessText元素的使用,以及如何指定一个访问键。
AccessText标记可以使用在任何控件中,如Button、Label等,通过在字母前加一个下划线指定该字母为访问键。连着两个下划线,可以显示一个下划线。
还有就是本例是以StackPanel开始的,并不是一个传统的Page或Window——所有的布局控件都可以这么使用。相应的后台代码文件要继承StackPanel。VS2008目前还不支持创建这样的文件,只有手动设置。例如一个VS2008创建的一个名为Pane1的Page,先修改页面标记Page为StackPanel,这时,后台的Page1.g.i.cs文件会自动改为Pane1:StackPanel,然后再修改Pane1.xaml.cs文件,使Pane1继承于StackPanel。这样就建立了一个所谓的StackPanel控件。
小技巧,在VS2008中,以StackPanel开始的页面的Design视图是没有滚动条的,这就只能看到左上部分——如果xaml内容很多的话,我们可以使用Design视图右上角的“比例尺”,缩小比例可以看到全部试图。
2.BtnColor
按钮中可以放入任何控件,如image。
注意到OnClick4方法。由于设置了背景色,所以按钮点击后的效果看上去像是一个颜色渐变的动画。这是由WPF本身提供的,即使是不设置背景色,点击后也会有颜色渐变效果,只是不太明显而已。
最后一个按钮的点击事件,创建了一个新的按钮加入到XAML控件树中,这与传统的WinForm模型是一致的。
仍然是最后一个按钮,按钮并没有Name值——这是允许的,也会在编译时被序列化,只是这个按钮的Name值为空,而其它属性都还是存在的。
3.BtnStyles
这个示例使用Application级别的资源为Button设定样式。
注意Button标签中Style="{StaticResource SystemResStyle}的使用,以及<Application.Resources>中样式资源,有3种:
一种是直接的键值对,是静态的:
<Setter Property = "Foreground" Value= "DarkBlue"/>
一种是使用WPF内嵌的资源,是动态的:
<Setter Property = "FontWeight" Value= "{DynamicResource {x:Static SystemFonts.MessageFontWeightKey}}"/>
还有一种是触发器,当条件满足时,属性会相应改变:
<Style.Triggers>
<Trigger Property="Button.IsMouseOver" Value="true">
<Setter Property = "Background" Value="Red"/>
</Trigger>
<Trigger Property="Button.IsPressed" Value="true">
<Setter Property = "Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
4.BulletPanel
Bullet用于绘制一组对象的列表。原有的BulletPanel标签已经被BulletDecorator取代。
Bullet中可以放置任何UI元素,如CheckBox、TextBox、RadioButton、Image、TextBlock以及任何Shape。下面是一个标准的用法:
<BulletDecorator >
<BulletDecorator.Bullet>
<Image Source="images"apple.jpg"/>
</BulletDecorator.Bullet>
<TextBlock Name="FontSizeExample">XXX</TextBlock>
</BulletDecorator>
这里把Image作为Bullet,而把TextBlock作为BulletDecorator的子一级元素。Image和TextBlock是可以互换的,没有区别,但是标签<BulletDecorator.Bullet>中只能有一个UI元素。
WindowLoaded负责创建一个BulletDecorator控件,也就是图中左下角的那个。其中创建一个BitmapImage的代码如下:
BitmapImage myBitmapImage = new BitmapImage();
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri(@"pack://application:,,/images/apple.jpg");
myBitmapImage.EndInit();
——这是值得我们学习的。
*补注:面板本身没有文本内容,它们是其他元素的矩形容器。总共有七种面板,每种的布局都不同:BulletPanel、Canvas、DockPanel、Grid、StackPanel、TabPanel和ToolBarOverflowPanel。面板可以层层嵌套。
5.CheckBoxElement
WPF对多选框控件也提供了同样的支持,只是更加简单,每个条目都是一个CheckBox,有自己的Name,以及可以内嵌其它控件。
CheckBox的Checked和Unchecked事件,分别当该条目被选中和被取消选中时触发。
6.CheckBoxStyles
这个示例使用Application级别的资源为CheckBox设定样式。
具体参见示例4 BtnStyles
7.ComboBoxItems
这个示例分为两部分。
首先是ComboBoxItems的显示,以下是部分截取的代码:
<ComboBox Name="cb"….
IsEditable="true" Text="Open Combo Box" IsReadOnly="true"
StaysOpenOnEdit="true" IsDropDownOpen="true">
<ComboBoxItem>Spain - Item 0</ComboBoxItem>
</ComboBox>
它的Text属性是默认的显示值,只在初始的时候作为默认选中项显示,当选中列表中一项时,这和个Text属性值就不再存在了。
IsEditable和IsReadOnly属性共同决定了选项是否可以更改,但改动过的值不会影响该项原先的值——已经存储在后台,必须写代码进行手动修改。
StaysOpenOnEdit属性决定了在编辑时——也就是光标定位在ComboBox的文本框时,下拉框是否仍然显示。
IsDropDownOpen属性决定了默认下拉框是否为打开的,比如说窗体第一次显示时。
其次,就是那个Menu控件的作用了——通过MenuItem的Click事件,根据MenuItem的Header值,也就是ComboBox中相应的索引值,来决定显示哪一个ComboBoxItem。
ComboBoxItem cbi = (ComboBoxItem)
(cb.ItemContainerGenerator.ContainerFromIndex(index));
这条语句重新得到了该索引的ComboBoxItem。
8.ComboBoxSimple
这个例子和示例-8是一样的,从略。
9.ComboBoxStyles
这个例子演示了4个不同样式的ComboBox。这些样式来自Apllication级别。
第一个是SimplePlus样式,设定了默认打开下拉列表(IsDropDownOpen=true)和下拉列表的高度(MaxDropDownHeight=30)。
第二个是Simple样式,设定了前景色和背景色。
第三个仍然使用Simple样式,但给其内部的ComboBoxItem使用SimpleComboBoxItem样式,这就覆盖了之前设置的样式。
最后一个使用了触发器。这使得当鼠标移动到ComboBoxItem时,相应的选项会发生变化。
10.ContentControl
ContentControl表示包含单项内容的控件,这是一个基类,很多控件都派生于此,如Frame、ListBoxItem、Window等等。我们也可以直接使用它。
ContentControl具有有限的默认样式,为此我们要额外设计样式以及控件模板:
<Style x:Key="ContentCtrl" TargetType="{x:Type ContentControl}">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentControl ContentControl.Content="Hello"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这就添加了前景色、字体大小和宽度、以及一个指定了显示内容的控件模板,那么第一个ContentControl就使用这套样式:
<ContentControl Style="{StaticResource ContentCtrl}"/>
或者创建一个新的数据模板,
<DataTemplate x:Key="template1">
<TextBlock Text="{Binding}" FontSize="12" FontWeight="Bold" TextWrapping="Wrap"></TextBlock>
</DataTemplate>
第二个ContentControl使用了这个模板:
<ContentControl Name="contCtrl" ContentTemplate="{StaticResource template1}"
注:DataTemplate不仅仅用于数据绑定
此外,ContentControl有一个HasContent属性,用以判断控件的Content是否有值。
11.ContextMenu
这个例子演示了ContextMenu的种种用法。
我们可以把ContextMenu捆绑到Button上:
<Button Name="cmButton" Height="30">Button with Context Menu
<Button.ContextMenu>
<ContextMenu Name="cm" Opened="OnOpened" Closed="OnClosed" StaysOpen="true">
<MenuItem Header="File"/>
<MenuItem Header="Recent Files">
<MenuItem Header="ReadMe.txt"/>
</MenuItem>
……
ContextMenu上可以设置OnOpened事件和OnClosed事件,分别发生在上下文菜单弹出和关闭时。StaysOpen属性为false,表示上下文菜只能弹出一次,当鼠标再次右击,不会再弹出;否则,不加限制。
还可以为MenuItem添加tooltip:
<MenuItem Header="Context Menu item with ToolTip">
<MenuItem.ToolTip>
<ToolTip>
Some information.
</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
或者在MenuItem中加入图片:
<MenuItem>
<MenuItem.Header>
<Image Source="data/cat.png"/>
</MenuItem.Header>
</MenuItem>
也可以为一个disabled的控件添加ContextMenu,比如说Button,只要设定它的属性:
ContextMenuService.ShowOnDisabled="True"
最后,就是在代码中动态添加一个ContextMenu,见OnClick方法。
12.ContextMenuShared
This example describes how to create a ContextMenu that can be associated with more than one control. For example the ContextMenu is associated with both a Button and a CheckBox.
这个例子演示了两个Button和两个CheckBox共享页面资源中同样的ContextMenu。
页面资源如下:
<ContextMenu x:Key="MyContextMenu" x:Shared="true">
<MenuItem Header="This MenuItem is checkable" IsCheckable="true" />
<Separator/>
<MenuItem Header="This is a regular MenuItem" />
</ContextMenu>
这里的关键是x:Shared,当设置为 false时,会修改 WPF资源检索行为,以便资源请求会为每个请求创建一个新实例,而不是所有请求共享同一个实例。
指定x:Shared="true"并不常见,因为这已经是默认行为,意味着任何给定资源请求都始终返回同一个实例。对于x:Shared,没有直接的代码等效项。
x:Shared只有在满足以下条件的情况下才是合法的:
·包含具有x:Shared的项的ResourceDictionary必须已编译。ResourceDictionary不能在松散XAML内或用于主题。(所以本例要指定x:Class)
·包含项的ResourceDictionary不得嵌套在另一个 ResourceDictionary内。例如,不能对已经是