Many people don't understand how the WPF layout system works, or how that knowledge can help them in their projects. I intend to shine a little light on the mechanics behind all those cool layout controls in WPF.

To explain the system, I will give a step-by-step example of creating a custom panel for WPF. This panel will be similar to the StackPanel, with the difference that it will expand the last child to fill the remaining space.

Step 1: Create a new project

Create a new WPF Application project called WpfLayoutSystem.

Step 2: Add the custom panel

Add a new class to the project. Call it ExpandingStackPanel.cs.

To create your own custom panel, create a class that inherits from Panel, and override MeasureOverride and ArrangeOverride. That's it. This is the most basic panel, which doesn't add any functionality, yet.

using System;
using System.Windows;
using System.Windows.Controls; namespace WpfLayoutSystem
{
class ExpandingStackPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
} protected override Size ArrangeOverride(Size finalSize)
{
return base.ArrangeOverride(finalSize);
}
}
}

Step 3: Measure

A layout pass is made up of two steps. Measuring is the first. In the measure step, each control determines how much space it needs. Panels do this by measuring the child controls, and then basing it's desired size on the child controls. Content controls base their size on their content. Each panel tells its children how much space is available, and each child tells its parent how much space it wants.

Lets examine how this works by writing an example. Here is the code for MeasureOverride.

protected override Size MeasureOverride(Size availableSize)
{
double sumX = 0.0;
double maxY = 0.0;
foreach (UIElement child in this.Children)
{
child.Measure(new Size(Math.Max(availableSize.Width - sumX, 0.0), availableSize.Height));
sumX += child.DesiredSize.Width;
maxY = Math.Max(maxY, child.DesiredSize.Height);
}
return new Size(sumX, maxY);
}

Step 4: Arrange

The second step in the layout pass is arranging. In the arrange step, each control arranges its content or children based on the available space. Each panel tells its children how much space they have been given. Each child tells the parent how much space it actually used. You may ask why the measure and arrange passes aren't combined. Often a control is given more or less space than it asked for in the measure pass, and then it will arrange itself differently.

To see how this works, let's write the ArrangeOverride method.

protected override Size ArrangeOverride(Size finalSize)
{
double x = 0.0;
for (int i = ; i < this.Children.Count - ; i++)
{
UIElement child = this.Children[i];
child.Arrange(new Rect(x, 0.0, child.DesiredSize.Width, child.DesiredSize.Height));
x += child.DesiredSize.Width;
}
if (this.Children.Count > )
{
UIElement lastChild = this.Children[this.Children.Count - ];
lastChild.Arrange(new Rect(x, 0.0, Math.Max(finalSize.Width - x, 0.0), lastChild.DesiredSize.Height));
}
return finalSize;
}

Step 5: Using the panel

I used this code to test the panel. Feel free to use it with other code, but I can't claim that it will work in all scenarios. It was just designed as an example. Anyway, here is MainWindow.xaml.

<Window x:Class="WpfLayoutSystem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfLayoutSystem"
Title="MainWindow" Height="" Width="">
<local:ExpandingStackPanel>
<Button>A Button</Button>
<Ellipse Width="" Height="" Stroke="Black" />
<TextBlock>Some</TextBlock>
<RadioButton>Other</RadioButton>
<TextBox>Controls</TextBox>
<Button>Another Button</Button>
</local:ExpandingStackPanel>
</Window>

For your convenience, here is the entire ExpandingStackPanel class.

using System;
using System.Windows;
using System.Windows.Controls; namespace WpfLayoutSystem
{
class ExpandingStackPanel : Panel
{
protected override Size MeasureOverride(Size availableSize)
{
double sumX = 0.0;
double maxY = 0.0;
foreach (UIElement child in this.Children)
{
child.Measure(new Size(Math.Max(availableSize.Width - sumX, 0.0), availableSize.Height));
sumX += child.DesiredSize.Width;
maxY = Math.Max(maxY, child.DesiredSize.Height);
}
return new Size(sumX, maxY);
} protected override Size ArrangeOverride(Size finalSize)
{
double x = 0.0;
for (int i = ; i < this.Children.Count - ; i++)
{
UIElement child = this.Children[i];
child.Arrange(new Rect(x, 0.0, child.DesiredSize.Width, child.DesiredSize.Height));
x += child.DesiredSize.Width;
}
if (this.Children.Count > )
{
UIElement lastChild = this.Children[this.Children.Count - ];
lastChild.Arrange(new Rect(x, 0.0, Math.Max(finalSize.Width - x, 0.0), lastChild.DesiredSize.Height));
}
return finalSize;
}
}
}

