原文:
背水一战 Windows 10 (72) - 控件(控件基类): UIElement - UIElement 的位置, UIElement 的布局, UIElement 的其他特性
背水一战 Windows 10 (72) - 控件(控件基类): UIElement - UIElement 的位置, UIElement 的布局, UIElement 的其他特性
作者:webabcd
介绍
背水一战 Windows 10 之 控件(控件基类 - UIElement)
- 获取 UIElement 的位置
- UIElement 的布局相关(Measure, Arrange)
- UIElement 的非完整像素布局(UseLayoutRounding)
- UIElement 的其他特性(Visibility, Opacity, CacheMode)
示例
1、演示如何获取 UIElement 的位置
Controls/BaseControl/UIElementDemo/TransformToVisualDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.UIElementDemo.TransformToVisualDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.UIElementDemo" 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="10 0 10 10"> <Grid HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5"> <Rectangle Name="rectangle1" Width="300" Height="200" Fill="Red" /> <Rectangle Name="rectangle2" Width="150" Height="100" Fill="Green" /> </Grid> <TextBlock Name="lblMsg" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/UIElementDemo/TransformToVisualDemo.xaml.cs
/* * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/) * TransformToVisual(UIElement visual) - 返回相对于指定 UIElement 原点(左上角顶点)的 GeneralTransform 类型的对象,传 null 值则为相对于 app 原点(左上角顶点) * * * GeneralTransform * Point TransformPoint(Point point) - 获取相对于指定位置的位置 * * * 本例用于演示如何获取 UIElement 的位置 */ using System; using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; namespace Windows10.Controls.BaseControl.UIElementDemo { public sealed partial class TransformToVisualDemo : Page { public TransformToVisualDemo() { this.InitializeComponent(); this.Loaded += TransformToVisualDemo_Loaded; } void TransformToVisualDemo_Loaded(object sender, RoutedEventArgs e) { Demo1(); Demo2(); } // 演示如何获取 UIElement 相对于 app 原点(左上角顶点)的位置 private void Demo1() { GeneralTransform generalTransform = rectangle1.TransformToVisual(null); // 获取 rectangle1 相对于 app 原点(左上角顶点)的 GeneralTransform Point point = generalTransform.TransformPoint(new Point(0, 0)); // rectangle1 的原点(左上角顶点)相对于屏幕 0,0 点的位置 lblMsg.Text += "红色矩形的原点(左上角顶点)相对于屏幕的原点(左上角顶点)的位置:" + point.ToString(); lblMsg.Text += Environment.NewLine; } // 演示如何获取 UIElement 相对于另一个 UIElement 原点(左上角顶点)的位置 private void Demo2() { GeneralTransform generalTransform = rectangle1.TransformToVisual(rectangle2); // 获取 rectangle1 相对于 rectangle2 原点(左上角顶点)的 GeneralTransform Point point = generalTransform.TransformPoint(new Point(0, 0)); // rectangle1 的原点(左上角顶点)相对于 rectangle2 的原点(左上角顶点)的位置 lblMsg.Text += "红色矩形的原点(左上角顶点)相对于绿色矩形的原点(左上角顶点)的位置:" + point.ToString(); } } }
2、演示 UIElement 的布局相关
Controls/BaseControl/UIElementDemo/LayoutDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.UIElementDemo.LayoutDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.UIElementDemo" 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="10 0 10 10"> <StackPanel Name="stackPanel" Margin="1 2 3 4" HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Background="Orange"> <Rectangle Name="rectangle1" Fill="White" Width="100" Height="100" /> </StackPanel> <TextBlock Name="lblMsg" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/UIElementDemo/LayoutDemo.xaml.cs
/* * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/) * Measure(), Arrange(), InvalidateMeasure(), InvalidateArrange() - 参见 /MyControls/MyControl2.cs * DesiredSize - 获取通过 Measure() 计算后得到的期望尺寸 * RenderSize - 获取通过 Arrange() 计算后得到的呈现尺寸 * UpdateLayout() - 相当于依次调用 InvalidateMeasure() 和 InvalidateArrange(),然后同步等待结果,而 InvalidateMeasure() 和 InvalidateArrange() 本身是异步处理的 * * * 注: * 1、uwp 的 layout 是一个递归系统,更多说明请参见 /MyControls/MyControl2.cs * 2、InvalidateMeasure() 就是递归调用自己和子辈门的 Measure() * 3、InvalidateArrange() 就是递归调用自己和子辈门的 Arrange() * * * 本例用于演示 UIElement 的布局相关 */ using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace Windows10.Controls.BaseControl.UIElementDemo { public sealed partial class LayoutDemo : Page { public LayoutDemo() { this.InitializeComponent(); this.Loaded += LayoutDemo_Loaded; } private void LayoutDemo_Loaded(object sender, RoutedEventArgs e) { lblMsg.Text += stackPanel.DesiredSize.ToString(); // 204,106(期望尺寸,是包括 margin 的) lblMsg.Text += Environment.NewLine; lblMsg.Text += stackPanel.RenderSize.ToString(); // 200,100(呈现尺寸,是不包括 margin 的) lblMsg.Text += Environment.NewLine; // 更改外观 stackPanel.Margin = new Thickness(5); rectangle1.Height = 300; // 更改外观后,布局系统会自动调用 InvalidateMeasure() 和 InvalidateArrange(),但是这是个异步的过程 // 所以此处获取到的 DesiredSize 和 RenderSize 仍然是更改外观之前的值 lblMsg.Text += stackPanel.DesiredSize.ToString(); // 204,106(期望尺寸,是包括 margin 的) lblMsg.Text += Environment.NewLine; lblMsg.Text += stackPanel.RenderSize.ToString(); // 200,100(呈现尺寸,是不包括 margin 的) lblMsg.Text += Environment.NewLine; // 如果想要同步知道结果的话就调用 UpdateLayout() stackPanel.UpdateLayout(); // 所以此处获取到的 DesiredSize 和 RenderSize 为更改外观之后的值 lblMsg.Text += stackPanel.DesiredSize.ToString(); // 210,310(期望尺寸,是包括 margin 的) lblMsg.Text += Environment.NewLine; lblMsg.Text += stackPanel.RenderSize.ToString(); // 200,300(呈现尺寸,是不包括 margin 的) } } }
3、演示 UIElement 的 UseLayoutRounding 的应用
Controls/BaseControl/UIElementDemo/UseLayoutRoundingDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.UIElementDemo.UseLayoutRoundingDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.UIElementDemo" 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="10 0 10 10"> <!-- UseLayoutRounding - 是否使用完整像素布局。默认值为 true 举例说明:如果设置了某个元素的 Margin="1.6"(非完整像素),那么 1、当 UseLayoutRounding="true" 时,则设置为 Margin="1.6" 的元素的各个方向的 Margin 是不相等的,但是显示清晰 2、当 UseLayoutRounding="false" 时,则设置为 Margin="1.6" 的元素的各个方向的 Margin 是相等的,但是显示不清晰 注:UseLayoutRounding 是会自动继承的,即子元素会继承父元素的 UseLayoutRounding 设置 --> <Grid Width="200" Height="200" Margin="5" HorizontalAlignment="Left"> <Border BorderBrush="Black" Background="White" BorderThickness="1"></Border> <Border BorderBrush="Black" Background="White" BorderThickness="1" Margin="1.6" UseLayoutRounding="True"></Border> </Grid> <Grid Width="200" Height="200" Margin="5" HorizontalAlignment="Left"> <Border BorderBrush="Black" Background="White" BorderThickness="1"></Border> <Border BorderBrush="Black" Background="White" BorderThickness="1" Margin="1.6" UseLayoutRounding="False"></Border> </Grid> </StackPanel> </Grid> </Page>
Controls/BaseControl/UIElementDemo/UseLayoutRoundingDemo.xaml.cs
/* * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/) * UseLayoutRounding - 是否使用完整像素布局。默认值为 true * * * 本例用于演示 UIElement 的 UseLayoutRounding 的应用 */ using Windows.UI.Xaml.Controls; namespace Windows10.Controls.BaseControl.UIElementDemo { public sealed partial class UseLayoutRoundingDemo : Page { public UseLayoutRoundingDemo() { this.InitializeComponent(); } } }
4、演示 UIElement 的其他特性
Controls/BaseControl/UIElementDemo/OthersDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.UIElementDemo.OthersDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.UIElementDemo" 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="5"> <Rectangle Fill="Orange" Width="100" Height="100" Margin="5" Visibility="Collapsed" /> <Rectangle Fill="Orange" Width="100" Height="100" Margin="5" Opacity="0.5" CacheMode="BitmapCache" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/UIElementDemo/OthersDemo.xaml.cs
/* * UIElement - UIElement(继承自 DependencyObject, 请参见 /Controls/BaseControl/DependencyObjectDemo/) * Visibility - 可见性 * Visible - 显示 * Collapsed - 不显示,且不占位 * Opacity - 不透明度(0.0 - 1.0 之间,默认值为 1.0) * CacheMode - 缓存模式 * null - 默认值 * BitmapCache - 用 GPU 渲染 RenderTransform 和 Opacity * 如果 RenderTransform 或 Opacity 使用了 storyboard 动画的话,动画一律将变为 Dependent Animation 而不是 Independent Animation,这样性能就会变差。一般来说不用设置成 BitmapCache 模式 * * * 本例用于演示 UIElement 的其他特性 */ using Windows.UI.Xaml.Controls; namespace Windows10.Controls.BaseControl.UIElementDemo { public sealed partial class OthersDemo : Page { public OthersDemo() { this.InitializeComponent(); // this.Visibility = Visibility.Collapsed; // this.Opacity = 0.5; // this.CacheMode = null; // this.CacheMode = new BitmapCache(); } } }
OK
[源码下载]