WPF学习(3)布局
今天我们来说说WPF的布局。我们知道WinForm的布局主要是采用基于坐标的方式,当窗口内容发生变化时,里面的控件不会随之动态调整,这就造成了一个很不好的用户体验。而WPF为了避免这个缺点,采用了基于流的这种灵活的布局方式(WinForm在.net 2.0中也增加了对flow-based的支持)。工欲善其事,必先利其器。首先,我们来看看WPF的布局控件主要有哪些。然后,了解下主要用于构成复杂控件的原始控件。最后说说关于内容溢出的处理办法。
1.布局控件
WPF常用的布局控件主要有这么几个:Grid、StackPanel、Canvas、DockPanel、WrapPanel,它们都继承自Panel抽象类。
1.1Grid
Grid应该算是WPF中最常用的布局控件了。新建一个窗口可看到Grid是作为其默认的布局控件的。它的效果类似html中的Table,只不过在外观上Grid默认是没有边框的。我们可以在Visual Studio中的Xaml设计器上快速的创建表格,如下图所示:
通过Xaml设计器设计,会自动为我们生成布局代码,值都是精确的,我们可以适当微调。当然,直接手写Xaml也可以达到同样的效果,下面我们来用C#代码来实现这样的布局:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace LayoutDemo { /// <summary> /// GridWnd1.xaml 的交互逻辑 /// </summary> public partial class GridWnd1 : Window { public GridWnd1() { InitializeComponent(); Grid grid = new Grid(); //添加行 RowDefinition row1 = new RowDefinition(); row1.Height = new GridLength(1, GridUnitType.Star); //添加Button Button button1 = new Button(); button1.Content = "Button1"; button1.Width = 70; button1.Height = 30; //button1.SetValue(Grid.RowProperty, 0); Grid.SetRow(button1, 0); RowDefinition row2 = new RowDefinition(); row2.Height = new GridLength(1, GridUnitType.Star); RowDefinition row3 = new RowDefinition(); row3.Height = new GridLength(1, GridUnitType.Star); grid.RowDefinitions.Add(row1); grid.RowDefinitions.Add(row2); grid.RowDefinitions.Add(row3); //添加列 ColumnDefinition col1 = new ColumnDefinition(); col1.Width = new GridLength(1, GridUnitType.Star); ColumnDefinition col2 = new ColumnDefinition(); col2.Width = new GridLength(1, GridUnitType.Star); ColumnDefinition col3 = new ColumnDefinition(); col3.Width = new GridLength(1, GridUnitType.Star); grid.ColumnDefinitions.Add(col1); grid.ColumnDefinitions.Add(col2); grid.ColumnDefinitions.Add(col3); grid.Background = Brushes.LightBlue; grid.Children.Add(button1); this.Content = grid; } } }
上面代码中,在设置Grid的行高列宽时使用的是“*”,这就要我们了解下宽带和高度可以有哪些值。先来说下它们的单位:
像素是默认单位,当使用其它三种时也会自动转换为像素。
对于Grid的行高和列宽我们可以设置三种值:
1.绝对值: double类型的值加单位,单位可以有上图几种,省略不写默认为px,不会随着容器的改变而改变
2.比例值 :double类型的值加星号“*”,当是“1*”时,“1”可以省略,计算的是在所有比例值中所占的比例,会动态调整
3.自动值 :字符串“Auto”,它会根据实际的高度或者宽度来自动调整
注意:在WPF也有一个Table类,它是用来文档显示,而此处的Grid是用来界面显示的。
1.2StackPanel
StackPanel正如它的名字一样,默认的情况下,它的子元素会从上到下排列,当然我们可以控制它的Orientation属性控制排列方向。Orientation属性有两个值一个Horizontal,一个是Vertical(默认)。看下图:
StackPanel还有一个FlowDirection,它一般结合Orientation的值为Horizontal来使用,用来控制元素在水平方向上的排列方式。上图的Xaml代码:
<Window x:Class="LayoutDemo.StackPanel1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="StackPanel1" Height="267" Width="334"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <StackPanel> <Button Content="button1" /> <Button Content="button2" /> </StackPanel> <StackPanel Orientation="Horizontal" Grid.Column="1"> <Button Content="button1" /> <Button Content="button2" /> </StackPanel> <StackPanel Orientation="Horizontal" Grid.Column="2" FlowDirection="RightToLeft"> <Button Content="button1" /> <Button Content="button2" /> </StackPanel> </Grid> </Window>
1.3Canvas
Canvas相对于其它的布局控件来说,是有点儿特殊的,其它布局控件基本上都是基于流的,而它是基于坐标的。
Canvas有四个用于定位的附加属性Left、Top、Right和Bottom,分别水平方向(X轴)两个,竖直方向(Y轴)两个。
需要注意的一点是:当在一个方向同时设置了两个附加属性时,Left会覆盖Right,Top会覆盖Bottom。这样,排列组合可以有四种方式。还有一个zindex来控制Z轴,在Sliverlight中作为了Canvas的附加属性(Canvas.zindex),而在WPF中作为了Panel的附加属性(Panel.zindex)。如下图所示:
默认情况下,后面的元素会盖住前面的元素,也就是button2会盖住button1,通过修改Panel.zindex的值来控制谁显示在前面。
1.4DockPanel
DockPanel可以让元素停靠在面板的某一边,然后拉伸元素以填满全部的宽度或高度。它有一个Dock属性用来设置停靠的位置,有Left、Top、Right和Bottom四个值。先来看下效果:
需要注意的是,DockPanel没有Fill属性,但是默认情况会将最后的子元素用来填充剩余空间,除非将其LastChildFill设为False,如下图所示:
与StackPanel一样,任何元素的拉伸都是有其Horizontal或者Vertical属性为Stretch造成,当设置为其它时又是又一番样子,请看下图:
Xaml代码如下:
<Window x:Class="LayoutDemo.DockPanel1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DockPanel1" Height="300" Width="300"> <Grid> <DockPanel LastChildFill="False"> <Button Content="button1" DockPanel.Dock="Top" Background="Red" HorizontalAlignment="Center" /> <Button Content="button2" DockPanel.Dock="Left" Background="Green" VerticalAlignment="Center" /> <Button Content="button3" DockPanel.Dock="Right" Background="Blue" VerticalContentAlignment="Center"/> <Button Content="button4" DockPanel.Dock="Bottom" Background="BlanchedAlmond"/> <Button Background="Silver" Content="button5" /> </DockPanel> </Grid> </Window>
其实仔细说来,DockPanel的功能要比StackPanel要强。当我们把DockPanel的LastChildFill设为False时,可以实现像StackPanel一样的布局。
先看图:
Xaml代码:
<Window x:Class="LayoutDemo.DockPanel2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DockPanel2" Height="300" Width="300"> <Grid> <DockPanel LastChildFill="False"> <Button Content="button1" DockPanel.Dock="Top" /> <Button Content="button2" DockPanel.Dock="Top" /> <Button Content="button3" DockPanel.Dock="Top" /> </DockPanel> </Grid> </Window>
1.5WrapPanel
WrapPanel在可能的空间中,一次以一行或者一列的形式布置控件元素。与StackPanel类似,WrapPanel也有Orientation属性来控制布局方向,不过它默认值是Horizontal(StackPanel默认是Vertical)。
当你为一行或一列中的第一个元素设置高度或宽度时,该行或该列的高度或宽度默认也设为该值,这是由元素的Horizontal和Vertical的值默认为Stretch导致的。我们可以认为来修改,如下图所示:
当你在伸缩窗口时,元素会自动调整。
Xaml代码:
<Window x:Class="LayoutDemo.WrapPanel1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WrapPanel1" Height="300" Width="300"> <Grid> <WrapPanel Orientation="Horizontal" > <Button Content="button1" Height="60"/> <Button Content="button2" Height="40"/> <Button Content="button3" VerticalAlignment="Top"/> <Button Content="button4" VerticalAlignment="Bottom"/> <Button Content="button5" /> <Button Content="button6" /> </WrapPanel> </Grid> </Window>
WrapPanel也有和StackPanel一样的FlowDirection属性,功能一样,不在赘述。
2.原始面板
这里说的原始面板是指大部分位于System.Windows.Controls.Primitives 命名空间下的布局控件,主要有这么几个TabPanel、ToolBarOverFlowPanel、UniformGrid,还有一个ToolBarTray是位于System.Windows.Controls命名空间的,它们主要用于构成其他更复杂控件的一部分的基类和控件。关于该命名空间,可查看MSDN 。本节和模板Template联系紧密,我们将在模板时细说。这里以TabPanel为例,简单说明下。由于TabPanel是构成TabControl的内部的默认的布局控件,所以我们需要用Blend解剖TabControl来看下它的模板:
<SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#8C8E94"/> <Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="Padding" Value="4,4,4,4"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/> <Setter Property="Background" Value="#F9F9F9"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabControl}"> <Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local"> <Grid.ColumnDefinitions> <ColumnDefinition x:Name="ColumnDefinition0"/> <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition x:Name="RowDefinition0" Height="Auto"/> <RowDefinition x:Name="RowDefinition1" Height="*"/> </Grid.RowDefinitions> <TabPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/> <Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local"> <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </Grid> <ControlTemplate.Triggers> <Trigger Property="TabStripPlacement" Value="Bottom"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/> </Trigger> <Trigger Property="TabStripPlacement" Value="Left"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/> <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/> <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="0"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/> </Trigger> <Trigger Property="TabStripPlacement" Value="Right"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/> <Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/> <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/> <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="0"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
我们发现TabControl主要是由Header和Content部分构成的,Header就是由我们这里的TabPanel来充当的,而Content则由ContentPresenter来充当。知道了这些,我们可以做一个另类的TabControl了,看下效果图:
Xaml代码:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="LayoutDemo.TabPanel1" Title="TabPanel1" Height="300" Width="300"> <Window.Resources> <SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#8C8E94"/> <Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="Padding" Value="4,4,4,4"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/> <Setter Property="Background" Value="#F9F9F9"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabControl}"> <Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local"> <Grid.ColumnDefinitions> <ColumnDefinition x:Name="ColumnDefinition0"/> <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition x:Name="RowDefinition0" Height="*"/> <RowDefinition x:Name="RowDefinition1" Height="Auto"/> </Grid.RowDefinitions> <Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="0" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local"> <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> <StackPanel x:Name="HeaderPanel" Orientation="Horizontal" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="1" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" HorizontalAlignment="Right"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="TabStripPlacement" Value="Bottom"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/> </Trigger> <Trigger Property="TabStripPlacement" Value="Left"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/> <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/> <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="0"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/> </Trigger> <Trigger Property="TabStripPlacement" Value="Right"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/> <Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/> <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/> <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="0"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <TabControl Style="{DynamicResource TabControlStyle1}"> <TabItem Header="Tab1"> <TextBlock Text="Hello" /> </TabItem> <TabItem Header="Tab2"> <TextBlock Text="WPF" /> </TabItem> </TabControl> </Grid> </Window>
这里只是简单改了布局,用StackPanel来简单替换了TabPanel,当然根据需要,也可以用其它的布局控件来替换了。
3.内容溢出
内建的面板会尽可能的满足其子元素的尺寸要求,然而有时候,我们不能不压缩子元素的尺寸,这样导致子元素的内容溢出。处理内容溢出主要有以下几种方式:
3.1剪辑(Clipping)
通过设置ClipToBounds属性来控制是否让元素超出边界部分在外边界显示。尽管这个属性是所有UIElement及其子类都有的属性,但是只对Canvas起作用,其它布局控件都会剪辑掉超出 部分。当然,ClipToBounds属性也可以对自己内容进行剪辑。举个例子说明:
这是当我们MouseOver的时候Button的样子,此时ClipToBounds默认为False,我们将它改为True然后再MouseOver到Button上看下效果:
发现溢出部分被剪辑掉了。Xaml代码如下:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="LayoutDemo.ContentOverflow" Title="ContentOverflow" Height="300" Width="300"> <Window.Resources> <LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#F3F3F3" Offset="0"/> <GradientStop Color="#EBEBEB" Offset="0.5"/> <GradientStop Color="#DDDDDD" Offset="0.5"/> <GradientStop Color="#CDCDCD" Offset="1"/> </LinearGradientBrush> <SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/> <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}"> <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/> <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/> <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Padding" Value="1"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Button}"> <Microsoft_Windows_Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true"> <ContentPresenter x:Name="cp" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RenderTransformOrigin="0.5,0.5"> <ContentPresenter.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </ContentPresenter.RenderTransform> </ContentPresenter> </Microsoft_Windows_Themes:ButtonChrome> <ControlTemplate.Triggers> <Trigger Property="IsKeyboardFocused" Value="true"> <Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/> </Trigger> <Trigger Property="IsMouseOver" Value="true"> <Setter Property="RenderTransform" TargetName="cp"> <Setter.Value> <TransformGroup> <ScaleTransform ScaleX="1.5" ScaleY="1.5"/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Setter.Value> </Setter> </Trigger> <Trigger Property="ToggleButton.IsChecked" Value="true"> <Setter Property="RenderPressed" TargetName="Chrome" Value="true"/> </Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="#ADADAD"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <Button Content="button" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{DynamicResource ButtonStyle1}" ClipToBounds="True" /> </Grid> </Window>
这里需要注意的一点是:剪辑是在RenderTransform生效之前发生的。
3.2滚屏(Scrolling)
主要是通过ScrollViewer控件来实现的,属性主要有HorizontalScrollBarVisibility(默认值为auto)和VerticalScrollBarVisibility(默认为Visible)。直接看例子:
<Window x:Class="LayoutDemo.ContentOverflow1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ContentOverflow1" Height="300" Width="300"> <Grid> <ScrollViewer HorizontalScrollBarVisibility="Visible"> <StackPanel Orientation="Horizontal"> <Button Content="button1" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top"/> <Button Content="button1" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top"/> <Button Content="button1" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top"/> <Button Content="button1" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top"/> </StackPanel> </ScrollViewer> </Grid> </Window>
效果图如下:
3.3缩放(scalling)
说到缩放,我们首先会想到ScaleTransform,它是相对于元素的自身大小来进行缩放,相对于滚屏方式,需要写很多额外的代码,有没有和ScrollViewer一样使用简单的控件来实现缩放的效果呢?有,那就是Viewbox,那是一种类似于只有一个子元素的面板,是一种Decorator装饰类,通过它的Stretch属性来实现任意内容的缩放。假如我们在一个300*300的窗口有一个300*400的大号按钮,窗口只能显示其中的的一部分,现在我们可以用Viewbox来缩放让它完全显示在窗口上面,先看原图:
再看使用Viewbox,设置其Stetch属性后的效果:
经过缩放后,已经能够完全显示了。Xaml代码如下:
<Window x:Class="LayoutDemo.ContentOverflow2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ContentOverflow2" Height="300" Width="300"> <Viewbox Stretch="Uniform" StretchDirection="Both"> <Button Content="button1" Width="400" Height="300" /> </Viewbox> </Window>
4.总结
WPF布局牵涉的内容很多,只有在平时不断积累才能渐趋完善!