【WPF.NET开发】WPF 中的 Layout

本文内容

  1. 元素边界框
  2. 布局系统
  3. 测量和排列子元素
  4. 面板元素和自定义布局行为
  5. 布局性能注意事项
  6. 子像素渲染和布局舍入

本主题介绍 Windows Presentation Foundation (WPF) 布局系统。 了解布局计算发生的方式和时间对于在 WPF 中创建用户界面非常重要。

1、元素边界框

在 WPF 中构思布局时,了解环绕所有元素的边界框非常重要。 布局系统使用的每个 FrameworkElement 都可以被视为嵌入到布局中的矩形。 LayoutInformation 类返回元素的布局分配或布局槽的边界。 矩形的大小是通过计算可用屏幕空间、任何约束的大小、特定于布局的属性(如边距和填充)以及父 Panel 元素的个别行为来确定的。 处理此数据时,布局系统能够计算特定 Panel 的所有子级的位置。 请务必记住,调整在父元素(如 Border)上定义的特性的大小会影响其子级。

下图显示了一个简单的布局。

grid-no-bounding-box-superimpose.png?view=netframeworkdesktop-4.8

可以通过使用以下 XAML 实现此布局。

<Grid Name="myGrid" Background="LightSteelBlue" Height="150"><Grid.ColumnDefinitions><ColumnDefinition Width="250"/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions><TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana" Grid.Column="0" Grid.Row="0">Hello World!</TextBlock><Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0" Grid.Row="1">Show Bounding Box</Button><TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>

单个 TextBlock 元素托管在 Grid 中。 虽然文本仅填充第一列的左上角,但 TextBlock 的分配空间实际上要大得多。 可以使用 GetLayoutSlot 方法检索任何 FrameworkElement 的边界框。 下图显示 TextBlock 元素的边界框。

visible-textblock-bounding-box.png?view=netframeworkdesktop-4.8

如黄色矩形所示,TextBlock 元素的分配空间实际上远大于所显示的空间。 由于还有其他元素添加到 Grid 中,这种分配可能会收缩或扩展,具体取决于所添加元素的类型和大小。

使用 GetLayoutSlot 方法将 TextBlock 的布局槽转换为 Path。 此方法可用于显示元素的边界框。

private void getLayoutSlot1(object sender, System.Windows.RoutedEventArgs e)
{RectangleGeometry myRectangleGeometry = new RectangleGeometry();myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1);Path myPath = new Path();myPath.Data = myRectangleGeometry;myPath.Stroke = Brushes.LightGoldenrodYellow;myPath.StrokeThickness = 5;Grid.SetColumn(myPath, 0);Grid.SetRow(myPath, 0);myGrid.Children.Add(myPath);txt2.Text = "LayoutSlot is equal to " + LayoutInformation.GetLayoutSlot(txt1).ToString();
}

2、布局系统

简单地说,布局是一个递归系统,实现对元素进行大小调整、定位和绘制。 更具体地说,布局描述测量和排列 Panel 元素的 Children 集合的成员的过程。 布局是一个密集的过程。 Children 集合越大,必须进行的计算次数就越多。 根据拥有该集合的 Panel 元素所定义的布局行为,还可能会增加复杂性。 相对简单的 Panel(如 Canvas)可以比更复杂的 Panel(如 Grid)具有更好的性能。

每当子 UIElement 改变其位置时,布局系统都可能触发一个新的传递。 因此,了解哪些事件会调用布局系统就很重要,因为不必要的调用可能导致应用程序性能变差。 下面描述调用布局系统时发生的过程。

  1. 子 UIElement 通过首先测量其核心属性来开始布局过程。

  2. 计算 FrameworkElement 上定义的大小调整属性,例如 Width、Height 和 Margin。

  3. 应用 Panel 特定的逻辑,例如 Dock 方向或堆叠 Orientation。

  4. 测量所有子级后排列内容。

  5. 在屏幕上绘制 Children 集合。

  6. 如果向集合添加了其他 Children,应用了 LayoutTransform,或者调用了 UpdateLayout 方法,则会再次调用该过程。

以下各节更详细地定义了此过程及其调用方式。

3、测量和排列子元素

布局系统为 Children 集合的每个成员完成两个过程:一个测量过程和一个排列过程。 每个子 Panel 都提供自己的 MeasureOverride 和 ArrangeOverride 方法来实现自己的特定布局行为。

