原文:重新想象 Windows 8 Store Apps (17) - 控件基础: Measure, Arrange, GeneralTransform, VisualTree

[源码下载]

重新想象 Windows 8 Store Apps (17) - 控件基础: Measure, Arrange, GeneralTransform, VisualTree

作者:webabcd

介绍
重新想象 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() 后都会被更新
*/

2、演示如何获取UI元素的位置信息
Controls/Basic/GeneralTransformDemo.xaml

<Page
x:Class="XamlDemo.Controls.Basic.GeneralTransformDemo"
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">
<StackPanel Margin="120 0 0 0"> <Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<Rectangle Name="rectangle1" Width="300" Height="200" Fill="Red" />
<Rectangle Name="rectangle2" Width="150" Height="100" Fill="Green" />
</Grid> <TextBlock Name="lblMsg" FontSize="14.667" Margin="0 10 0 0" /> </StackPanel>
</Grid>
</Page>

Controls/Basic/GeneralTransformDemo.xaml.cs

/*
* 演示 GeneralTransform 的应用,可以通过 UIElement.TransformToVisual() 获取
*/ using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media; namespace XamlDemo.Controls.Basic
{
public sealed partial class GeneralTransformDemo : Page
{
public GeneralTransformDemo()
{
this.InitializeComponent(); this.Loaded += TransformToVisual_Loaded;
} void TransformToVisual_Loaded(object sender, RoutedEventArgs e)
{
lblMsg.Text = "";
Demo1();
lblMsg.Text += Environment.NewLine;
Demo2();
} // 演示如何获取 UIElement 相对于屏幕原点所占用的矩形区域
private void Demo1()
{
GeneralTransform generalTransform = rectangle1.TransformToVisual(null); // 获取 rectangle1 相对于屏幕的 GeneralTransform
Point point = generalTransform.TransformPoint(new Point(, )); // rectangle1 的原点(左上角顶点)相对于屏幕 0,0 点的位置
Rect rect = new Rect(point, new Size(rectangle1.ActualWidth, rectangle1.ActualHeight)); lblMsg.Text += "红色矩形相对于屏幕原点的位置:" + rect.ToString();
} // 演示如何获取 UIElement 相对于另一个 UIElement 原点所占用的矩形区域
private void Demo2()
{
GeneralTransform generalTransform = rectangle1.TransformToVisual(rectangle2); // 获取 rectangle1 相对于 rectangle2 的 GeneralTransform
Point point = generalTransform.TransformPoint(new Point(, )); // rectangle1 的原点(左上角顶点)相对于 rectangle2 的原点(左上角顶点)的位置
Rect rect = new Rect(point, new Size(rectangle1.ActualWidth, rectangle1.ActualHeight)); lblMsg.Text += "红色矩形相对于绿色矩形左上角顶点的位置:" + rect.ToString();
}
}
}

3、演示 VisualTreeHelper 的应用
Controls/Basic/VisualTree.xaml

<Page
x:Class="XamlDemo.Controls.Basic.VisualTree"
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">
<StackPanel Margin="120 0 0 0"> <Grid Name="container" HorizontalAlignment="Left" VerticalAlignment="Top" Tapped="container_Tapped_1">
<Rectangle Name="rectangle" Width="300" Height="200" Fill="Red" />
<Border Name="border" Width="200" Height="120" Background="Green" />
<ScrollViewer Name="scrollViewer" Width="150" Height="150" Background="Blue" />
</Grid> <TextBlock Name="lblMsg" FontSize="14.667" Margin="0 10 0 0" /> </StackPanel>
</Grid>
</Page>

Controls/Basic/VisualTree.xaml.cs

