摘要首先很高兴这个系列能得到大家的关注和支持这段时间一直在研究Windows Azure所以暂缓了更新同时也本着想把它写好、宁缺毋滥的精神在速度上自然也就慢了下来这篇文章拖拖拉拉也经历了十多天才发布出来每天写一点不过请大家放心这个系列一定会继续写下去。由于自己才疏学浅且是对这些技术的使用总结和心得体会错误之处在所难免怀着技术交流的心态在这里发表出来所以希望大家能够多多指点这样在使一部分人受益的同时也能纠正我的错误观点以便和各位共同提高。这篇文章主要是对WPF布局系统做一个较简单的介绍大家都知道UI是做好一个软件很重要的因素如果没有一个漂亮的UI再怎么强大的功能也会显得这个软件很脆弱且没有投资价值。本文以总分总的形式展开介绍首先对WPF Panel做一个总体认识、然后讲解各Panel基本用法分别用XAML和C#两种方式实现同一个功能便于大家学习、布局综合应用、自定义布局控件以及最后的总结希望对大家有所帮助。二. 本文提纲· 1.摘要· 2.本文提纲· 3.总体介绍· 4.Canvas· 5.StackPanel· 6.WrapPanel· 7.DockPanel· 8.Grid· 9.UniformGrid· 10.ViewBox· 11.Border· 12.ScrollViewer· 13.布局综合应用· 14.自定义布局控件· 15.本文总结· 16.系列进度· 17.相关代码三. 总体介绍WPF的布局控件都在System.Windows.Controls.Panel这个基类下面使用 Panel 元素在WPF应用程序中放置和排列子对象。它具体包括哪些布局控件以及如何使用这些布局控件分别用XAML和C#两种方式实现同一个功能、如何开发自定义的布局控件也就是本文所要讨论的范畴Panel具体继承关系详见下面类图如上图公共属性太多了就简单介绍几个常见的属性Margin是元素与其他元素的外边距Padding是指在本元素内部的元素内容与边缘的距离前面这两个元素基本和ASP.NE中的Margin和Padding类似只是定义大小的设置不同而已 FlowDirection属性标示元素的内容显示方向Panel.ZIndex是相对于显示屏的Z轴坐标用于调整层叠元素的显示先后RenderTransform和LayoutTransform用来将缩放和旋转的变换应用到某个元素上。一个Panel 的呈现是测量和排列Children子元素、然后在屏幕上绘制它们的过程。所以在布局的过程中会经过一系列的计算那么Children 越多执行的计算次数就越多。如果不需要较为复杂的 Panel如 Grid和自定义复杂的Panel则可以使用构造相对简单的布局如 Canvas、UniformGrid等这种布局可带来更好的性能。 如果有可能我们应尽量避免不必要地调用 UpdateLayout方法。每当Panel内的子元素改变其位置时布局系统就可能触发一个新的处理过程。对此了解哪些事件会调用布局系统就很重要因为不必要的调用可能导致应用程序性能变差。换句话说布局是一个递归系统实现在屏幕上对元素进行大小调整、定位和绘制然后进行呈现。具体如下图要实现控件0的布局,那么先要实现0的子控件01,02...的布局,要实现01的布局,那么得实现01的子控件001,002...的布局,如此循环直到子控件的布局完成后,再完成父控件的布局,最后递归回去直到递归结束,这样整个布局过程就完成了.布局系统为 Children 集合的每个成员完成两个处理过程测量处理过程Measure和排列处理过程Arrange。每个子 Panel 均提供自己的 MeasureOverride 和 ArrangeOverride 方法以实现自己特定的布局行为。四. CanvasCanvas比较简单只是一个存储元素的容器它不会自动调整内部元素的排列及大小。不指定元素位置元素将默认显示在画布的左上方。Canvas的主要用途是用来画图。Canvas默认不会自动裁减超过自身范围的内容即溢出的内容会显示在Canvas外面这是因为默认 ClipToBoundsFalse我们可以通过设置ClipToBoundsTrue来裁剪多出的内容。​编辑​编辑要实现的效果如下图用XAML和C#实现同一效果XAML代码实现Window xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassWPFLayoutDemo.CanvasDEMO x:NameWindow TitleCanvasDEMO WindowStartupLocationCenterScreen Width640 Height480 Canvas Margin0,0,0,0 BackgroundWhite Rectangle FillRed StrokeAzure Width209 Height159 Canvas.Left310 Canvas.Top181/ Ellipse FillAzure StrokeGreen Width258 Height97 Panel.ZIndex1 Canvas.Left165 Canvas.Top145/ /Canvas /WindowC#代码实现namespace WPFLayoutDemo { public partial class CanvasDEMOCodeBehind { public CanvasDEMOCodeBehind() { this.InitializeComponent(); Canvas canv new Canvas(); //把canv添加为窗体的子控件 this.Content canv; canv.Margin new Thickness(0, 0, 0, 0); canv.Background new SolidColorBrush(Colors.White); //Rectangle Rectangle r new Rectangle(); r.Fill new SolidColorBrush(Colors.Red); r.Stroke new SolidColorBrush(Colors.Red); r.Width 145; r.Height 126; r.SetValue(Canvas.LeftProperty, (double)124); r.SetValue(Canvas.TopProperty, (double)122); canv.Children.Add(r); //Ellipse Ellipse el new Ellipse(); el.Fill new SolidColorBrush(Colors.Azure); el.Stroke new SolidColorBrush(Colors.Azure); el.Width 121; el.Height 100; el.SetValue(Canvas.ZIndexProperty, 1); el.SetValue(Canvas.LeftProperty, (double)195); el.SetValue(Canvas.TopProperty, (double)191); canv.Children.Add(el); } } }五.StackPanelStackPanel就是将子元素按照堆栈的形式一一排列通过设置面板的Orientation属性设置了两种排列方式横排Horizontal默认的和竖排Vertical。纵向的StackPanel默认每个元素宽度与面板一样宽反之横向亦然。如果包含的元素超过了面板空间它只会截断多出的内容。 元素的Margin属性用于使元素之间产生一定得间隔当元素空间大于其内容的空间时剩余空间将由HorizontalAlignment和VerticalAlignment属性来决定如何分配。其他属性大家可以看看如下类图要实现的效果如下图用XAML和C#实现同一效果XAML代码实现Window xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassWPFLayoutDemo.StackPanelDEMO x:NameWindow TitleStackPanelDEMO WindowStartupLocationCenterScreen Width640 Height480 StackPanel Margin0,0,0,0 BackgroundWhite OrientationVertical Button ContentTop of Stack/ Button ContentMiddle of Stack/ Button ContentBottom Of Stack/ /StackPanel /WindowC#代码实现namespace WPFLayoutDemo { public partial class StackPanelDEMOCodeBehind { public StackPanelDEMOCodeBehind() { this.InitializeComponent(); StackPanel sp new StackPanel(); //把sp添加为窗体的子控件 this.Content sp; sp.Margin new Thickness(0, 0, 0, 0); sp.Background new SolidColorBrush(Colors.White); sp.Orientation Orientation.Vertical; //Button1 Button b1 new Button(); b1.Content Top of Stack; sp.Children.Add(b1); //Button2 Button b2 new Button(); b2.Content Middle of Stack; sp.Children.Add(b2); //Button3 Button b3 new Button(); b3.Content Bottom of Stack; sp.Children.Add(b3); } } }六. WrapPanelWrapPanel是一个非常简单的面板从左至右按顺序位置定位子元素如果排满断开至下一行。后续排序按照从上至下或从右至左的顺序进行。WrapPanel面板也提供了 Orientation属性设置排列方式这跟上面的StackPanel基本相似。不同的是WrapPanel会根据内容自动换行。要实现的效果如下图用XAML和C#实现同一效果XAML代码实现Window xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml x:ClassWPFLayoutDemo.WrapPanelDEMO x:NameWindow TitleWrapPanelDEMO WindowStartupLocationCenterScreen Width640 Height480 WrapPanel Margin0,0,0,0 BackgroundWhite Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ Rectangle Margin10,10,10,10 Fill Azure Width60 Height60/ /WrapPanel /WindowC#代码实现namespace WPFLayoutDemo { public partial class WrapPanelDEMOCodeBehind { public WrapPanelDEMOCodeBehind() { this.InitializeComponent(); WrapPanel wp new WrapPanel(); //把wp添加为窗体的子控件 this.Content wp; wp.Margin new Thickness(0, 0, 0, 0); wp.Background new SolidColorBrush(Colors.White); //遍历增加Rectangles Rectangle r; for (int i 0; i 10; i) { r new Rectangle(); r.Fill new SolidColorBrush(Colors.Azure); r.Margin new Thickness(10, 10, 10, 10); r.Width 60; r.Height 60; wp.Children.Add(r); } } }