本次将介绍控件——继承自System.Windows.Control类的元素。首先分析Control基类,并学习该类支持画刷和字体的原理。然后研究WPF控件的目录,包括以下控件:
- 内容控件——这些控件能够包含嵌套的元素,为它们提供几乎无限的显示能力。内容控件包括Label、Button以及ToolTip类。
- 带有标题的内容控件——这些空间是允许添加一个主要内容部分以及一个单独标题部分的内容控件。他们通常用于包装更大的用户界面块。这类控件包括TabItem、GroupBox以及Expander类。
- 文本控件——文本控件比较少,他们允许用户输入文本。文本控件支持普通文本、密码以及格式化文本。
- 列表控件——这些空间在列表中显示项目集合。列表控件包括ListBox和ComboBox类。
- 基于范围的控件——这些空间通常只关心一个属性:Value,可以使用预先规定范围内的任何数字设置该属性。
- 日期控件——这类控件包含两个允许用户选择日期的控件Calendar和DatePicker控件。
6.1 控件类
在WPF窗口充满了各种元素,但是这些元素中只有一部分是控件。在WPF中,控件通常被描述为和用户交互的元素——能够接收焦点并接受键盘或鼠标输入的元素。所有控件都继承自System.Windows.Control类,该类添加了一点基本的基础结构:
- 设置控件内容对齐方式
- 设置Tab键顺序的能力
- 支持绘制背景、前景和边框
- 支持格式化文本内容的尺寸和字体
6.1.1 背景画刷和前景画刷
所有的空间都包含背景和前景的概念。通常,背景是控件的表面,而前景是文本。在WPF中,分别使用Background和Foreground属性设置这两个区域的颜色。在WPF中Background和Foreground属性不像在Windows窗体应用程序总所做的那样。这些属性可以使用更强大的对象:Brush对象。该对象为填充背景和前景内容体统了灵活性,可以使用单一颜色(SolidColorBrush)或更特殊的颜色(LinearGradientBrush或TileBrush)填充背景和前景。此次只使用简单的SolidColorBrush画刷,之后学习更特殊的画刷。
我们可以用Colors类的静态属性预定义的颜色,创建一个新的SolidColorBrush画刷。然后将该画刷设置为控件的背景颜色。如下一个示例,将一个按钮的颜色设置为有轻微阴影的蓝色
cmd.Background=new SolidColorBrush(Colors.AliceBlue);
也可以从System.Windows.SystemColors枚举中获取系统颜色。
cmd.Background=new SolidColorBrush(SystemColors.ControlColor);
因为系统画刷经常使用,所以SystemColors类还提供了预定义的返回SolidColorBrush对象的属性。cmd.Background=SystemColors.ControlBrush;
Colors和SystemColors类提供了便捷的方法,但这并不是设置颜色的唯一方法。也可以通过提供R、G、B创建一个Color对象。这三个值都是0-255之间的数字:
int red=0; int green=255; int blue=0; cmd.Foreground=new SolidColorBrush(Color.FromRgb(red,green,blue));
也可以通过提供一个Alpha值,并调用Color.FromArgb()方法创建部分透明的颜色,Alpha值255表示完全不透明,0表示不透明。
在XAML中设置背景色和前景色时,可以使用一个非常有用的快捷方式。不是定义一个Brush对象,而是提供一个颜色名或颜色值。WPF解析器会自动使用指定的颜色创建一个SolidColorBrush对象,并为前景或背景使用该画刷对象。下面是一个使用颜色名的示例:
<Button Background="Red">A Button</Button> <Button>A Button <Button.Background> <SolidColorBrush Color="Red"/> </Button.Background> </Button>
如果希望使用颜色代码,就需要使用稍微有些不方便的语法,以十六进制方式设置R、G和B的值。可以使用两种格式中的任意一种—#rrggbb或#aarrggbb(区别为后者中格式包含了alpha值)。
使用画刷不仅可以设置Background和Foreground属性。还可以使用BorderBrush和BorderThickness属性在控件(以及其他元素)周围绘制一个边框。BorderBrush属性使用所选的画刷,而BorderThickness属性使用设备无关单位的边框宽度值。在显示边框前要设置这两个属性。
6.1.2 字体
Control类定义了一小部分与字体相关的属性,这些属性确定文本在控件中的显示方式。
FontFamily | 希望使用的字体的名称 |
FontSize | 字体的设备无关单位尺寸。 |
FontStyle | 由FontStyle对象表示的文本角度。可以从FontStyles类的静态属性中获取需要的预定义FontStyle对象,包括Normal、Italic或Oblique字母 |
FontWeight | 由FontWeight对象表示的文本重量。可以从FontWeight类的静态属性中获取需要的预定义FontWeight对象。 |
FontStretch | 字体被拉伸或压缩的程度,由FontStretch对象表示。 |
FontFamily——相关字体的集合。当选择字体时,必须提供完整的字体家族名称,如下:
<Button Name="cmd" FontFamily="Times New Roman" FontSize="18">A Button</Button>
也可以使用代码:cmd.FontFamily="Times New Roman";cmd.FontSize="18";
文本装饰和排版——有些元素还可以通过TextDecorations和Typograhpy属性,支持更高级的文本控制。这些属性可以修饰文本。例如:TextDecorations类的静态属性设置TextDecorations属性。该类提供了4种修饰,每种都可以为文本添加几类线(Baseline、Overline、Strikethrough、Underline)。Typography属性更高级:通过该属性可以访问只有某些字体才会提供的特殊的字体变种。对于大多数情况,TextDecorations和Typograhpy特征只用于刘文档内容——用于创建丰富的可读的文档。然而,这些属性也可以用于TextBox类。此外,TextBlock元素也支持它们。
字体继承——当设置任何字体属性时,属性值都会流经嵌套的对象。例如:如果为顶级窗口设置了FontFamily属性,窗口中的所有空间按都会得到相同的FontFamily属性值。这一特性和Windows窗体中的环境属性类似,但是背后的工作原理不同。之所以会这样是因为字体属性石依赖项属性,并且依赖项属性能搞提供的特性之一就是属性值继承。
字体替换——当设置字体时,一定要谨慎,确保选择的字体在用户计算机上已经存在。然而,WPF没有通过字体回调系统提供一点灵活性。可以将FontFamily属性设置为一个由逗号分割的字体选择列表。如下:
<Button FontFamily="Technical Italic, Comic Sans MS, Arial">A Button</Button>
如果某个字体家族的名称中确实包含一个逗号,则需要通过在一行中包含它两次来转义该逗号。此外使用System.Windows.Media.Fonts类的静态的SystemFontFamilies集合,可以获得在当前计算机上已安装的所有自提的列表。如下,是将该集合添加到一个列表框中
foreach(FontFamily fontFamily in Fonts.SystemFontFamilies) { lstFonts.Items.Add(fontFamily.Source); }
FontFamily对象还允许其他检查其它细节,如行间距和关联的字体。
文本格式化模式—— WPF中文本渲染和来的基于GDI的应用程序的文本渲染有很大的区别。有很大一部分区别是由于WPF的设备无关显示系统造成的,但是WPF中的文本渲染也得到了显著的增强,能更清晰得显示文本。在WPF中显示比较小的文本尺寸时,文本会变得模糊,并且会显示一些令人讨厌的问题。为了使用GDI风格的文本渲染,为显示文本的元素,增加了TextOptions.TextFormattingMode附加属性,并且将其设置为Display
<TextBlock FontSize="12" Margin="5"> This is a Test. Ideal text is blurry at small sizes. </TextBlock> <TextBlock FontSize="12" Margin="5" TextOptions.TextFormattingMode="Display"> This is a Test. Display text is crisp at small sizes. </TextBlock>
鼠标光标——对于任何应用程序一个常见的任务是,调整鼠标光标以指
但是要记住TextFormattingMode仅是针对小尺寸文本的解决方案。示当前应用程序正处于繁忙状态或指示不同控件的工作方式。可以为任何元素使用Cursor属性设置鼠标指针,该属性继承自FrameworkElement类。每个光标通过一个System.Windows.Input.Cursor对象表示。获取Cursor对象的最简单方法是使用Cursors类的静态属性。它包含所有标准的Windows鼠标光标。如下将当前窗口的鼠标光标设置为沙漏光标:
this.Cursor=Cursors.Wait;
如果使用XAML设置鼠标光标,就不需要直接使用Cursors类。因为Cursor属性的类型转换器能够识别属性名称,并从Cursors类中检索对应的鼠标光标。如下是一个帮助光标按钮
<Button Cursor="Help">Help</Button>
通过使用ForceCursor属性,父元素可以覆盖子元素的光标设置。当把该属性设置为true时,会忽略子元素的Cursor属性,并且父元素的光标会被应用到内部的所有内容。
6.2 内容控件
内容控件是更特殊的控件类型,他们可以包含一块内容。从技术角度讲,内容控件是可以包含单个嵌套元素的控件。所有WPF布局容器都继承自抽象的Panel类,该类提供了对包含多个元素的支持。类似的,所有内容控件都继承自抽象的ContentControl类。
6.2.1 Content属性
与Panel类提供一个Children集合来保存嵌套的元素不同,Control类添加了一个Content属性,该属性只接受单一对象。Content属性支持任何类型的对象,但是可以将该属性包含的对象分为两大类,针对每一类进行不同的处理:
- 未继承自UIElement类的对象:内容控件调用这些控件的ToString()方法获取文本,然后显示该文本。
- 继承自UIElement类的对象:这些对象(包括所有的可视化元素,它们是WPF组成部分)使用UIElement.OnRender()方法在内容控件内部进行显示
如下的示例:
<StackPanel Margin="3"> <Button Margin="3">Text button</Button> <Button Margin="3"> <Image Source="happyface.jpg" Stretch="None" /> </Button> <Button Margin="3"> <StackPanel> <TextBlock Margin="3">Image and text button</TextBlock> <Image Source="happyface.jpg" Stretch="None" /> <TextBlock Margin="3" >Courtesy of the StackPanel</TextBlock> </StackPanel> </Button> <Button Padding="3" Margin="3" HorizontalContentAlignment="Stretch"> <StackPanel> <TextBlock Margin="3">Type something here:</TextBlock> <TextBox Margin="3" HorizontalAlignment="Stretch">Text box in a button</TextBox> </StackPanel> </Button> </StackPanel>
6.2.2 对齐内容
通过使用HorizontalContentAlignment和VerticalContentAlignment属性属性内容控件中的内容如何和其边框对齐。我们可以通过这两个属性将内容对齐到控件的任意边缘(TOP、Bottom、Left、Right),可以居中(Center),或者可以拉伸内容使其充满可用空间(Strech)。这些设置被直接应用于嵌套的内容元素,但是可以使用多层嵌套创建复杂布局。
6.2.3 标签
所有内容控件中最简单的是Label控件。其他任何内容控件类似,Label控件接受希望放入其中的单一内容。但不同的是Label控件支持记忆符——本质上,记忆符是能够为链接的控件设置焦点的快捷键。为支持此功能,Label控件添加了一个Target属性。为了设置Target属性,需要使用一个指向另一个控件的绑定表达式,所有记忆符都是使用Alt键和已确定的快捷键工作。如下:
<Label Target="{Binding ElementName=txtA}">Choose _A</Label> <TextBox Name="txtA"></TextBox> <Label Target="{Binding ElementName=txtB}">Choose _B</Label> <TextBox Name="txtB"></TextBox>
6.2.4 按钮
WPF提供了三种类型的按钮控件:熟悉的Button控件、CheckBox控件和RadioButton控件。所有这些控件都继承自ButtonBase类的内容控件。ButtonBase类增加了几个成员。定义了Click事件并添加了对命令的支持,从而允许为更高层的应用程序任务触发按钮。ButtonBase类添加了一个ClickMode属性,该属性决定何时引发Click事件以引发Click事件以响应鼠标动作。默认值是ClickMode.Release(单击鼠标并释放时触发Click事件),ClickMode.Press是第一次按下时引发,ClickMode.Hover是在按钮上悬停一会儿就触发。
Button控件——Button类表示一直使用的Windows下压按钮。它添加了两个可写属性:IsCancel和IsDefault。
- 如果IsCancel属性设置为true,按钮就成为窗口的取消按钮,在当前窗口的任何文职如果按下Esc键,就会触发该按钮。
- 如果IsDefault属性设置为true,按钮就会成为默认按钮。它的行为取决于焦点在窗口中的当前位置。
ToggleButton控件和RepeatButton控件——除了Button类之外,还有三个继承自ButtonBase类。
- GridViewColumnHeader类,当使用一个基于网格的ListView控件时,该类表示一列可以单机的标题。
- RepeatButton类,只要按钮保持按下状态,该类就不断的触发Click事件。
- ToggleButton类,该类表示具有两个状态的按钮,当单击ToggleButton按钮时,它会保持按下状态知道再次单击该按钮已释放它。有时称为“黏贴单击”行为。
CheckBox控件——CheckBox控件和RadioButton控件是不同类型的按钮。他们继承自ToggleButton类,这意味着用户可以切换他们的开与关状态。对于CheckBox控件切换到控件的“开”状态,意味着在其中放置了一个复选标记。ToggleButton类添加了IsChecked属性。IsChecked属性是一个可空的boolean类型,这意味着该属性可以设置为true、false、null。ToggleButton类还添加了IsThreeState属性,该属性决定了用户是否能够将复选框设置为不确定状态,如果IsThreeState属性为false,只有选择和未选择两种状态,如果IsThreeState属性为true,则会有不确定的状态。ToggleButton还定义了Checked、UnChecked、Indeterminate三个事件。
RadioButton控件——RadioButton控件也继承自ToggleButton类,并且使用相同的IsChecked属性和相同的Checked、UnChecked以及Indeterminate事件。另外,RadioButton类还增加了GroupName属性,该属性用于控制如何对单选按钮进行分组。如下示例:
<StackPanel> <GroupBox Margin="5"> <StackPanel> <RadioButton>Group 1</RadioButton> <RadioButton>Group 1</RadioButton> <RadioButton>Group 1</RadioButton> <RadioButton Margin="0,10,0,0" GroupName="Group2">Group 2</RadioButton> </StackPanel> </GroupBox> <GroupBox Margin="5"> <StackPanel> <RadioButton>Group 3</RadioButton> <RadioButton>Group 3</RadioButton> <RadioButton>Group 3</RadioButton> <RadioButton Margin="0,10,0,0" GroupName="Group2">Group 2</RadioButton> </StackPanel> </GroupBox> </StackPanel>
6.2.5 工具提示
在WPF中为工具提示(tooltip)提供了一个灵活的模型,因为在WPF中工具提示是内容控件,所以可以在工具提示中放置任何可视化元素。还可以改变各种时间设置来控制工具提示的显示和隐藏速度。我们可以为元素简单的设置Tooltip属性,ToolTip属性是在FrameworkElement类中定义的,所以所有可以放置到窗口上的元素都可以使用ToolTip属性。如下:
<Button ToolTip="This is my tooltip" ToolTipService.InitialShowDelay="5000">I have a tooltip</Button>
如果我们希望提供更复杂的工具提示内容,就需要将ToolTip属性分为单独的元素如下:
<Button ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="5000"> <Button.ToolTip> <ToolTip Background="#60AA4030" Foreground="White" HasDropShadow="False" > <StackPanel> <TextBlock Margin="3" >Image and text</TextBlock> <Image Source="happyface.jpg" Stretch="None" /> <TextBlock Margin="3" >Image and text</TextBlock> </StackPanel> </ToolTip> </Button.ToolTip> <Button.Content>I have a fancy tooltip</Button.Content> </Button>
设置ToolTip对象的属性——ToolTip是一个内容控件,所以可以调整它的标准属性,如Background属性、Padding属性和Font属性。还可以修改ToolTip类中定义的成员,如下:
HasDropShadow | 决定工具提示是否具有扩散的黑色阴影,使其和背后的窗口区别开来。 |
Placement | 使用一个PlacementMode枚举值决定如何放置工具提示。Mouse:表示工具提示方框的左上角与当前鼠标的位置相关其他枚举值使用绝对屏幕坐标来设置工具提示的位置,或相对于其他元素设置工具提示的位置。 |
HorizontalOffset和VerticalOffset | 将工具提示为跳到所希望的位置。可以使用正值和负值。 |
PlacementTarget | 允许相对于另一个元素定位工具提示。为了使用该属性,Placement属性必须设置为Left、Right、Top、Bottom或Center。 |
CustomPopupPlacementCallback | 允许使用代码动态地定位工具提示。如果Placement属性被设置为Custom,此属性确定由TooTip调用来获取ToolTip对象放置位置的方法。回调方法接收三部分信息——popupSize(ToolTip的大小)、targetSize(PlacementTarget的大小)和offset(根据HorizontalOffset和VerticalOffset属性创建的一个点)。该方法返回一个CustomPopupPlacement对象,该对象告诉WPF将工具提示放在什么位置。 |
StaysOpen | 该属性实际上不起作用。它的目的是让你创建一个直保持打开状态的工具提示,直到用户在其他地方点击鼠标位置。然而,ToolTipService.ShowDuration属性覆盖了StaysOpen属性。因此,在经历了设置的时间之后或当用户移开鼠标时,工具提示总是会消失。如果希望创建一个始终保持打开状态的类似工具提示的窗口,最简单的方法是使用Popup控件 |
IsEnabled和IsOpen | IsEnabled属性可以暂时禁用工具提示,而通过IsOpen水洗那个可以使用代码控制工具提示的显示和隐藏。 |
ToolTipService属性——有几个工具提示属性不能通过ToolTip类的属性进行配置。对此,需要使用另一个类ToolTipService类。使用ToolTipService类可以配置显示工具提示的相关延迟时间。ToolTipService类的所有属性都是附加属性,所以尅在控件标签中直接设置他们。ToolTipService类定义了许多与ToolTip相同的属性,从而当处理只有文本的工具提示时可以使用更简单的语法。,不是添加一个嵌套的TooTip元素,可以使用特性设置所有内容:
<Button ToolTip="This tooltip is alined with the bottom edge" ToolTipService.Placement="Bottom">I have a tooltip</Button>
ToolTipService类还提供了两个路由事件:ToolTipOpening和ToolTipClosing。可以响应这些事件使用即使内容填充工具提示,或重写工具提示的工作方式。下面是ToolTipService类的属性:
InitialShowDelay | 设置当鼠标悬停在元素上时,工具提示显示之前的延迟时间 |
ShowDuration | 设置如果用户不移动鼠标,在工具提示消失之前显示的时间 |
BetweenShowDelay | 设置一个时间间隔,在该期间用户可以在工具提示之间移动而不用经历InitialShowDelay属性设置的延迟时间。 |
ToolTip | 为工具提示设置内容。设置ToolTipService.ToolTip属性相当于设置元素的FrameworkElement.ToolTip属性 |
HasDropShadow | 确定工具提示是否具有扩散的黑色阴影,从而使其与背后的窗口相互区别 |
ShowOnDisabled | 确定当相关联的元素被禁用后是否显示工具提示。如果该属性为true,将为禁用的元素显示工具提示。默认为false。 |
Placement、PlacementTarget、PlacementRectangle以及VerticalOffset | 这些属性用于控制工具提示的位置,用法与ToolTip属性一样 |
Popup控件——Popup也只能包含单一内容,该单一内容可以包含任何WPF元素。另外,和ToolTip控件一样,Popup控件也可以延伸出窗口的边界,可以使用相同的布局属性放置Popup控件,并且可以使用相同的IsOpen属性显示或隐藏Popup控件。Popup控件和ToolTop控件之间的区别更重要,下面是他们的区别:
- Popup控件永远不会自动显示。为了显示Popup控件必须设置IsOpen属性。
- 默认情况下,Popup.StaysOpen水洗那个被设置为true,并且Popup控件会一直显示,直到明确的将IsOpen属性设置为false为止。如果Popup.StaysOpen属性设置为false,当用户在其他地方单机鼠标时,Popup控件就会消失。
- Popup控件提供了一个PopupAnimation属性,当把IsOpen属性设置为true时,通过该属性可以控制Popup控件进入视野的方式。None是默认方式,Fade是弹出窗口的透明度逐渐增加,Scroll是在足够的空间内,弹出窗口将从窗口的左上角滑入,Slide在足够的空间内,弹出窗口将从上向下滑进其位置。为了使用这些动画,还要将AllowsTransparency属性设置为true。
- Popup控件可以接收焦点。因此可以在其内部放置与用户交互的控件;该功能是使用Popup控件的主要原因。
- Popup控件在System.Windows.Controls.Primitive名称空间中定义的,因为它的最常见用法是用作更复杂控件的构建。在外观修饰方面可以发现Popup控件和其他控件的区别。如果希望看到内容,必须设置Background属性,因为Popup控件不会从包含它的窗口继承背景设置,并且需要自己添加边框。
因为必须手动显示Popup控件,所以您可能会完全通过代码创建它,也可以用XAML标记定义Popup控件——但要确保包含Name属性,从而可以使用代码操纵该控件。如下示例:
//XAML部分 <TextBlock TextWrapping="Wrap">You can use a Popup to provide a link for a specific <Run TextDecorations="Underline" MouseEnter="run_MouseEnter" >term</Run> of interest.</TextBlock> <Popup Name="popLink" StaysOpen="False" Placement="Mouse" MaxWidth="200" PopupAnimation="Slide" AllowsTransparency = "True"> <Border BorderBrush="Beige" BorderThickness="2" Background="White"> <TextBlock Margin="10" TextWrapping="Wrap" > For more information, see <Hyperlink NavigateUri="http://en.wikipedia.org/wiki/Term" Click="lnk_Click">Wikipedia</Hyperlink> </TextBlock> </Border> </Popup> //代码部分 private void run_MouseEnter(object sender, MouseEventArgs e) { popLink.IsOpen = true; } private void lnk_Click(object sender, RoutedEventArgs e) { Process.Start(((Hyperlink)sender).NavigateUri.ToString()); }
6.3 特殊容器控件
ScrollViewer控件——如果希望让大量的内容适应有限的空间,滚动是一个重要特性。在WPF中为了获得活动支持,需要在ScrollViewer控件中包装希望滚动的内容。尽管ScrollViewer控件可以包含任何内容,但是通常使用它包含一个布局容器。如下示例:
<ScrollViewer Name="scroller"> <Grid Margin="0,10,0,0" Focusable="False"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"></ColumnDefinition> <ColumnDefinition Width="*" MinWidth="50" MaxWidth="800"></ColumnDefinition> <ColumnDefinition Width="Auto"></ColumnDefinition> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Margin="3" VerticalAlignment="Center">Home:</Label> <TextBox Grid.Row="0" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="0" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="1" Grid.Column="0" Margin="3" VerticalAlignment="Center">Network:</Label> <TextBox Grid.Row="1" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="1" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="2" Grid.Column="0" Margin="3" VerticalAlignment="Center">Web:</Label> <TextBox Grid.Row="2" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="2" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="3" Grid.Column="0" Margin="3" VerticalAlignment="Center">Secondary:</Label> <TextBox Grid.Row="3" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="3" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="4" Grid.Column="0" Margin="3" VerticalAlignment="Center">Home:</Label> <TextBox Grid.Row="4" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="4" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="5" Grid.Column="0" Margin="3" VerticalAlignment="Center">Network:</Label> <TextBox Grid.Row="5" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="5" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="6" Grid.Column="0" Margin="3" VerticalAlignment="Center">Web:</Label> <TextBox Grid.Row="6" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="6" Grid.Column="2" Margin="3" Padding="2">Browse</Button> <Label Grid.Row="7" Grid.Column="0" Margin="3" VerticalAlignment="Center">Secondary:</Label> <TextBox Grid.Row="7" Grid.Column="1" Margin="3" Height="Auto" VerticalAlignment="Center"></TextBox> <Button Grid.Row="7" Grid.Column="2" Margin="3" Padding="2">Browse</Button> </Grid> </ScrollViewer>
ScrollViewer控件的VerticalScrollBarVisbility属性控制滚动条的显示方式,如:当窗口不足以显示所有内容时,显示滚动条,当窗口足够显示内容时消失,就把VerticalScrollBarVisbility属性设置为Auto;Visible是总是显示滚动条;Disable是不显示滚动条。ScrollViewer控件也支持水平滚动条,但默认是垂直方向,我们可以把HorizontalScrollBarVisibility属性设置为Auto,默认是Hidden。
代码滚动——我们除了用鼠标滚动ScrollViewer控件外,还可以用代码的方式进行操作,LineUp()和LineDown(),这两个方法向上和向下移动的效果相当于单击一次垂直滚动条两端的箭头按钮。PageUp()和PageDown()方法是向上和向下滚动一屏。用于水平滚动的方法是LineLeft、LineRight、PageLeft()、PageRight()。还有ScrollToXxx()一类的方法,以滚动到特定的位置。对于垂直滚动,包括ScrollToEnd()和ScrollToHome(),这两个方法可以滚动到内容的顶部和底部。还有ScrollToVerticalOffset,该方法可以滚动到特定的位置。对于水平滚动类似的方法有ScrollToLeftEnd()、ScrollToRightEnd()、ScrollToHorizontalOffset()。
自定义滚动——ScrollViewer控件内置的滚动功能是很有用的。该功能允许慢慢地滚动任何内容,从复杂的矢量图形乃至元素网格。ScrollViewer控件最奇特的特征是它允许所包含的内哦内容参与滚动过程。
- 在ScrollViewer控件中放置一个能够滚动的元素。可以是任何实现了IScrollInfo接口的任意元素。
- 通过将ScrollViewer.CanContentScroll属性设置为true,告诉ScrollViewer控件其内容知道如何进行滚动。
- 当和ScrollViewer控件进行交互时,ScrollViewer控件通过IScrollInfo接口来调用元素的恰当方法。然后元素执行它自己的自定义滚动功能。
<ScrollViewer CanContentScroll="True"> <StackPanel > <Button Height="100">1</Button> <Button Height="100">2</Button> <Button Height="100">3</Button> <Button Height="100">4</Button> </StackPanel> </ScrollViewer>
6.4 带标题的内容控件
HeaderedContentControl类是也是一个继承自ContentControl的类。他的角色很简单——表示同时具有单一元素内容和单一元素标题的容器。添加的标题正是HeaderedContentControl类和到目前为止介绍的内容控件的区别。有三个类继承自HeaderedContentControl类:GroupBox、TabItem和Expander。
6.4.1 GroupBox
GroupBox显示为一个具有圆角和标题的方框。如下示例:
<GroupBox Header="A GroupBox Test" Padding="5" Margin="5" VerticalAlignment="Top"> <StackPanel> <RadioButton Margin="3" Content="One" /> <RadioButton Margin="3" Content="Two" /> <RadioButton Margin="3" Content="Three" /> <Button Margin="3">Save</Button> </StackPanel> </GroupBox>
GroupBox仍然需要布局容器来布置内容。GroupBox控件经常用来对数量不多的相关控件进行分组。GroupBox控件没有提供内置功能,所以可以随意使用它。
6.4.2 TabItem
TabItem表示TabControl控件中的一页。TabItem类添加的唯一一个有意义的属性是IsSelected,该属性指示选项卡当前是否正显示在TabControl控件中。如下是一个简单示例:
<TabControl Margin="5"> <TabItem Header="Tab One"> <StackPanel Margin="3"> <CheckBox Margin="3">Setting One</CheckBox> <CheckBox Margin="3">Setting Two</CheckBox> <CheckBox Margin="3">Setting Three</CheckBox> </StackPanel> </TabItem> <TabItem Header="Tab Two"> </TabItem> </TabControl>
与Content属性一样,Header属性也可以接受任何类型的对象。继承自UIElement的类通过渲染来显示,对于内联文本以及其他所有对象则使用ToString()方法。这意味着可以创建一个组合或选项卡,在它们的标题中包含图形内容或任意元素。如下:
TabItem> <TabItem.Header> <StackPanel> <TextBlock Margin="3" >Image and Text Tab Title</TextBlock> <Image Source="happyface.jpg" Stretch="None" /> </StackPanel> </TabItem.Header> <StackPanel Margin="3"> <CheckBox Margin="3">Setting One</CheckBox> <CheckBox Margin="3">Setting Two</CheckBox> <CheckBox Margin="3">Setting Three</CheckBox> </StackPanel> </TabItem>
6.4.3 Expander
Expander控件,他包装了一块内容,通过单击一个小箭头按钮可以显示或隐藏所包含的内容。使用Expander控件非常简单,只需要在该控件内部包装希望使其能够折叠的内容。通常每个Expander控件开始都是折叠的,但是可以在标记中通过设置IsExpanded属性来改变这种行为。如下示例:
<StackPanel> <Expander Margin="5" Padding="5" Header="Region One" BorderThickness="1" BorderBrush="Black"> <Button Padding="3">Hidden Button One</Button> </Expander> <Expander Margin="5" Padding="5" Header="Region Two" BorderThickness="1" BorderBrush="Black"> <TextBlock TextWrapping="Wrap"> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam mi sapien, viverra et, lacinia varius, ullamcorper sed, sapien. Proin rutrum arcu vitae tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque libero dui, eleifend faucibus, auctor at, aliquet a, nulla. Nunc eros. Phasellus mauris nisi, eleifend nec, adipiscing nec, luctus nec, lacus. Aliquam justo metus, vestibulum non, accumsan id, hendrerit at, nibh. Praesent accumsan urna quis tortor. Proin erat libero, facilisis nec, rhoncus ut, malesuada ut, ipsum. Donec id nibh. </TextBlock> </Expander> <Expander Margin="5" Padding="5" Header="Region Three" IsExpanded="True" BorderThickness="1" BorderBrush="Black"> <Button Padding="3">Hidden Button Two</Button> </Expander> </StackPanel>
我们还可以选择扩展器的扩展方向。标准方向是Down,但是也可以将ExpandDirection属性设置为Up、Left或Right,箭头总是指向将要展开的方向。
通常,当展开一个Expander时,它会增大以适应所包含的内容。当所有内容都展开后,如果窗口不足以显示所有内容,这可能带来问题。下面是处理问题的几种方法:
- 为窗口设置最小尺寸(使用MinWidth和MinHeight属性),以确保窗口在最小时也可以适合所有内容。
- 设置窗口的SizeToContent属性,从而当打开或关闭Expander控件时,使窗口自动扩展为所需要的大小。通常将SizeToContent属性设置为Manual,但是也可以使用Width或Height,以使窗口为了适应所包含的内容在任意方向上扩展或收缩。
- 通过硬编码Expander控件的Height和Width属性来限制其尺寸。但当Expander控件中的内容太长时,可能会裁剪掉部分内容。
- 使用ScrollViewer控件创建一个可滚动的扩展区域。
6.5 文本控件
WPF提供了三个用于输入文本的控件:TextBox、RichTextBox和PasswordBox。PasswordBox控件直接继承自Control类。TextBox和RichTextBox控件间接继承自TextBoxBase类。文本框能够包含的内容类型是有限制的。TextBox控件总是存储字符串。PasswordBox控件也处理字符串内容(由Password属性提供),尽管为了减轻特定类型的攻击,它在内部使用SecureString属性。只有RichTextBox控件可以存储更复杂的内容:可以包含复杂元素组合的FlowDocument对象。
6.5.1 多行文本
通常,TextBox控件存储单行文本(可以通过设置MaxLength属性来限制字符的数量)。然而,去多情况下需要处理大量内容,从而会希望创建多行文本框。可以将TextWrapping属性设置为Wrap或WrapWithOverflow。如果将TextWrapping属性设置为Wrap,总会在控件的边缘换行,甚至会将一个特别长的单词放置在两行中。如果将TextWrapping属性设置为WrapWithOverflow,这时如果换行算法发没发现合适的位置进行换行,WrapWithOverflow就允许拉伸某些行超出边缘。为了能够自动在文本框中看到更多行文本,需要将尺寸设置得足够大。不应该设置一个硬编码的高度,而可以使用方便的MinLines和MaxLines属性。通过设置VerticalScrollBarVisibility属性设置为Visible或Auto,添加始终显示或按需显示的滚动条是有意义的。为了确保文本框支持Enter键,需要将AcceptsRuturn属性设置为true,也可以设置AcceptsTabs属性,从而允许用户插入Tab键,否则,Tab键会根据Tab焦点顺序将焦点移动到下一个可以得到焦点的控件上。IsReadOnly 属性设置是否可以编辑文本,IsEnabled属性设置是否禁用文本框。
6.5.2 选择文本
TextBox类还提供了使用SelectionStart、SelectionLength以及SelectedText属性,通过编程决定选择哪些文本或改变当前所选文本的能力。SelectionStart属性标识所选文本的开始位置,该位置是从0开始的。SelectionLength属性指示选中的字符的总数量。使用SelectedText属性可以快速检查或改变在文本框中选中的文本。可以通过处理SelectionChanged事件对文本选择变化做出响应。TextBox类还提供了一个可以控制文本选择行为的属性:AutoWordSelection。如果将该属性设为true,当在文本中拖动鼠标时文本框每次会选择整个单词。TextBox控件的另一个功能是UNDO,该功能允许用户撤销最近的操作。只要CanUndo属性没有设置为false,就可以通过代码获得Undo功能(调用Undo()方法),并且可以使用Ctlr+Z快捷键获得该功能。
6.5.3 拼写检查
TextBox的拼写检查功能会在文本中不能识别的单词下面添加红色的波浪线。用户可以右击不能识别的单词并从可能正确的单词列表中进行选择。要为TextBox控件开启拼写检查,只需要简单的设置SpellCheck.IsEnabled依赖项属性。如下:
<TextBox SpellCheck.IsEnbled="True">...</TextBox>
拼写检查是WPF特有的功能,并且该功能不依赖于其他软件。拼写检查根据为键盘配置的输入语言来决定使用哪个词典。WPF拼写检查目前只局限于:英语、西班牙语、法语和德语。
6.5.4 PasswordBox
PasswordBox通过显示一个圆圈符号字来屏蔽它的实际字符(可以设置PasswordChar属性改变隐藏字符)。PasswordBox不支持剪贴板,从而不能复制文本。PasswordBox控件提供了MaxLength属性;Clear()、Paste()以及SelectAll()方法;并且提供了一个当文本发生变化时触发的事件PasswordChanged事件。尽管可以使用password属性作为普通字符串读取和设置文本,但是在内部PasswordBox类只使用System.Security.SecureString对象。SecureString对象是一个纯文本对象。区别是在内存中的存储方式。SecureString已加密的方式在内存中保存。用于加密字符串的密钥是随机生成的,并且存储在一块从不会写入到磁盘的内存中。SecureString类还提供了根据需要丢弃内容的功能。当调用SecureString.Dispose()方法时,内存中的密码数据就会被重写。
6.6 列表控件
WPF提供了许多包装项目集合的控件,包括在本节介绍的ListBox和ComboBox控件以及更特殊的控件,例如:ListView、TreeView和ToolBar控件,这些控件将在以后介绍。所有的这些控件都继承自ItemsControl类(ItemsControl类本身又继承自Control类)。ItemsControl类添加了所有基于列表的控件都是用的基本功能。它提供了填充列表项的两种方式。最直接的方法是使用代码或XAML将列表直接添加到Items集合中。WPF中使用数据绑定的方式更为普遍。使用数据绑定方法,需要将ItemsSource属性设置为希望显示的具有数据项集合的对象。ItemsControl类之后的继承层次有些混乱。一个主要分支是选择器(selector),包括ListBox、ComboBox以及TabControl。这些控件都继承自Selector类,并且都具有跟踪当前选择项(SelectedItem)或其位置(SelectedIndex)的属性。包装列表项的控件是另一个分支,以不同的方式选择列表项。该分支包括用于菜单、工具栏以及树的类——所有这些类都属于ItemsControl但不是选择器。
6.6.1 ListBox
ListBox类代表了一种最常用的Windows设计——允许用户从长度可变的列表中选择一项。为向ListBox控件中添加项,可在ListBox元素中嵌套ListBoxItem元素。如下:
<ListBox> <ListBoxItem>Green</ListBoxItem> <ListBoxItem>Red</ListBoxItem> <ListBoxItem>Yellow</ListBoxItem> <ListBoxItem>Blue</ListBoxItem> </ListBox>
ListBox控件不仅可以包含ListBoxItem对象,还可以嵌套其他任意元素。因为ListBoxItem类继承自ContentControl类,从而ListBoxItem能够包含一段嵌套的内容。而且ListBox控件足够智能,它能够隐式的创建所需的ListBoxItem对象。这意味着可以直接在ListBox元素中放置对象。如下:
<ListBox Margin="5" SelectionMode="Multiple" Name="lst" SelectionChanged="lst_SelectionChanged"> <StackPanel Orientation="Horizontal"> <Image Source="happyface.jpg" Width="30" Height="30"></Image> <Label VerticalContentAlignment="Center">A happy face</Label> </StackPanel> <StackPanel Orientation="Horizontal"> <Image Source="redx.jpg" Width="30" Height="30"></Image> <Label VerticalContentAlignment="Center">A warning sign</Label> </StackPanel> <StackPanel Orientation="Horizontal"> <Image Source="happyface.jpg" Width="30" Height="30"></Image> <Label VerticalContentAlignment="Center">A happy face</Label> </StackPanel> </ListBox>
当在一个列表内部使用不同的元素时需要谨慎。当读取SelectedItem值时(以及SelectedIems和Items集合),看不到ListBoxItem对象——反而将看到放入到列表中的对象。下面的CheckedListBox示例:
//XAML部分 <ListBox Name="lst" SelectionChanged="lst_SelectionChanged" CheckBox.Click="lst_SelectionChanged" > <CheckBox Margin="3">Option 1</CheckBox> <CheckBox Margin="3">Option 2</CheckBox> <CheckBox Margin="3">Option 3</CheckBox> </ListBox> <StackPanel Grid.Row="1" Margin="0,10,0,0"> <TextBlock>Current selection: </TextBlock> <TextBlock Name="txtSelection" TextWrapping="Wrap"></TextBlock> <Button Margin="0,10,0,0" Click="cmd_CheckAllItems">Examine All Items</Button> </StackPanel> //代码部分 private void lst_SelectionChanged(object sender, RoutedEventArgs e) { if (e.OriginalSource is CheckBox) { lst.SelectedItem = e.OriginalSource; } if (lst.SelectedItem == null) return; txtSelection.Text = String.Format( "You chose item at position {0}. Checked state is {1}.", lst.SelectedIndex, ((CheckBox)lst.SelectedItem).IsChecked); } private void cmd_CheckAllItems(object sender, RoutedEventArgs e) { StringBuilder sb = new StringBuilder(); foreach (CheckBox item in lst.Items) { if (item.IsChecked == true) { sb.Append( item.Content + " is checked."); sb.Append(" "); } } txtSelection.Text = sb.ToString(); }
6.6.2 ComboBox
ComboBox控件和ListBox控件类似。该控件包含一个ComboBox对象的集合,即可显式的也可以隐式的创建该集合。与ListBoxItem类似,ComboBoxItem也是一个可以包含任何嵌套元素的内容控件。ComboBox控件使用下拉列表,一次只能选一个项目。如果希望用户在组合框中通过输入文本选择一个项目,必须将IsEditable属性设置为true,并且必须确保项目集合中存储的是普通的纯文本的ComboBoxItem对象,或者是提供了有意义的ToString()表示的对象。
6.7 基于范围的控件
WPF提供了三个使用范围概念的控件,这些控件使用一个在特定最小值和最大值之间的数值。这些控件——ScrollBar、 ProgressBar以及Slider都继承自RangeBase类(该类继承自Control类)。尽管它们使用相同的抽象概念,但是它们的工作方式却有很大的区别。RangeBase类定义的属性如下:
Value | 控件的当前值(必须在最大值和最小值之间)。默认从0开始。Value属性值不是整数——而是双精度浮点数,所以它接受小数值。如果当Value属性值发生变化时希望得到通知,可以响应ValueChanged事件 |
Maximum | 上限 |
Minimum | 下限 |
SmallChange | Value属性为"小变化"向上或向下调整的数量。小变化的含义和控件相关(而且有的控件可能根本不使用小变化)。对于ScrollBar和Slider控件,这是当使用箭头键时值改变的量,对于ScrollBar控件还可以使用滚动条两端的箭头按钮。 |
LargeChange | Value属性为"大变化"向上或向下调整的数量。大变化的含义和控件相关(而且有的控件可能根本不适用大变化)。对于ScrollBar和Slider控件,这是使用PageUp和PageDown键或单击滑块两侧时值改变的量 |
通常,不需要直接使用ScrollBar控件。高级的ScrollViewer控件(包装了两个ScrollBar控件)通常更有用。Slider和ProgressBar控件更实用,并且经常单独使用。
6.7.1 Slider控件
Slider控件是偶尔使用的特殊控件——例如,当数字本身不是特别重要时可以使用该控件设置数值。再比如,播放器的音量调节。Slider控件的重要属性是在RangeBase类中定义的。除了这些属性,还可以使用如下属性:
Orientation | 在竖直滑动和水平滑动条之间切换 |
Delay和Interval | 当单击并按下滑动条的两侧时,控制滑块沿轨迹移动的速度。这两个属性都是毫秒值。Delay是单击后在滑块移动一个单位之前的时间,而Interval是如果继续保持鼠标按下状态滑块再次移动之前的时间。 |
TickPlacement | 决定刻度显示的位置(刻度是在滑动条附近用于帮助观察数值的刻痕记号),默认情况下,TickPlacement属性被设置为None,并且不显示刻度表计。如果是水平滑动条,可以在上面放置刻度标记(TopLeft)或在下面放置刻度标记(BottomRight)。对于竖直滑动条,可以在左边(TopLeft)和右边(BottomRight)放置刻度标记(TickPlacement的名称有些令人迷惑,因为根据滑动条的方向两个值包含了4中可能) |
TickFrequency | 设置刻度之间的间隔,他决定了显示多少刻度。例如每隔5个单位放置一个刻度 |
Ticks | 如果希望在特定的不规则的位置放置刻度,可以使用Ticks集合。简单的为每个刻度标记向该集合添加一个数值(双精度浮点数)。例如可以通过添加相应的数值,在1、1.5、2和10刻度位置放置一个刻度记号 |
IsSnapToTickEnabled | 如果该属性为true,当移动滑动条时,会自动跳转到合适的位置——最近的刻度标记,默认值是false |
IsSelectionRangeEnabled | 如果为true,可以使用一个选择范围使滑动条的一部分显示阴影。使用SelectionStart和SelectionEnd属性设置位置选择范围。选择范围没有严格的含义,但是可以为任何有意义的目的的使用它。例如:播放器有时使用阴影北京工具条指示媒体文件的下载进度 |
<StackPanel Margin="10"> <TextBlock Margin="0,0,0,5">Normal Slider (Max=100, Val=10)</TextBlock> <Slider Maximum="100" Value="10"></Slider> <TextBlock Margin="0,15,0,5">Slider with Tick Marks (TickFrequency=10, TickPlacement=BottomRight)</TextBlock> <Slider Maximum="100" Value="10" TickFrequency="10" TickPlacement="BottomRight"></Slider> <TextBlock Margin="0,15,0,5">Slider with Irregular Tick Marks (Ticks=0,5,10,15,25,50,100)</TextBlock> <Slider Maximum="100" Value="10" Ticks="0,5,10,15,25,50,100" TickPlacement="BottomRight"></Slider> <TextBlock Margin="0,15,0,5" TextWrapping="Wrap">Slider with a Selection Range (IsSelectionRangeEnabled=True, SelectionStart=25, SelectionEnd=75)</TextBlock> <Slider Maximum="100" Value="10" TickFrequency="10" TickPlacement="BottomRight" IsSelectionRangeEnabled="True" SelectionStart="25" SelectionEnd="75"></Slider> </StackPanel>
6.7.2 进度条
进度条用于指示一个长时间运行任务的进度。与滑动条控件不同,ProgressBar控件不能和用户进行交互。反而,需要由代码递增Value属性值。ProgressBar控件具有4个设备无关单位的最小高度。如果希望看到一个更大、更传统的进度条,需要设置Height属性(或将它放入具有适当固定尺寸的容器中)。使用ProgressBar控件的通常方式是将它作为一个长时间运行状态的指示器,甚至可能不知道该任务需要执行多长时间。可以通过将IsIndeterminate属性设置为true来完成这一工作。
<ProgressBar Height="18" Width="200" IsIndeterminate="true"></ProgressBar>
当设置IsIndeterminate属性时,不再使用Minimum、Maximum以及Value属性。ProgressBar控件会周期性地显示从左向右的绿色脉冲,这是通用的Windows约定,表示正在工作当中。
6.8 日期控件
WPF4添加了两个日期控件:Calendar和DatePicker。这两个控件都允许用户选择一个日期。Calendar控件显示一个日历,与在Windows操作系统中看到的日历很相似。该控件每次显示一个月份,并且允许从一个月份跳刀另一个月份,或跳到一个特定的月份DatePicker控件需要更少的空间。他模仿简单的文本控件,该文本框以长日期格式或短日期格式保存一个日期字符串。DatePicker控件提供了一个下拉箭头,当单击时,会弹出一个完整的日历视图,该视图和Calendar控件显示的视图相同。Calendar和DatePicker控件提供的属性,允许你确定显示哪些日期以及哪些日期是能够选择的。可使用的属性如下:
DisplayDateStart和DisplayDateEnd | 设置在日历视图中显示的日期范围,从第一个最早的日期(DisplayDateStart)到最后最近的日期(DisplayDateEnd)。用户不能导航到没有包含能够显示的日期的月份。为了显示所有日期,可以将DisplayDateStart属性设置为DateTime.MinValue,并将DisplayDateEnd属性设置为DateTime.MaxValue。 |
BackouttDates | 保存在日历中将被禁用或不能选择的日期集合。如果这些日期不在可以显示的日期范围内,或者如果已经选择了这些日期中的某个日期,将接收到一个异常。为了阻止选择任何过去的日期,可以调用BlackoutDates.AddDatesInPast()方法。 |
SelectedDate | 作为一个DateTime对象提供选择的日期(或者没有日期被选中时使用null值)。可以通过代码、通过单击日历中的日期、或通过用户键入一个日期字符串(在DatePicker控件中)设置该属性。在日历视图中,选择的日期使用一个 具有阴影的方框标识,只有当日期控件具有焦点时才会显示该方框。 |
SelectedDates | 作为DateTime对象的集合提供选择的日期。Calendar控件支持该属性,并且只有当修改了SelectionMode属性,以允许选择多个日期时,该属性才有用。 |
DisplayDate | 确定在日历视图中最初显示的日期。如果该属性为空,显示SelectedDate属性的值。如果DisplayDate和SelectedDate属性均为空,使用当前日期。显示的日期决定了日历视图中最初的月份页面。当日期控件具有焦点时,在该月份中恰当的某天周围显示一个方形边框 |
FirstDayOfWeek | 确定在日历中每行的开始位置(最左边的位置)显示一星期中的哪一天 |
IsTodayHightlighted | 确定日历视图是否通过突出显示指出当前日期 |
DisplayMode(只用于Calendar控件) | 确定日历最初的月份显示模式。如果将该该属性设置为Month,Calendar控件显示标准的单一月份视图。如果设置为Year,Calendar控件显示当前年份中的月份(与当用户单击月份题头时显示的内容类似)。一旦用户单击了一个月份,Calendar控件就会显示该月份的完整日历视图 |
SelectionMode(只用于Calendar控件) | 确定允许的日期选择类型。默认值是SingleDate,该设置允许选择单个日期。其它选项包括None(完全禁止选择日期)、SingRange(可以选择一组联系的日期)以及MultipleRange(可以选择任意日期组合)。在SingRange和MultipleRange模式下,用户可以拖动选择多个日期,或当按下Ctrl键时通过单击选择多个日期可以使用SelectedDates属性获取包含所有选择日期的集合。 |
IsDropDownOpen(只用于DatePicker控件) | 确定是否打开DatePicker控件中的下拉日历视图。可以通过代码设置该属性以显示或隐藏日历 |
SelectedDateFormat(只用于DatePicker控件) | 确定在DatePicker控件的文本部分显示选择的日期的方式。可以选择Short或Long。实际的显示格式取决于客户计算机的区域设置。例如,如果使用Short,可能以yyyy/mm/dd格式或dd/mm/yyyy格式显示日期。长日期通常包含月份和天的名称。 |
日期控件还提供了几个不同的事件。最有用的事件是(DatePicker中的)SelectedDateChanged,或(Calendar控件)类似的SelectedDatesChanged,该事件添加了多个日期选择的支持。可以响应这些事件已拒绝特定的日期选择,例如周末的日期:
private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e) { // Check all the newly added items. foreach (DateTime selectedDate in e.AddedItems) { if ((selectedDate.DayOfWeek == DayOfWeek.Saturday) || (selectedDate.DayOfWeek == DayOfWeek.Sunday)) { lblError.Text = "Weekends are not allowed"; ((Calendar)sender).SelectedDates.Remove(selectedDate); } } }