Understanding the WPF Layout System的更多相关文章

  1. WPF Layout 系统概述——Measure

    原文:WPF Layout 系统概述--Measure 前言 在WPF/Silverlight当中,如果已经存在的Element无法满足你特殊的需求,你可能想自定义Element,那么就有可能会面临重 ...

  2. WPF Layout 系统概述——Arrange

    原文:WPF Layout 系统概述--Arrange Arrange过程概述 普通基类属性对Arrange过程的影响 我们知道Measure过程是在确定DesiredSize的大小,以便Arrang ...

  3. 【翻译】Sencha Touch2.4 The Layout System 布局

    [翻译]The Layout System 布局 In Sencha Touch there are two basic building blocks: componentsand containe ...

  4. 在Winform或WPF中System.Diagnostics.Process.Start的妙用

    原文:在Winform或WPF中System.Diagnostics.Process.Start的妙用 我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑 ...

  5. WPF中System.Diagnostics.Process.Start的妙用

    我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑中某个指定的硬盘分区及文件夹, 甚至是"控制面板"相关的东西, 那么如何做呢? 答案 ...

  6. WPF 类型“System.ComponentModel.ISupportInitialize”在未被引用的程序集中定义。

    问题:类型“System.ComponentModel.ISupportInitialize”在未被引用的程序集中定义.必须添加对程序集“System, Version=4.0.0.0, Cultur ...

  7. WPF的System.Windows.Threading.DispatcherTimer的使用(每隔一定的时间重复做某事)

    这里使用了一个进度条来展示, 前段代码: <Window x:Class="TimerTest.MainWindow" xmlns="http://schemas. ...

  8. WPF Layout 系统概述 MeasureOverride和ArrangeOverride

    说的非常的好:多参考!!! https://blog.csdn.net/nncrystal/article/details/47416339 https://www.cnblogs.com/dingl ...

  9. WPF使用System.Windows.SystemParameters类获得屏幕分辨率

    转自 http://hi.baidu.com/shirley_cst/item/a55c290c8aa2ee2ca0312da3 示例代码如下所示. double x = SystemParamete ...

随机推荐

  1. python 获取控制台输入

    python想从控制台获取输入的的函数有两个一个是raw_input,一个是input. 这两个函数的区别是input获取的时候会精确到类型,假设输入的是1,那么获取的就是int型的变量,如果想输入字 ...

  2. Mysql控制语句

    14.6.5.1 CASE Syntax 14.6.5.2 IF Syntax 14.6.5.3 ITERATE Syntax 14.6.5.4 LEAVE Syntax 14.6.5.5 LOOP ...

  3. 苹果应用 Windows 申请 普通证书 和Push 证书 Hbuilder 个推

    最近使用Hbuilder 进行了HTML5开发,因为 HTML5 可以放在android 机器上,也可以放到 IOS机器上,所以很感兴趣,于是开发了一个小应用, 不过问题接着来了: 图1 如图所示:当 ...

  4. DB2 for Z/os Statement prepare

    The PREPARE statement creates an executable SQL statement from a string form of the statement. The c ...

  5. 验证码的种类与实现 C#封装类 - .NET MVC WEBFORM

    验证码方式 1.随机字母或者数字,纯文本验证码 这种非常容易破解 ,市场上有大量的现成接口或者工具,背景越复杂难度越高. 2.题库验证码 要破解这种验证码,需要人工收集题库才可以破解,可以免疫不是专门 ...

  6. C#的yield关键字

    using System; using System.Collections.Generic; using System.Reflection; using System.Text.RegularEx ...

  7. 【JAVA中String、StringBuffer、StringBuilder类的使用】

    一.String类概述 1.String对象一旦创建就不能改变. 2.字符串常量池. 字符串常量池的特点:池中有则直接使用,池中没有则创建新的字符串常量. 例1: public class Strin ...

  8. 5-06使用Sql 语句为表添加约束

    约束名的命名规则推荐采用:约束类型_约束列. 为用户表添加约束 ALTER TABLE UserInfo ADD CONSTRALNT PK_UserId PRIMATY REY(UserId) CO ...

  9. C# 与 Microsoft Expression Encoder实现屏幕录制

    在日常开发中,我们会经常遇到屏幕录制的需求.在C#中可以通过Expression Encoder的SDK实现这样的需求.首先需要下载Expression Encoder SDK,实现代码: priva ...

  10. ICP 算法步骤

    The Iterative Closest Point (ICP) is an algorithm employed to match two surface representations, suc ...