WPF布局

来源:互联网 发布:mac磁盘工具修复权限 编辑:程序博客网 时间:2024/04/29 03:43

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

    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属性来决定如何分配。

      2环绕面板(WrapPanel)

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

      3停靠面板(DockPanel)

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

DockPanel

效果如图

在这里顺带指明一下,WPF中所有元素都由FrameworkElement元素继承而来。

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

      4网格面板(Grid)

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

      4.1Grid列宽与行高

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

Grid列宽行高

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

      4.2跨越多行和多列

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

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

      4.3网格的连续性

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

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

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

      5均布网格

 

UniformGrid

 

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

      6画布Canvas

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

      7视图框ViewBox

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

      8公共布局属性

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

      9自定义面板

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


using System;
using System.Windows.Controls;
using System.Windows;

namespace CustomPanel {
    
public class DiagonalPanel : Panel {

        
protected override Size MeasureOverride( Size availableSize ) {
            
double totalWidth = 0;
            
double totalHeight = 0;

            
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 );
        }


        
protected override Size ArrangeOverride( Size finalSize ) {
            Point currentPosition 
= new Point( );

            
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 );
        }

    }

}