Understanding the WPF Layout System
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的更多相关文章
- WPF Layout 系统概述——Measure
原文:WPF Layout 系统概述--Measure 前言 在WPF/Silverlight当中,如果已经存在的Element无法满足你特殊的需求,你可能想自定义Element,那么就有可能会面临重 ...
- WPF Layout 系统概述——Arrange
原文:WPF Layout 系统概述--Arrange Arrange过程概述 普通基类属性对Arrange过程的影响 我们知道Measure过程是在确定DesiredSize的大小,以便Arrang ...
- 【翻译】Sencha Touch2.4 The Layout System 布局
[翻译]The Layout System 布局 In Sencha Touch there are two basic building blocks: componentsand containe ...
- 在Winform或WPF中System.Diagnostics.Process.Start的妙用
原文:在Winform或WPF中System.Diagnostics.Process.Start的妙用 我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑 ...
- WPF中System.Diagnostics.Process.Start的妙用
我们经常会遇到在Winform或是WPF中点击链接或按钮打开某个指定的网址, 或者是需要打开电脑中某个指定的硬盘分区及文件夹, 甚至是"控制面板"相关的东西, 那么如何做呢? 答案 ...
- WPF 类型“System.ComponentModel.ISupportInitialize”在未被引用的程序集中定义。
问题:类型“System.ComponentModel.ISupportInitialize”在未被引用的程序集中定义.必须添加对程序集“System, Version=4.0.0.0, Cultur ...
- WPF的System.Windows.Threading.DispatcherTimer的使用(每隔一定的时间重复做某事)
这里使用了一个进度条来展示, 前段代码: <Window x:Class="TimerTest.MainWindow" xmlns="http://schemas. ...
- WPF Layout 系统概述 MeasureOverride和ArrangeOverride
说的非常的好:多参考!!! https://blog.csdn.net/nncrystal/article/details/47416339 https://www.cnblogs.com/dingl ...
- WPF使用System.Windows.SystemParameters类获得屏幕分辨率
转自 http://hi.baidu.com/shirley_cst/item/a55c290c8aa2ee2ca0312da3 示例代码如下所示. double x = SystemParamete ...
随机推荐
- JNDI 和JDBC的区别
1.JNDI 和JDBC的区别和联系.两者都是API,是一个标准.并不是什么产品或方法.JDBC 全称:Java Database Connectivity 以一种统一的方式来对各种各样的数据库进行存 ...
- CLR via C#(14)-可空值类型,关于?和??的故事
我们都知道,值类型是不能为Null的,但是在实际应用中有些情形却需要将值类型置为null.因此,CLR中引用了可空值类型的用法.今天的文章中见到最多的符号估计就是?了吧. ?——初识可空值类型 1. ...
- 解析PHP处理换行符的问题 \r\n
一首先说说 \r 与\n的区别回车”(Carriage Return)和“换行”(Line Feed)这两个概念的来历和区别.在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model ...
- 【20140113】package 与 import
一个完整的java源程序应该包括下列部分: package语句: //该部分至多只有一句,必须放在源程序的第一句 import语句: public classDefinition: //公共类定义部分 ...
- [Win32命令行] 更改提示符字符串(PS1)
当进入的目录比较深时, cmd的提示符几乎会占据整行, 很烦, 于是Google之... 参考: A better PROMPT for CMD.EXE ... 更改方式: 1. pro ...
- 关于strcpy_s
#include"stdafx.h" #include<iostream> #include<cstring> int main() { using nam ...
- Oracle备份及备份策略
第二章. 了解备份的重要性 可以说,从计算机系统出世的那天起,就有了备份这个概念,计算机以其强大的速度处理能力,取代了很多人为的工作,但是,往往很多时候,它又是那么弱不禁风,主板上的芯片.主板电路.内 ...
- android 入门-git之上传本地代码到github
github部分: 1.首先去github网站 上注册一个用户 2.说明 https://guides.github.com/activities/hello-world/ 2.点击 New repo ...
- [JAVA] IOException: Invalid byte 2 of 2-byte UTF-8 sequence(解决办法)
日志打印不全,后台只打印出出标题的异常信息: 先前的日志打印信息:log.debug(e.getMessage()); 后面改成了日志打印信息:log.debug(e); log.debug(e.ge ...
- Spring容器初始化过程
一.Spring 容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配号Bean之间的依 ...