程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Windows 8 Store Apps學習(17) 控件基礎: Measure等

Windows 8 Store Apps學習(17) 控件基礎: Measure等

編輯:關於.NET

控件基礎: 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() 後都會被更新
 */

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

[源碼下載]:http://files.cnblogs.com/webabcd/Windows8.rar

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved