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. oracle TIMESTAMP日期相减

    select extract(day from inter) * 24 * 60 * 60 + extract(hour from inter) * 60 * 60 + extract(minute ...

  2. 避免产生僵尸进程的N种方法(zombie process)

    http://blog.csdn.net/duyiwuer2009/article/details/7964795 认识僵尸进程 1.如果父进程先退出 子进程自动被 init 进程收养,不会产生僵尸进 ...

  3. 《Thinking in Java》十七章_容器深入研究_练习13(Page484)

    练习13: 单词计数器 import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFou ...

  4. 二、JavaScript语言--JS实践--倒计时效果

    主要内容:分析不同倒计时效果的计算思路及方法,掌握日期对象Date,获取时间的方法,计算时差的方法,实现不同的倒时计效果. Javascript 日期对象: Date()返回当前的日期和时间 getY ...

  5. C#的Attribute

    using System; using System.Collections; using System.Collections.Generic; using System.IO; namespace ...

  6. WPA: 4-Way Handshake failed - pre-shared key may be incorrect

    生成psk网址: https://www.wireshark.org/tools/wpa-psk.html 相关 bug: 重点 关注 : https://en.community.sonos.com ...

  7. AJax中post与get请求注意事项

    在使用ajax提交表单时,一定要区分提交按钮的形式和数据表头的设置,实例如下: GET请求: HTML代码: <!doctype html> <html lang="en& ...

  8. .NET NLog 详解(五) - Condition Expression

    Sample <!-- during normal execution only log Info messages --> <defaultFilter>level > ...

  9. wp8 入门到精通 高仿微信发信息 键盘不消失

    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> < ...

  10. 编译器 expected unqualified-id before numeric constant 错误

    今天调试代码,碰到expected unqualified-id before numeric constant 错误,代码的错误模块出现在一个函数模块上, 奇怪的是这个函数模块之前编译了很多次,也没 ...