/*
* 演示 VisualTreeHelper 的应用
*
* VisualTreeHelper - 访问可视树的帮助类
* GetChildrenCount(DependencyObject reference) - 获取指定的元素内的子元素的数量
* DependencyObject GetChild(DependencyObject reference, int childIndex) - 获取指定的元素内的,指定索引位置的子元素
* GetParent(DependencyObject reference) - 获取指定的元素的父元素
* FindElementsInHostCoordinates(Point intersectingPoint, UIElement subtree, bool includeAllElements) - 查找某一点内的全部元素(包括控件模板内的元素)
* intersectingPoint - 指定的点的坐标
* subtree - 在此元素内进行查找,包括此元素
* includeAllElements
* true - 查找全部元素,包括 IsHitTestVisible 为 true 的和 IsHitTestVisible 为 false 的
* false - 仅查找 IsHitTestVisible 为 true 的元素
* FindElementsInHostCoordinates(Rect intersectingRect, UIElement subtree, bool includeAllElements) - 查找某一矩形区域内的全部元素(包括控件模板内的元素)
* intersectingRect - 指定的矩形区域
* subtree - 在此元素内进行查找,包括此元素
* includeAllElements
* true - 查找全部元素,包括 IsHitTestVisible 为 true 的和 IsHitTestVisible 为 false 的
* false - 仅查找 IsHitTestVisible 为 true 的元素
*/ using System;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media; namespace XamlDemo.Controls.Basic
{
public sealed partial class VisualTree : Page
{
public VisualTree()
{
this.InitializeComponent(); this.Loaded += VisualTree_Loaded;
} void VisualTree_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
// 获取 container 中包含的元素
lblMsg.Text = "container 中包含的元素有:";
int numVisuals = VisualTreeHelper.GetChildrenCount(container);
for (int i = ; i < numVisuals; i++)
{
DependencyObject element = VisualTreeHelper.GetChild(container, i);
lblMsg.Text += Environment.NewLine;
lblMsg.Text += element.GetType().ToString();
} lblMsg.Text += Environment.NewLine;
lblMsg.Text += Environment.NewLine; // 在 scrollViewer 控件自身的模板中查找类型为 ScrollBar 的名为 VerticalScrollBar 的控件
lblMsg.Text += "查找 scrollViewer 中的名为“VerticalScrollBar”的 ScrollBar 控件:";
lblMsg.Text += Environment.NewLine;
ScrollBar scrollBar = GetVisualChild<ScrollBar>(scrollViewer, "VerticalScrollBar");
if (scrollBar != null)
lblMsg.Text += "找到了";
else
lblMsg.Text += "未找到";
} private void container_Tapped_1(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
// 获取鼠标单击的位置,container 范围内所包含的全部元素(包括控件模板内的元素)
lblMsg.Text = "鼠标单击的位置,container 内,包含的元素有:";
IEnumerable<UIElement> elementsPoint = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), container, true);
var elementsPointEnumerator = elementsPoint.GetEnumerator();
while (elementsPointEnumerator.MoveNext())
{
lblMsg.Text += Environment.NewLine;
lblMsg.Text += elementsPointEnumerator.Current.GetType().ToString();
} lblMsg.Text += Environment.NewLine;
lblMsg.Text += Environment.NewLine; // 获取以鼠标单击的位置为顶点,100*100 大小的矩形内,container 范围内所包含的全部元素(包括控件模板内的元素)
lblMsg.Text += "以鼠标单击的位置为顶点,100*100 大小的矩形范围内,container 内,包含的元素有:";
IEnumerable<UIElement> elementsRect = VisualTreeHelper.FindElementsInHostCoordinates(new Rect(e.GetPosition(null), new Size(, )), container, true);
var elementsRectEnumerator = elementsRect.GetEnumerator();
while (elementsRectEnumerator.MoveNext())
{
lblMsg.Text += Environment.NewLine;
lblMsg.Text += elementsRectEnumerator.Current.GetType().ToString();
}
} /// <summary>
/// 获取指定元素内部的指定名称的 FrameworkElement
/// </summary>
private T GetVisualChild<T>(DependencyObject parent, string name)
where T : FrameworkElement
{
// T 是引用类型则为 null,T 是值类型则为 0
T child = default(T); int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = ; i < numVisuals; i++)
{
DependencyObject obj = VisualTreeHelper.GetChild(parent, i);
child = obj as T; if (child == null || child.Name != name)
child = GetVisualChild<T>(obj, name);
if (child != null)
break;
}
return child;
}
}
}

OK
[源码下载]

