zoukankan      html  css  js  c++  java
  • 重新想象 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(0, 0)); // 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(0, 0)); // 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 = 0; 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(100, 100)), 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 = 0; 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
    [源码下载]

  • 相关阅读:
    资料
    CSS 折角效果
    CSS3 动画
    选择器--验证表单
    -moz 火狐 -msIE -webkit[chrome safari]
    css3 fileter始终效果 图片渲染
    jquery 库下载地址http://www.jq22.com/jquery-info122
    CSS 文字垂直居中
    图片预加载技术(存在问题,已修复)
    Round#628(div2)
  • 原文地址:https://www.cnblogs.com/webabcd/p/3006628.html
Copyright © 2011-2022 走看看