• 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布局牵涉的内容很多,只有在平时不断积累才能渐趋完善!

  • 相关阅读:
    Android设计中的.9.png图片
    Socket原理
    word2vec中文类似词计算和聚类的使用说明及c语言源代码
    Scala之集合Collection
    使用C语言调用mysql数据库编程实战以及技巧
    Web学习篇之---html基础知识(一)
    μCOS-II系统之事件(event)的使用规则及Semaphore实例
    activiti自己定义流程之Spring整合activiti-modeler实例(一):环境搭建
    将ASP.NET用户控件转化为自定义控件
    【C#】Excel导出合并行和列并动态加载行与列
  • 原文地址:https://www.cnblogs.com/jellochen/p/3416600.html
Copyright © 2020-2023  润新知