在测量过程中,会计算 Children 集合的每个成员。 此过程从调用 Measure 方法开始。 需要在父 Panel 元素的实现中调用此方法,而不必为要出现的布局显式调用该方法。

首先,计算 UIElement 的本机大小属性,例如 Clip 和 Visibility。 这将生成一个名为 constraintSize 的值,该值将传递给 MeasureCore。

其次,处理在 FrameworkElement 上定义的框架属性,这会影响 constraintSize 的值。 这些属性通常描述基础 UIElement 的大小调整特性,例如其 Height、Width、Margin 和 Style。 其中每个属性都可以更改显示元素所需的空间。 然后使用 constraintSize 作为参数调用 MeasureOverride。

 备注

Height 和 Width 属性与 ActualHeight 和 ActualWidth 属性有所不同。 例如,ActualHeight 属性是基于其他高度输入和布局系统的计算值。 该值是由布局系统本身基于实际呈现的传递设置的,因此可能稍微小于属性(例如作为输入更改基础的 Height)的设置值。

因为 ActualHeight 是计算所得的值,所以你应该知道,由于布局系统各种操作的结果,该值可能有多次或递增的报告的更改。 布局系统可能会计算子元素所需的测量空间、父元素的约束等。

测量过程的最终目标是让子元素确定其 DesiredSize,这发生在 MeasureCore 调用期间。 Measure 存储 DesiredSize 值,供在内容排列过程中使用。

排列过程从调用 Arrange 方法开始。 在排列过程中,父 Panel 元素会生成一个表示子元素边界的矩形。 该值将传递给 ArrangeCore 方法进行处理。

ArrangeCore 方法计算子元素的 DesiredSize,并且计算可能影响元素呈现大小的任何其他边距。 ArrangeCore 生成一个 arrangeSize,后者作为参数传递给 Panel 的 ArrangeOverride 方法。 ArrangeOverride 生成子元素的 finalSize。 最后,ArrangeCore 方法执行偏移量属性(如边距和对齐)的最终计算,并将子元素放在其布局槽内。 子元素不需要(并且通常不)填充整个分配空间。 然后将控件返回给父级 Panel,布局过程即告完成。

4、面板元素和自定义布局行为

WPF 包含一组派生自 Panel 的元素。 这些 Panel 元素支持许多复杂的布局。 例如,使用 StackPanel 元素可以轻松实现堆叠元素,而使用 Canvas 可实现更复杂和自由流动的布局。

下表汇总了可用的布局 Panel 元素。

面板名称说明
Canvas定义一个区域,可在其中通过相对于 Canvas 区域的坐标显式定位子元素。
DockPanel定义一个区域,可在其中使子元素相互水平或垂直排列。
Grid定义由列和行组成的灵活的网格区域。
StackPanel将子元素排列成水平或垂直的一行。
VirtualizingPanel为虚拟化其子数据集合的 Panel 元素提供一个框架。 这是一个抽象类。
WrapPanel按从左到右的顺序位置定位子元素,在包含框的边缘处将内容切换到下一行。 排序顺序是从上到下还是从右到左,取决于 Orientation 属性的值。

对于需要使用任何预定义的 Panel 元素都无法实现的布局的应用程序,可以通过继承 Panel 并替代 MeasureOverride 和 ArrangeOverride 方法来实现自定义布局行为。

5、布局性能注意事项

布局是一个递归过程。 Children 集合中的每个子元素都会在每次调用布局系统期间得到处理。 因此,应避免在不必要时触发布局系统。 以下注意事项有助于实现更好的性能。

  • 应注意哪些属性值更改会强制执行布局系统的递归更新。

    如果依赖属性的值可能导致布局系统被初始化,则会使用公共标志对该依赖属性进行标记。 AffectsMeasure 和 AffectsArrange 提供了有用的线索,说明哪些属性值更改会强制执行布局系统的递归更新。 一般来说,任何可能影响元素边界框大小的属性都应将 AffectsMeasure 标志设置为 True。 

  • 如果可能,请使用 RenderTransform 而不是 LayoutTransform。

    LayoutTransform 是一种影响用户界面 (UI) 内容的非常有用的方式。 但是,如果转换效果不需要影响其他元素的位置,则最好改用 RenderTransform,因为 RenderTransform 不会调用布局系统。 LayoutTransform 会应用其转换,并强制执行递归布局更新以获得受影响元素的新位置。

  • 避免对 UpdateLayout 进行不必要的调用。

    UpdateLayout 方法会强制执行递归布局更新,通常是不必要的。 除非你确定需要进行完整更新,否则请依赖布局系统为你调用此方法。

  • 在处理大型 Children 集合时,请考虑使用 VirtualizingStackPanel 而不是常规的 StackPanel。

    通过虚拟化子集合,VirtualizingStackPanel 仅在内存中保留当前位于父级视区内的对象。 因此,在大多数情况下,性能得到显著提高。

