《Programming WPF》学习(三)布局

            WPF提供了一套面板,他们是用于排列他们所包含的元素的特殊用户界面元素。

      3.1栈面板(StackPanel)

      栈面板就是将其其包含的元素按照堆栈的形式排列,通过设置面板的Orientation属性设置了两种排列方式:默认的横排(Horizontal)和竖排(Vertical)。纵向的StatickPanel默认每个元素宽度与面板一样宽,反之横向亦然。如果包含的元素超过了面板空间,它只会截断内容。

< StackPanel >
  
< TextBlock Margin = " 3 " > Lock For: TextBlock >
  
< Button Margin = " 3,5 "  HorizontalAlignment = " Left " > Search Button >
StackPanel >

      元素的Margin属性用于使元素之间产生一定得间隔,当元素空间大于其内容的空间时,剩余空间将由HorizontalAlignment和VerticalAlignment属性来决定如何分配。

      3.2环绕面板(WrapPanel)

      将WrapPanel翻译成环绕面板个人觉得有待商榷,管他的就这么叫吧。大伙都知道在以往的TextBox中Wrap属性的意思就是在文本超过TextBox的长度时自动换行,这个面板也是如此。WrapPanel面板也提供了Orientation属性设置排列方式,这跟上面的StackPanel如出一辙。不同的是WrapPanel会自动换行。

      3.3停靠面板(DockPanel)

      停靠面板其实就是在2.0中类似于Dock属性的元素。DockPanel会对每个子元素进行排序,并停靠在面板的一侧,多个停靠在同侧的元素则按顺序排序,最后一个元素填充这个Panel(除非将LastChildFill属性设置为False,它才会使得没有填充的部分为空)。对于在DockPanel中的元素的停靠属性可以通过Panel.Dock的附加属性来设置,如下:

ContractedBlock.gif ExpandedBlockStart.gif DockPanel
<DockPanel>
  
<Button DockPanel.Dock="Top">TopButton>
  
<Button DockPanel.Dock="Bottom">BottomButton>
  
<Button DockPanel.Dock="Left">LeftButton>
  
<Button DockPanel.Dock="Right">RightButton>
  
<Button>FillButton>
DockPanel>

效果如图

《Programming WPF》学习(三)布局_第1张图片在这里顺带指明一下,WPF中所有元素都由FrameworkElement元素继承而来。

      在DockPanel中,停靠边界交界处的元素定义顺序直接影响到最终的显示效果。如果将left和Bottom按钮对调定义,显示如下图

《Programming WPF》学习(三)布局_第2张图片

      3.4网格面板(Grid)

      Grid与其他面板不同的是,他的面板布局由列元素集和行元素集合两种元素组成。而放置在Grid面板中的控件元素入TextBox等都必须显示采用附加属性语法定义其放置所在的行和列,否则元素均默认放置在第0行第0列。由于Grid的组成并非简单的添加属性标记来区分行列,这也使得用户在实际应用中可以具体到某一单元格中,这似乎更为明智!

      3.4.1Grid列宽与行高

      Grid的列宽与行高可采用固定、自动、按比列三种方式定义

ContractedBlock.gif ExpandedBlockStart.gif Grid列宽行高
<Grid>
  
<Grid.RowDefinitions>
    
<RowDefinition />
  
Grid.RowDefinitions>
  
<Grid.ColumnDefinitons>
    
<ColumnDefinition Width="50"/>
    
<ColumnDefinition Width="Auto"/>
    
<ColumnDefinition Width="1*"/>
    
<ColumnDefinition Width="2*"/>
  
Grid.ColumnDefinitons>
  
<TextBox Grid.Row=0 Grid.Column="0" Margin="5">
Grid>

      主要说明一下按比例定义的方式,即代码中的1*和2*,*是指相对大小,也就是说2*的宽度是1*的2倍,上面的代码写成3*和6*是没有区别的。据个例子,如果整个Grid宽度为350,第一列定义为固定长度50,第二列自动长度,而放入第二列的元素宽度为100,则剩下的2列按照1比2分配给定义为1*和2*的列。另外,如果*之前没有加数值则表示1*。也可以用浮点型的数字来定义比例,如2.5*。

      3.4.2跨越多行和多列

      使用Grid.ColumnSpan和Grid.RowSpan附加属性可以让相互间隔的行列合并

