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;
        }
    }
}
View Code

 上面代码中,在设置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>
View Code

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>
View Code

 

 其实仔细说来,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>
View Code

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>
View Code

 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>
View Code

 

我们发现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>
View Code

 这里只是简单改了布局,用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>
View Code

 这里需要注意的一点是:剪辑是在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>
View Code

 效果图如下:

 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>
View Code

 4.总结

WPF布局牵涉的内容很多,只有在平时不断积累才能渐趋完善!

posted @ 2013-11-10 13:41  jello chen  阅读(2249)  评论(0编辑  收藏  举报