子像素渲染和布局舍入

WPF 图形系统使用与设备无关的单元来使分辨率和设备独立。 每个与设备无关的像素都会随着系统的每英寸点数 (dpi) 设置自动进行缩放。 这为 WPF 应用程序提供了不同 dpi 设置的适当缩放,并使应用程序自动感知 dpi。

但是,这种 dpi 无关性可能由于抗锯齿而呈现出不规则的边缘。 这些伪影通常被视为模糊或半透明边缘,当边缘的位置落在设备像素的中间而不是设备像素之间时,就可能出现。 布局系统提供了一种通过布局倒圆对此进行调整的方法。 布局舍入是布局系统在布局传递中舍入任何非整数像素值的情况。

默认情况下禁用布局舍入。 若要启用布局舍入,请在任何 FrameworkElement 上将 UseLayoutRounding 属性设置为 true。 因为它是一个依赖属性,所以该值将传播到可视化树中的所有子级。 若要为整个 UI 启用布局舍入,请在根容器上将 UseLayoutRounding 设置为 true。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/647468.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apollo Cyber RT:引领实时操作系统在自动驾驶领域的创新

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

深入理解旅游网站开发:Java+SpringBoot+Vue+MySQL的实战经验

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

ChatGPT 全域调教高手:成为人工智能交流专家

随着人工智能的快速发展&#xff0c;ChatGPT作为一种强大的文本生成模型&#xff0c;在各行各业中越来越受到重视和应用。想要利用ChatGPT实现更加智能、自然的交流&#xff0c;成为 ChatGPT 全域调教高手吗&#xff1f;本文将为您介绍如何通过优化ChatGPT的训练方法&#xff0…

jquery多选框

使用hbuilder <!DOCTYPE html> <html><head><meta charset"GBK"><title></title></head><body><table id"myTable"> <tr> <td>黄1</td> </tr> <tr> <td>…

JAVA泛型、泛型通配符、综合练习

作用&#xff1a; 是 jdk5 中引入的特性&#xff0c;可以在编译阶段 约束 操作的数据类型&#xff0c;并进行检查。 格式&#xff1a; <数据类型> 注意泛型只能支持引用数据类型&#xff0c;基本数据类型可转成对应的包装类。 问题&#xff1a; 在没有泛型的时候&…

UE使用C++添加FGameplayTag(游戏标签)

首先Ue会有一个UGameplayTagsManager类型的对象 游戏标签管理器(全局中就有一个) 我们直接通过 UGameplayTagsManager::Get()静态函数拿到 全局唯一的游戏标签管理器的实例 返回的是个左值引用 之后通过调用 AddNativeGameplayTag()函数就可添加游戏标签了 就这么简单 第…

按条件自动搜索文件

在计算机的某个文件夹中&#xff0c;假如有一大堆不同格式的文件&#xff0c;如下图&#xff1a; 我们的目的&#xff1a;快速查找出文件名中包含某文字内容的指定格式的文件&#xff0c;看看它们都放在哪里&#xff1f;通过分析&#xff0c;可能在当前文件夹中也可能在某个子…

核心类库ArrayList、hashMap等

八. 核心类库 1. ArrayList 数组缺点 ArrayList&#xff0c;它常常被用来替代数组 数组的缺点&#xff1a;不能自动扩容&#xff0c;比如已经创建了大小为 5 的数组&#xff0c;再想放入一个元素&#xff0c;就放不下了&#xff0c;需要创建更大的数组&#xff0c;还得把旧…

防御保护---防火墙(安全策略、NAT策略实验)