重新想象 Windows 8 Store Apps (17) - 控件基础: Measure, Arrange, GeneralTransform, VisualTree的更多相关文章

  1. 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试

    原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...

  2. 重新想象 Windows 8 Store Apps (4) - 控件之提示控件: ProgressRing; 范围控件: ProgressBar, Slider

    原文:重新想象 Windows 8 Store Apps (4) - 控件之提示控件: ProgressRing; 范围控件: ProgressBar, Slider [源码下载] 重新想象 Wind ...

  3. 重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState, VisualStateManager

    原文:重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState ...

  4. 重新想象 Windows 8 Store Apps (14) - 控件 UI: RenderTransform, Projection, Clip, UseLayoutRounding

    原文:重新想象 Windows 8 Store Apps (14) - 控件 UI: RenderTransform, Projection, Clip, UseLayoutRounding [源码下 ...

  5. 重新想象 Windows 8 Store Apps (13) - 控件之 SemanticZoom

    原文:重新想象 Windows 8 Store Apps (13) - 控件之 SemanticZoom [源码下载] 重新想象 Windows 8 Store Apps (13) - 控件之 Sem ...

  6. 重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示

    原文:重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示 [源码下载] 重新想象 Windows 8 Store Ap ...

  7. 重新想象 Windows 8 Store Apps (11) - 控件之 ListView 和 GridView

    原文:重新想象 Windows 8 Store Apps (11) - 控件之 ListView 和 GridView [源码下载] 重新想象 Windows 8 Store Apps (11) - ...

  8. 重新想象 Windows 8 Store Apps (10) - 控件之 ScrollViewer 特性: Chaining, Rail, Inertia, Snap, Zoom

    原文:重新想象 Windows 8 Store Apps (10) - 控件之 ScrollViewer 特性: Chaining, Rail, Inertia, Snap, Zoom [源码下载] ...

  9. 重新想象 Windows 8 Store Apps (9) - 控件之 ScrollViewer 基础

    原文:重新想象 Windows 8 Store Apps (9) - 控件之 ScrollViewer 基础 [源码下载] 重新想象 Windows 8 Store Apps (9) - 控件之 Sc ...

随机推荐

  1. ThinkPhp学习12

    原文:ThinkPhp学习12 二.输出模板内容      (重点) a.display 1.display中没有参数    $this->display(); 2.可以带参数    $this ...

  2. Android获取Activity(应用)的执行状态及其它信息

    检測某Activity是否在当前Task的栈顶 public static boolean isTopActivy(String cmdName, Context context) { Activit ...

  3. DelphiXE7中创建WebService(服务端+客户端) good

    相关资料:http://www.2ccc.com/news/Html/?1507.html DelphiXE7新建WebService具体操作:1.打开“DelphiXE7”->“File”-& ...

  4. TStack,TQueue,TObjectList,TObjectStack等等

    TStack,TQueue,TObjectList,TObjectStack等等,都在Contnrs.pas单元里,需要手动添加. 不同于TList类,TObjectList对象将销毁任何从列表中删除 ...

  5. Linux下一个简单的日志系统的设计及其C代码实现

    1.概述 在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件.在日志文件中存放程序流程中的一些重要信息, 包括:变量名称及其值.消息结构定义.函数返回 ...

  6. Cocos2d-x 3.1.1 lua-tests 开篇

    Cocos2d-x 3.1.1 lua-tests开篇   本篇博客打算从研究Cocos2d-x引擎提供的測试样例来写起,笔者针对Cocos2d-x 3.1.1这个版本号来介绍怎样来学习它给我们提供的 ...

  7. thinkphp中URL传参数的几种方式

    在thinkphp中,url传参合asp.net中原理类似,下面就单个参数和多个参数传递方式进行一个简单讲解 1.传单个参数 单个参数这种比较简单,例如 想像edit操作里面传递一个id值,如下写法_ ...

  8. ASA QOS限速

    cisco的Qos限速和H3C的有点区别,不过总体来说,H3C的比较渣,单位是不一样的,H3C 的CAR单位的是kpbs,而cisco police限速时的单位是Bits per seconds,H3 ...

  9. appium简明教程

    appium简明教程 什么是appium? 下面这段介绍来自于appium的官网. Appium is an open-source tool you can use to automate mobi ...

  10. hdu 4739【位运算】.cpp

    题意: 给出n个地雷所在位置,正好能够组成正方形的地雷就可以拿走..为了简化题目,只考虑平行于横轴的正方形.. 问最多可以拿走多少个正方形.. 思路: 先找出可以组成正方形的地雷组合cnt个.. 然后 ...