ContractedBlock.gif ExpandedBlockStart.gif 单元格合并
<Rectangle Grid.Row="1" Grid.Column="2" Grid.RowSpan="3" Margin="5,3" Fill="Black" />
<Rectangle Grid.Column="0" Grid.Row="6" Grid.ColumnSpan="2" Grid.RowSpan="2" Margin="5,3" Fill="Black" />
<TextBlock Grid.Column="0" Grid.Row="0">Here Is Some WordsTextBlock>

由上实例可以看出Grid的单元格可以被多个元素使用,在这种情况系,元素将按照Panel.ZIndex的屏幕Z轴层叠元素;元素也可以跨越多个单元格。

      3.4.3网格的连续性

      网格的连续性要实现的效果是对于不同的Grid使得它们的行列一致,如将Grid放置在一个ScrollViewer中要显示Tilte等标题信息和明细信息,那么放置于同一Grid时会在明细太多的时候下拉滚动条,会使标题信息消失,那么就要用到2个Grid,一个用来显示标题信息,一个用来显示详细信息,那么2个Grid会出现列对齐不一致的问题。采用不同Grid之间的共享尺寸组,可以解决此问题

ContractedBlock.gif ExpandedBlockStart.gif 不同Grid将共享尺寸
<DockPanel Grid.IsSharedSizeScope="True">
  
<Grid DockPanel.Dock="Top">
    
<Grid.ColumnDefinitions>
      
<ColumnDefinition Width="*" />
      
<ColumnDefinition Width="Auto" SharedSizeGroup="Location" />
      
<ColumnDefinition Width="Auto" SharedSizeGroup="Rank" />
      
<ColumnDefinition Width="Auto" />
    
Grid.ColumnDefinitions>
    
<Border Grid.Column="0" Grid.Row="0" BorderThickness="1" Background="LightGray" BorderBrush="Gray">
      
<TextBlock>TitleTextBlock>
    
Border>
    
<Border Grid.Column="1" Grid.Row="0" BorderThickness="1" Background="LightGray" BorderBrush="Gray">
      
<TextBlock>LocationTextBlock>
    
Border>
    
<Border Grid.Column="2" Grid.Row="0" BorderThickness="1" Grid.ColumnSpan="2" Background="LightGray" BorderBrush="Gray">
      
<TextBlock>RankTextBlock>
    
Border>
    
<FrameworkElement Grid.Column="3"  
     Width
="{DynamicResource {x:Static SystemParameters.ScrollWidthKey}}" />

  
Grid>

  
<ScrollViewer>
    
<Grid>
      
<Grid.ColumnDefinitions>
        
<ColumnDefinition Width="*" />
        
<ColumnDefinition Width="Auto" SharedSizeGroup="Location" />
        
<ColumnDefinition Width="Auto" SharedSizeGroup="Rank" />
      
Grid.ColumnDefinitions>
    
<Grid>
  