防御保护---防火墙&#xff08;安全策略、NAT策略实验&#xff09; 1.实验需求2.实验说明及思路3.实验配置3.1 配置IP地址以及VLAN3.2 配置防火墙IP地址及划分区域3.3 配置防火墙安全策略3.4 配置防火墙NAT策略 1.实验需求 1.生产区在工作时间内可以访问服务器区&#xff0c;仅…

【iOS ARKit】人脸追踪之挂载虚拟元素

人脸跟踪&#xff08;Face Tracking&#xff09;是指将人脸检测扩展到视频序列&#xff0c;跟踪同一张人脸在视频序列中的位置。是论上讲&#xff0c;任何出现在视频中的人险都可以被跟踪&#xff0c;也即是说&#xff0c;在连续视频帧中检测到的人脸可以被识别为同一个人。人脸…

ActiveMQ|01-ClassicArtemis功能介绍

接上篇-MQ消息队列主流消息服务规范及代表产品&#xff0c;ActiveMQ就是基于JMS消息服务规范的消息中间件组件&#xff0c;主要应用在分布式系统架构中&#xff0c;帮助构建高可用、 高性能、可伸缩的企业级面向消息服务的系统 本文速览&#xff1a; JMS对象模型ActiveMQ的功…

import tensorflow.contrib.slim as slim中contrib报红,显示没有导入contrib

本人环境&#xff1a; python 3.6 tensorflow 1.13 问题如下图&#xff1a; 解决方法&#xff1a; 找到包的位置&#xff0c;查看tensorflow中是否下载了contrib包&#xff0c;如果有的话&#xff0c;建议重新装一次TensorFlow 如果没有找找&#xff0c;可以在搜索栏搜一下…

【Web前端实操15】利用Grid布局完成九宫格

相关知识点&#xff1a; 创建多列 column-count 属性指定了需要分割的列数 列与列之间的间隙 column-gap 属性指定了列与列间的间隙 列边框 column-rule-style 属性指定了列与列间的边框样式 column-rule-width 属性指定了两列的边框厚度 column-rule-color 属性指定了…

【GitHub项目推荐--不错的Flutter项目】【转载】

01 可定制的图表库 FL Chart是一个高度可定制的 Flutter 图表库&#xff0c;支持折线图、条形图、饼图、散点图和雷达图 。 项目地址&#xff1a;https://github.com/imaNNeoFighT/fl_chart LineChart BarChart PieChart Sample1 Sample2 Sample3 …

哪吒汽车与经纬恒润合作升级,中央域控+区域域控将于2024年落地

近日&#xff0c;在2024哪吒汽车价值链大会上&#xff0c;哪吒汽车与经纬恒润联合宣布合作升级&#xff0c;就中央域控制器和区域域控制器展开合作&#xff0c;合作成果将在山海平台新一代车型上发布。 哪吒汽车首席技术官戴大力、经纬恒润副总裁李伟 经纬恒润在智能驾驶领域拥…

百度Apollo | 实车自动驾驶:感知、决策、执行的无缝融合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测

多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测 目录 多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现DBO-BiLSTM多变量时间序…

Ubuntu 申请 SSL证书并搭建邮件服务器

文章目录 Log 一、域名连接到泰坦&#xff08;Titan&#xff09;电子邮件二、NameSilo Hosting 避坑三、Ubuntu 搭建邮件服务器1. 环境准备2. 域名配置3. 配置 Postfix 和 Dovecot① 安装 Nginx② 安装 Tomcat③ 申请 SSL 证书&#xff08;Lets Encrypt&#xff09;④ 配置 pos…

链表分割(新的错误:开头赋值)

1.单向链表&#xff1a;含有链表内容和下个链表的指针 2.双向链表&#xff1a;含有链表内容和上下两个链表的指针 3.带头和不带头&#xff1a;哨兵位的头结点&#xff08;不存储有效数据&#xff09;&#xff0c;主要区别在于链表为空时会存在一个哨兵位节点&#xff0c;优点…

【C#】基础巩固

最近写代码的时候各种灵感勃发&#xff0c;有了灵感&#xff0c;就该实现了&#xff0c;可是&#xff0c;实现起来有些不流畅&#xff0c;总是有这样&#xff0c;那样的卡壳&#xff0c;总结下来发现了几个问题。 1、C#基础内容不是特别牢靠&#xff0c;理解的不到位&#xff…