sender, RoutedEventArgs e)
scroller.PageDown();
ScrollableTextBoxColumn.xaml.cs
最终效果如下所示:
2、自定义滚动条
ScrollViewer控件内置的滚动功能是很有用的。该功能允许缓慢滚动任何内容,从复杂的矢量图形乃至元素网格。不过,ScrollViewer控件最奇特的特征是允许其包含的内容参与滚动过程。下面是工作原理:
(1)在ScrollViewer控件中放置能滚动的元素,可以是实现了IScrollInfo接口的任意元素。
(2)通过将ScrollViewer.CanContentScroll属性设置为true,告诉ScrollViewer控件其内容知道如何进行滚动。
(3)当和ScrollViewer控件进行交互时(通过使用滚动条、鼠标轮和滚动方法等),ScrollViewer控件通过IScrollInfo接口来调用元素的恰当方法。元素接着执行它自己的自定义滚动功能。
IScrollInfo接口定义了一套方法,这套方法响应不同的滚动动作。例如,它包含了ScrollViewer控件提供的许多滚动方法,如LineUp()、LineDown()、PageUp()以及PageDown()。它还定义了一些处理鼠标滚轮的方法。
实现了IScrollInfo接口的元素极少,其中一个元素是StackPanel面板容器。StackPanel类对IScrollInfo接口的实现使用逻辑滚动,从元素滚动到元素,而不是逐行滚动。
如果在ScrollViewer控件中放置StackPanel面板,而且不设置CanContentScroll,将得到普通的滚动行为。一次可向上或向下滚动几个像素。但如果将CanContentScroll属性设置为true,那么每次单击时会滚动到下一个元素的开头:
<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>
StackPanel面板的逻辑滚动系统对应用程序可能有用也可能没用。但是,如果要创建具有特殊滚动行为的自定义面板,它是必不可少的。
二、GroupBox
GroupBox是这三个继承自HeaderedContentControl类的控件中最简单的一个。它显示为具有圆角和标题的方框。下面是一个示例,下过如下图所示:
<Window x:Class="Controls.GroupBoxDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GroupBoxDemo" Height="300" Width="300">
<GroupBox Header="A GroupBox Test" Padding="5" Margin="5" VerticalAlignment="Top">
<StackPanel>
<RadioButton Margin="3">One</RadioButton>
<RadioButton Margin="3">Two</RadioButton>
<RadioButton Margin="3">Three</RadioButton>
<Button Margin="3">Save</Button>
</StackPanel>
</GroupBox>
</Grid>
</Window>
GroupBoxDemo
三、TabItem
TabItem表示TabControl控件中的一页。TabItem类添加的唯一有意义的属性是IsSelected,该属性只是选项卡(tab)当前是否显示在TabControl控件中。下面是创建简单示例:
<Window x:Class="Controls.TabItemDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TabItemDemo" Height="300" Width="300">
<TabControl Margin="5">
<TabItem Header="Tab One">
<StackPanel Margin="5">
<CheckBox Margin="3">Setting One</CheckBox>
<CheckBox Margin="3">Setting Two</CheckBox>
<CheckBox Margin="3">Setting Three</CheckBox>
</StackPanel>
</TabItem>
<TabItem Header="Tab Two">
<StackPanel Margin="5">
<CheckBox Margin="3">Setted One</CheckBox>
<CheckBox Margin="3">Setted Two</CheckBox>
<CheckBox Margin="3">Setted Three</CheckBox>
</StackPanel>
</TabItem>
</TabControl>
</Window
>
TabItemDemo.xaml
可以使用TabStripPlacement属性,使各个选项卡在选项卡控件的侧边显示,而不是在正常顶部位置显示。
与Content属性意义,Header属性也可以接受任何类型的对象。继承自UIElement的类通过渲染来显示,对于内敛文本以及其他所有对象则使用ToString()方法。这意味着可以创建组合框或选项卡,在他们的标题中包含图形内容或任意元素。下面是一个示例:
<Window x:Class="Controls.GraphicalTabTitles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="GraphicalTabTitles" Height="300" Width="300">
<TabControl Margin="5" >
<TabItem>
<TabItem.Header>
<StackPanel>
<TextBlock Margin="3">Image and Text Tab Title</TextBlock>
<Image Source="happyface.jpg" Stretch="None"></Image>
</StackPanel>
</TabItem.Header>
<StackPanel Margin="5">
<CheckBox Margin="3">Setting One</CheckBox>
<CheckBox Margin="3">Setting Two</CheckBox>
<CheckBox Margin="3">Setting Three</CheckBox>
</StackPanel>
</TabItem>
<TabItem Header="Tab Two">
<StackPanel Margin="5">
<CheckBox Margin="3">Setted One</CheckBox>
<CheckBox Margin="3">Setted Two</CheckBox>
<CheckBox Margin="3">Setted Three</CheckBox>
</StackPanel>
</TabItem>
</TabControl>
</Window>
GraphicalTabTitles
四、Expander
最奇特的具有标题的内容控件是Expander控件。它封装了一块内容,通过单击小箭头按钮可以显示或隐藏所包含的内容。
使用Expander控件是十分简单的——只需在该控件内部包装希望使其能够折叠的内容。通常,每个Expander控件开始时都是折叠的,但可在标记中(或代码中)通过设置IsExpanded属性来改变这种行为。下面是一个简单Expander示例:
<Window x:Class="Controls.ExpandableContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ExpandableContent" Height="300" Width="300" SizeToContent="Height">
<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>
</Window>
ExpandableContent
还可以选择扩展器的方向。上图使用的是标准值(Down),但也可将ExpandDirection树上设置为Up、Left或Right。当折叠Expander时,箭头始终指向将要展开的方向。
当使用不同的ExpandDirection值,情况就比较有趣了,因为对用户界面其他部分的影响取决于容器的类型。有些容器(如WrapPanel面板)只要挤压其他元素使其离开原来的位置。其他容器,如Grid面板,可以选择按比例或自动改变大小。下面有一个示例使用不同展开程度,该示例有一个具有4个单元格的网格。每个单元格中都包含一个具有不同展开方向的扩展器。例按比例改变其大小,从而强制Expander控件中的文本进行换行(自动改变尺寸的列回简单地被拉伸以适应文本,使它比窗口还大)。行被设置为自动改变尺寸,所以会扩展以容纳附加的内容。
示例代码如下所示:
<Window x:Class="Controls.MultiDirectionExpanders"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MultiDirectionExpanders" Height="327.2" Width="328.8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition ></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Expander Margin="5" Padding="5" Header="Region One"
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.
</TextBlock>
</Expander>
<Expander Grid.Column="1"
Margin="5" Padding="5" Header="Region Two" ExpandDirection="Right"
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.
</TextBlock>
</Expander>
<Expander Grid.Row="1"
Margin="5" Padding="5" Header="Region Three" ExpandDirection="Up"
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.
</TextBlock>
</Expander>
<Expander Grid.Row="1" Grid.Column="1"
Margin="5" Padding="5" Header="Region Three" ExpandDirection="Left"
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.
</TextBlock>
</Expander>
</Grid>
</Window>
MultiDirectionExpanders
在WPF程序中使用Expander控件是非常合适的,因为WPF鼓励使用流式布局模型,从而可以很方便地处理会大幅增大或缩小的内容区域。
如果要使其他控件与Expander同步,可处理Expanded和Collapsed事件。这些事件的名称并未表明其含义,这些事件正好在显示或隐藏内容前触发。这两个事件为实现延迟加载提供一种有用的方法。例如,如果创建Expander控件中的内容非常耗时,可能会直到要显示时才检索这些内容。或者可能希望在显示之前更新内容。无论哪种情况,都可以通过响应Expanded事件来执行相应的工作。
通常,当展开Expander时,它会增大以适应所包含的内容。当展开所有内容后,如果窗口不足以显示所有内容,这可能会带来问题。下面是处理该问题的集中策略:
为窗口设置最小尺寸(使用MinWidth和MinHeight属性),确保窗口在最小时也可以容纳所有内容。
设置窗口的SizeToContent属性,从而当打开或关闭Expander控件时,是窗口自动扩展为所需的大小。通常将SizeToContent属性设置为Manual,但也可以使用Width或Height,以使窗口为了适应所包含的内容在任意方向上扩展或收缩。
通过硬编码Expander控件的Height和Widht属性来限制其尺寸,但当Expander控件中的内容太长时,可能会裁剪掉部分内容。
使用ScrollViewer控件创建可滚动的扩展区域。
对于大多数情况,这些技术都是非常简单的。唯一需要进一步说明的是如何组合使用Expander控件和ScrollViewer控件,为让这个方法凑效,需要赢编码ScrollViewer控件的尺寸。否则,ScrollViewer控件会进行扩展以适应它包含的内容。下面是一个示例:
<Window x:Class="Controls.ExpandableScrollableContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ExpandableScrollableContent" Height="300" Width="300">
<StackPanel>
<Expander Margin="5" Padding="5" Header="Region One">
</Expander>
<Expander Margin="5" Padding="5" Header="Region Two" >
<ScrollViewer Height="50" >
<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>
</ScrollViewer>
</Expander>
<Expander Margin="5" Padding="5" Header="Region Three" IsExpanded="True">
<Button Padding="3">Hidden Button Two</Button>
</Expander>
</StackPanel>
</Window>
ExpandableScrollableContent
如果有一个系统,能让Expander控件根据窗口的可用空间,设置内容区域的尺寸,那将是非常好的。但这会明显增加复杂度(例如,当Expander控件展开时,如果在多个区域共享空间)。Grid布局容器看起来像是潜在的解决方案,但它不能和Expander控件很好地集成。如果尝试这样的做的话,当折叠Expander控件时,可能导致非常奇怪的行为,不能正确地更新网格的行高。
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。