ScrollViewer>
DockPanel>

      开发人员有可能有意无意的将不同的Grid使用相同共享尺寸组的组名,为避免这类问题,Grid的共享尺寸组的作用范围是限制在其父元素之下,也就是在不同父元素之下的Grid即使共享尺寸组名称相同,那么它们也不会采用相同的格式。Grid.IsSharedSizeScope的附加属性定义在DockPanel中,用来标明DockPanle是一个公用的父元素。将SharedSizeGroup将不同列划分相同的组。

      在头部标题Grid的尾列加入元素列的原因是出现这种情况:明细的Grid加入到可滚动的控件ScrollViewer中,滚动条占据了一定的空间,又第二列和第三列同组,从而造成上方的Grid第一列比下方Grid第一列要宽。如果为2个Grid的第一列也制定共享组,那么他们的*显示特性将不起作用,这是共享组的特性(即共享组将禁用*),2个Grid的第一列将变成Auto的现实方式,上方的Grid第一列仍然要比较宽,所以在上方Grid中加入第四列,来平衡ScrollViewer滚动条列宽。具体第四列采用动态资源绑定列宽的方式将在第12章资源中介绍。

      3.5均布网格 UniformGrid

      一笔带过,均布网格的是Grid的简化版本,每个单元格的大小相同,不用在定义行列集合。均布网格每个单元格只能容纳一个元素,将自动按照定义在其内部的元素个数,自动创建行列,并通常保持相同的行列数。

      3.6画布Canvas

      画布只是一个为元素的放置提供场所的一个容器,不会自动调整内部元素的排列及大小。不指定元素位置,元素将默认显示在画布的左上角。Canvas的主要用途是用来画图。Canvas不会自动裁减超过自身范围的内容,即多出的内容会显示在Canvas外面,那是因为默认ClipToBounds="False";如果设置ClipToBounds="True",则会裁剪多于内容。

      3.7视图框ViewBox

      ViewBox会自动缩放其内容以填充可用的空间。ViewBox由Derector派生而来,只能有一个子元素,严格上来说不是面板。由于Canvas不会随着画布大小个改变而调整画布内部的元素大小,所以当Canvas放置在ViewBox中是,画布内的元素就可以自动调整大小了。其中ViewBox的Stretch属性有Fill、None、和UniformToFill三种模式,Fill使得元素被拉伸填满ViewBox,None的视乎没有意义,因为设置了Stretch为None,则跟没有使用ViewBox没有区别。UniformToFill将保持元素大小,并在元素大于ViewBox的时候,在一个方向是截取元素内容。

      3.8公共布局属性

      公共属性比较多不一一介绍,先简要见一下Margin和Padding的区别,Margin是元素与其停放父元素的间距,Padding是指在本元素内部的元素内容与边缘的距离。FlowDirection属性标示元素的内容显示方向。Panel.ZIndex是相对于显示屏的Z轴坐标,用于调整层叠元素的现实先后。RenderTransform和LayoutTransform用来将缩放和旋转的变换应用到某个元素上

      3.9自定义面板

      布局系统的工作原理为:测量和排列,测量就是用探测面板需要多大空间的阶段,排列则定义其面板内子元素的排列规则。自定义面板要继承自Panel类并重写MeasureOverride和ArrangeOverride方法。

ContractedBlock.gif ExpandedBlockStart.gif 自定义面板DiagonalPanel ,元素成对角线排列
using System;
using System.Windows.Controls;
using System.Windows;

ExpandedBlockStart.gifContractedBlock.gif
namespace CustomPanel {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public class DiagonalPanel : Panel {

ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override Size MeasureOverride( Size availableSize ) {
            
double totalWidth = 0;
            
double totalHeight = 0;

ExpandedSubBlockStart.gifContractedSubBlock.gif            
foreach( UIElement child in Children ) {
                child.Measure( 
new Size( double.PositiveInfinity,double.PositiveInfinity ) );
                Size childSize 
= child.DesiredSize;
                totalWidth 
+= childSize.Width;
                totalHeight 
+= childSize.Height;
            }


            
return new Size( totalWidth, totalHeight );
        }


ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override Size ArrangeOverride( Size finalSize ) {
            Point currentPosition 
= new Point( );

ExpandedSubBlockStart.gifContractedSubBlock.gif            
foreach( UIElement child in Children ) {
                Rect childRect 
= new Rect( currentPosition, child.DesiredSize );
                child.Arrange( childRect );
                currentPosition.Offset( childRect.Width, childRect.Height );
            }


            
return new Size( currentPosition.X, currentPosition.Y );
        }

    }

}

 

转载于:https://www.cnblogs.com/FlyCloud/archive/2009/04/08/1432070.html

你可能感兴趣的:(《Programming WPF》学习(三)布局)