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. 立方体旋转 【web前端学习部落22群120342833】

    效果: HTML部分: <body class="body"> <div class="rect-wrap">   <!-- // ...

  2. 解决Fragment在Viepager中切换不保存状态的问题

    在FragmentPagerAdapter中重写以下方法: @Override public Object instantiateItem(ViewGroup container, int posit ...

  3. string int 转换

    int转stringint n = 0;std::stringstream ss;std::string str;ss<<n;ss>>str;string转intstd::st ...

  4. JavaScript基础——添加错误处理

    JavaScript编程的一个重要组成部分,是添加错误处理来应对可能会出现的问题.默认情况下,如果因为你的JavaScript中的问题二产生了一个代码异常,那么脚本就会失败并且无法完成加载.这通常不是 ...

  5. Linux SNMP oid

    http://www.debianadmin.com/linux-snmp-oids-for-cpumemory-and-disk-statistics.html

  6. Android bluetooth用户自定义数据

    default mac: [btif_core.c] btif_fetch_local_bdaddr() default device name: [btif_dm.c] btif_get_defau ...

  7. Android OkHttp完全解析 --zz

    参考文章 https://github.com/square/okhttp http://square.github.io/okhttp/ 泡网OkHttp使用教程 Android OkHttp完全解 ...

  8. poj 1003:Hangover(水题,数学模拟)

    Hangover Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 99450   Accepted: 48213 Descri ...

  9. sdut 2603:Rescue The Princess(第四届山东省省赛原题,计算几何,向量旋转 + 向量交点)

    Rescue The Princess Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Several days ago, a b ...

  10. 7-11使用UNION合并查询

    合并查询的语法: SELECT ...FROM  表名一 UNION SELECT ...FROM 表名二 合并查询的特点: 1: 合并表中的列的个数,数据类型数据类型相同或兼容. 2:UNION 默 ...