控制項基礎: Measure, Arrange, GeneralTransform, Visua
介紹
重新想象 Windows 8 Store Apps 之 控制項基礎
Measure() 和 Arrange() - xaml 的 layout 系統
GeneralTransform - 通過 UIElement.TransformToVisual() 擷取元素的位置資訊
VisualTree - 可視樹
樣本
1、示範 xaml 的 layout 系統
Controls/Basic/MeasureArrange.xaml
<Page x:Class="XamlDemo.Controls.Basic.MeasureArrange" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:XamlDemo.Controls.Basic" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <local:MyStackPanel Margin="120 0 0 0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Height="200"> <TextBlock Text="我是文本" Width="100" Height="100" /> <Button Content="我是按鈕" Width="150" Height="150" /> </local:MyStackPanel> </Grid></Page>
Controls/Basic/MeasureArrange.xaml.cs
/* * 示範 Layout 系統 * * win8 xaml 的 layout 就是一個遞迴系統,本 demo 就遞迴的一個過程做說明(步驟順序參見代碼注釋中的序號) */ using System;using System.Diagnostics;using Windows.Foundation;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls; namespace XamlDemo.Controls.Basic{ public sealed partial class MeasureArrange : Page { public MeasureArrange() { this.InitializeComponent(); } } public class MyStackPanel : StackPanel { // 1、首先爸爸知道自己能夠提供的尺寸 availableSize,然後告訴兒子們 protected override Size MeasureOverride(Size availableSize) { // 2、兒子們收到 availableSize 後,又結合了自身的實際情況,然後告訴爸爸兒子們所期望的尺寸 desiredSize Size desiredSize = base.MeasureOverride(availableSize); Debug.WriteLine("availableSize: " + availableSize.ToString()); Debug.WriteLine("desiredSize: " + desiredSize.ToString()); return desiredSize; // 以下是自訂的 Measure 邏輯,供參考 /* Size childrenSize = new Size(0, 0); foreach (UIElement child in this.Children) { child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity)); childrenSize.Width += child.DesiredSize.Width; childrenSize.Height += child.DesiredSize.Height; } return childrenSize; */ } // 3、爸爸收到兒子們的反饋後,告訴兒子們自己最終提供的尺寸 finalSize protected override Size ArrangeOverride(Size finalSize) { // 4、兒子們根據 finalSize 安排各自的位置,然後爸爸的呈現尺寸也就確定了 renderSize Size renderSize = base.ArrangeOverride(finalSize); Debug.WriteLine("finalSize: " + finalSize.ToString()); Debug.WriteLine("renderSize: " + renderSize.ToString()); return renderSize; // 以下是自訂的 Arrange 邏輯,供參考 /* Point childPos = new Point(0, 0); foreach (UIElement child in this.Children) { child.Arrange(new Rect(childPos, new Size(child.DesiredSize.Width, child.DesiredSize.Height))); childPos.Y += child.RenderSize.Height; } return finalSize; */ } }} /* * 輸出結果: * availableSize: 200,200 * desiredSize: 150,250 * finalSize: 200,250 * renderSize: 200,250*/ /* * 註: * UIElement * 調用 Measure() 方法後會更新 DesiredSize 屬性 * 調用 Arrange() 方法後會更新 RenderSize 屬性 * UpdateLayout() - 強制 layout 遞迴更新 * * FrameworkElement - 繼承自 UIElement * MeasureOverride() - 重寫 Measure() * ArrangeOverride() - 重寫 Arrange() * ActualWidth 和 ActualHeight 來自 RenderSize,每次 UpdateLayout() 後都會被更新 */