[源码下载]

背水一战 Windows 10 (79) - 自定义控件: Layout 系统, 控件模板, 事件处理

作者:webabcd

介绍
背水一战 Windows 10 之 控件(自定义控件)

  • 自定义控件的 Layout 系统
  • 自定义控件的控件模板和事件处理的相关知识点

示例
1、演示自定义控件的 Layout 系统
/MyControls/MyControl2.cs

  1. /*
  2. * 本例通过一个自定义控件来演示 uwp 中可视元素的 Layout 系统
  3. *
  4. * uwp 的 layout 是一个递归系统,本 demo 就递归的一个过程做说明(步骤顺序参见代码注释中的序号)
  5. *
  6. *
  7. * Measure() 的作用是测量尺寸
  8. * Arrange() 的作用是排列元素
  9. */
  10.  
  11. using Windows.UI.Xaml.Controls;
  12. using Windows.UI.Xaml;
  13. using Windows.Foundation;
  14. using System;
  15. using System.Linq;
  16. using System.Diagnostics;
  17. using System.Collections.Generic;
  18.  
  19. namespace MyControls
  20. {
  21. /// <summary>
  22. /// 一个每行都会自动缩进的 Panel
  23. /// </summary>
  24. public sealed class MyControl2 : Panel
  25. {
  26. // 相对上一行的缩进值
  27. const double INDENT = ;
  28.  
  29. public MyControl2()
  30. {
  31.  
  32. }
  33.  
  34. // 1、首先爸爸知道自己能够提供的尺寸 availableSize,然后告诉儿子们
  35. protected override Size MeasureOverride(Size availableSize) // 测量出期待的尺寸并返回
  36. {
  37. // 2、儿子们收到 availableSize 后,又结合了自身的实际情况,然后告诉爸爸儿子们所期望的尺寸 desiredSize
  38. List<double> widthList = new List<double>();
  39. Size desiredSize = new Size(, );
  40. foreach (UIElement child in this.Children)
  41. {
  42. // 如果 child 是 FrameworkElement 的话,则当调用其 Measure() 方法时会自动调用其 MeasureOverride() 方法
  43. child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
  44. widthList.Add(child.DesiredSize.Width);
  45. desiredSize.Height += child.DesiredSize.Height;
  46. }
  47.  
  48. if (this.Children.Count > )
  49. {
  50. desiredSize.Width = widthList.Max();
  51. desiredSize.Width += INDENT * (this.Children.Count - );
  52. }
  53.  
  54. Debug.WriteLine("availableSize: " + availableSize.ToString());
  55. Debug.WriteLine("desiredSize: " + desiredSize.ToString());
  56.  
  57. return desiredSize;
  58. }
  59.  
  60. // 3、爸爸收到儿子们的反馈后,告诉儿子们自己最终提供的尺寸 finalSize
  61. protected override Size ArrangeOverride(Size finalSize) // 排列元素,并返回呈现尺寸
  62. {
  63. // 4、儿子们根据 finalSize 安排各自的位置,然后爸爸的呈现尺寸也就确定了 renderSize
  64. Point childPosition = new Point(, );
  65. foreach (UIElement child in this.Children)
  66. {
  67. // 如果 child 是 FrameworkElement 的话,则当调用其 Arrange() 方法时会自动调用其 ArrangeOverride() 方法
  68. child.Arrange(new Rect(childPosition, new Size(child.DesiredSize.Width, child.DesiredSize.Height)));
  69. childPosition.X += INDENT;
  70. childPosition.Y += child.DesiredSize.Height;
  71. }
  72.  
  73. Size renderSize = new Size(, );
  74. renderSize.Width = finalSize.Width;
  75. renderSize.Height = childPosition.Y;
  76.  
  77. Debug.WriteLine("finalSize: " + finalSize.ToString());
  78. Debug.WriteLine("renderSize: " + renderSize.ToString());
  79.  
  80. return finalSize;
  81. }
  82. }
  83. }
  84.  
  85. /*
  86. * 输出结果如下(运行 /Controls/CustomControl/Demo2.xaml 示例)
  87. * availableSize: 800,Double.PositiveInfinity
  88. * desiredSize: 141,120
  89. * finalSize: 800,120
  90. * renderSize: 800,120
  91. */
  92.  
  93. /*
  94. * 注:
  95. * UIElement
  96. * 调用 Measure() 方法后会更新 DesiredSize 属性
  97. * 调用 Arrange() 方法后会更新 RenderSize 属性
  98. * UpdateLayout() - 强制 layout 递归更新
  99. *
  100. * FrameworkElement - 继承自 UIElement
  101. * MeasureOverride() - 在 Measure() 中自动调用
  102. * ArrangeOverride() - 在 Arrange() 中自动调用
  103. * ActualWidth 和 ActualHeight 来自 RenderSize,每次 UpdateLayout() 后都会被更新
  104. */
  105.  
  106. /*
  107. * 注:
  108. * 1、uwp 的 layout 是一个递归系统
  109. * 2、UIElement 的 InvalidateMeasure() 就是递归调用自己和子辈门的 Measure()
  110. * 3、UIElement 的 InvalidateArrange() 就是递归调用自己和子辈门的 Arrange()
  111. *
  112. * 一个通过 uwp 自带控件说明 layout 的示例,请参见:/Controls/BaseControl/UIElementDemo/LayoutDemo.xaml.cs
  113. */

Controls/CustomControl/Demo2.xaml

  1. <Page
  2. x:Class="Windows10.Controls.CustomControl.Demo2"
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:local="using:Windows10.Controls.CustomControl"
  6. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. mc:Ignorable="d"
  9.  
  10. xmlns:myControls="using:MyControls">
  11.  
  12. <Grid Background="Transparent">
  13. <StackPanel Margin="10 0 10 10">
  14.  
  15. <!--
  16. 演示元素的 Layout 系统
  17. 本例所用到的自定义控件请参看:MyControls/MyControl2.cs
  18. -->
  19. <myControls:MyControl2 Margin="5" Background="Orange" HorizontalAlignment="Left" Width="800">
  20. <myControls:MyControl2.Children>
  21. <TextBlock Text="aaaaaaaa" Margin="5" />
  22. <TextBlock Text="bbbbbbbb" Margin="5" />
  23. <TextBlock Text="cccccccc" Margin="5" />
  24. <TextBlock Text="dddddddd" Margin="5" />
  25. </myControls:MyControl2.Children>
  26. </myControls:MyControl2>
  27.  
  28. </StackPanel>
  29. </Grid>
  30. </Page>

Controls/CustomControl/Demo2.xaml.cs

  1. /*
  2. * 本例用于演示元素的 Layout 系统
  3. */
  4.  
  5. using Windows.UI.Xaml.Controls;
  6.  
  7. namespace Windows10.Controls.CustomControl
  8. {
  9. public sealed partial class Demo2 : Page
  10. {
  11. public Demo2()
  12. {
  13. this.InitializeComponent();
  14. }
  15. }
  16. }

2、演示自定义控件的控件模板和事件处理的相关知识点
/MyControls/themes/MyControl3.xaml

  1. <ResourceDictionary
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.  
  5. xmlns:local="using:MyControls">
  6.  
  7. <Style TargetType="local:MyControl3">
  8. <Setter Property="Template">
  9. <Setter.Value>
  10. <ControlTemplate TargetType="local:MyControl3">
  11.  
  12. <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
  13. <StackPanel>
  14. <TextBlock Name="textBlock" Foreground="White" FontSize="24" />
  15. </StackPanel>
  16.  
  17. <VisualStateManager.VisualStateGroups>
  18. <VisualStateGroup x:Name="CommonStates">
  19. <VisualState x:Name="Normal" />
  20.  
  21. <VisualState x:Name="PointerOver">
  22. <Storyboard>
  23. <ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Green" />
  24. </Storyboard>
  25. </VisualState>
  26.  
  27. <VisualStateGroup.Transitions>
  28. <VisualTransition To="PointerOver" GeneratedDuration="0:0:1">
  29. <VisualTransition.GeneratedEasingFunction>
  30. <ElasticEase EasingMode="EaseInOut" />
  31. </VisualTransition.GeneratedEasingFunction>
  32. </VisualTransition>
  33. </VisualStateGroup.Transitions>
  34. </VisualStateGroup>
  35. </VisualStateManager.VisualStateGroups>
  36. </Border>
  37.  
  38. </ControlTemplate>
  39. </Setter.Value>
  40. </Setter>
  41. </Style>
  42.  
  43. </ResourceDictionary>

/MyControls/MyControl3.cs

  1. /*
  2. * 开发一个自定义控件,用于演示控件模板和事件处理的相关知识点
  3. */
  4.  
  5. using Windows.UI.Xaml.Controls;
  6. using Windows.UI.Xaml;
  7. using Windows.UI.Xaml.Media;
  8. using Windows.UI.Xaml.Input;
  9.  
  10. namespace MyControls
  11. {
  12. /// <summary>
  13. /// 自定义控件
  14. /// </summary>
  15. public sealed class MyControl3 : Control
  16. {
  17. public MyControl3()
  18. {
  19. this.DefaultStyleKey = typeof(MyControl3);
  20. }
  21.  
  22. // ApplyTemplate() - 强制加载控件模板,一般不用调用(因为控件模板会自动加载)。有一种使用场景是:当父控件应用控件模板时要求子控件必须先应用控件模板以便父控件使用时,则可以先调用子控件的此方法
  23. // GetTemplateChild() - 查找控件模板中的指定名字的元素
  24. // override OnApplyTemplate() - 应用控件模板时调用
  25. protected override void OnApplyTemplate()
  26. {
  27. base.OnApplyTemplate();
  28.  
  29. TextBlock textBlock = (TextBlock)GetTemplateChild("textBlock");
  30. if (this.Background is SolidColorBrush)
  31. {
  32. textBlock.Text = $"background: {((SolidColorBrush)this.Background).Color}";
  33. }
  34.  
  35. VisualStateManager.GoToState(this, "Normal", false);
  36. }
  37.  
  38. // override GoToElementStateCore() - VisualState 转换时调用(此方法仅在自定义 ContentPresenter 并将其应用于 GridView 或 ListView 的 ItemContainerStyle 时才会被调用)
  39. // 参见:/Controls/CollectionControl/ItemsControlDemo/MyItemPresenter.cs
  40. protected override bool GoToElementStateCore(string stateName, bool useTransitions)
  41. {
  42. return base.GoToElementStateCore(stateName, useTransitions);
  43. }
  44.  
  45. // 在 Control 中有很多可 override 的事件处理方法,详见文档
  46. protected override void OnPointerEntered(PointerRoutedEventArgs e)
  47. {
  48. VisualStateManager.GoToState(this, "PointerOver", true);
  49. }
  50.  
  51. protected override void OnPointerExited(PointerRoutedEventArgs e)
  52. {
  53. VisualStateManager.GoToState(this, "Normal", false);
  54. }
  55. }
  56. }

Controls/CustomControl/Demo3.xaml

  1. <Page
  2. x:Class="Windows10.Controls.CustomControl.Demo3"
  3. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  5. xmlns:local="using:Windows10.Controls.CustomControl"
  6. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  7. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  8. mc:Ignorable="d"
  9.  
  10. xmlns:myControls="using:MyControls">
  11.  
  12. <Grid Background="Transparent">
  13. <StackPanel Margin="10 0 10 10">
  14.  
  15. <!--
  16. 演示自定义控件的控件模板和事件处理的相关知识点
  17. 本例所用到的自定义控件请参看:MyControls/MyControl3.cs
  18. -->
  19. <myControls:MyControl3 Background="Blue" BorderBrush="Yellow" BorderThickness="1" HorizontalAlignment="Left" Margin="5" />
  20.  
  21. </StackPanel>
  22. </Grid>
  23. </Page>

Controls/CustomControl/Demo3.xaml.cs

  1. /*
  2. * 本例用于演示自定义控件的控件模板和事件处理的相关知识点
  3. */
  4.  
  5. using Windows.UI.Xaml.Controls;
  6.  
  7. namespace Windows10.Controls.CustomControl
  8. {
  9. public sealed partial class Demo3 : Page
  10. {
  11. public Demo3()
  12. {
  13. this.InitializeComponent();
  14. }
  15. }
  16. }

OK
[源码下载]

背水一战 Windows 10 (79) - 自定义控件: Layout 系统, 控件模板, 事件处理的更多相关文章

  1. 背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性

    [源码下载] 背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性 作者:webabcd 介绍背水一战 Windows 10 之 控件(自定义控件) 自定义控件 ...

  2. 背水一战 Windows 10 (75) - 控件(控件基类): FrameworkElement - 基础知识, 相关事件, HorizontalAlignment, VerticalAlignment

    [源码下载] 背水一战 Windows 10 (75) - 控件(控件基类): FrameworkElement - 基础知识, 相关事件, HorizontalAlignment, Vertical ...

  3. 背水一战 Windows 10 (72) - 控件(控件基类): UIElement - UIElement 的位置, UIElement 的布局, UIElement 的其他特性

    [源码下载] 背水一战 Windows 10 (72) - 控件(控件基类): UIElement - UIElement 的位置, UIElement 的布局, UIElement 的其他特性 作者 ...

  4. 背水一战 Windows 10 (37) - 控件(弹出类): MessageDialog, ContentDialog

    [源码下载] 背水一战 Windows 10 (37) - 控件(弹出类): MessageDialog, ContentDialog 作者:webabcd 介绍背水一战 Windows 10 之 控 ...

  5. 背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox

    [源码下载] 背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox 作者:webabcd ...

  6. 背水一战 Windows 10 (7) - 控件 UI: VisualState, VisualStateManager, 控件的默认 UI

    [源码下载] 背水一战 Windows 10 (7) - 控件 UI: VisualState, VisualStateManager, 控件的默认 UI 作者:webabcd 介绍背水一战 Wind ...

  7. 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素

    [源码下载] 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中 ...

  8. 背水一战 Windows 10 (74) - 控件(控件基类): UIElement - 与 CanDrag 相关的事件, 与 AllowDrop 相关的事件

    [源码下载] 背水一战 Windows 10 (74) - 控件(控件基类): UIElement - 与 CanDrag 相关的事件, 与 AllowDrop 相关的事件 作者:webabcd 介绍 ...

  9. 背水一战 Windows 10 (73) - 控件(控件基类): UIElement - 拖放的基本应用, 手动开启 UIElement 的拖放操作

    [源码下载] 背水一战 Windows 10 (73) - 控件(控件基类): UIElement - 拖放的基本应用, 手动开启 UIElement 的拖放操作 作者:webabcd 介绍背水一战 ...

随机推荐

  1. (4)网络配置及CRT远程连接

    修改linux虚拟机中某一网卡的网络配置: 打开终端,输入命令vi /etc/sysconfig/network-scripts/ifcfg-eth0 在文件中写入以下内容: (这里有个错误,DNS要 ...

  2. 001之IP基础对话框

    在TCP/IP协议中,建立连接的两个进程(客户端和服务器)各自用一个socket(IP地址+TCP/UDP端口号)标识.在MFC中流式套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRA ...

  3. 1.Ansible安装以及配置

    本节内容以Centos7为系统环境进行讲解: 1.安装epel源,方便直接yum安装: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun ...

  4. Python介绍与安装

    Python 是一种面向对象的解释型程序设计语言,支持支持面向过程.函数式和面向对象编程.另外,Python可以在Windows.UNIX等多个操作系统上使用. 为什么学编程 编程是一种工具,可以实现 ...

  5. MYSQL性能优化(3)

    优化数据库对象 1.优化表的数据类型 select * from tbl1 procedure analyse(16,256) ,会输出优化建议,结合情况优化 2.拆分表(仅Myisam) 2.1 纵 ...

  6. phpstorm 不能自动打开上次的历史文件

    问题产生的原因:可能是电脑非正常关机,导致phpstrom 无法正常关闭. 一开始我以为是配置上那里出现了问题,所以直接就把配置删除了,然后生成了默认配置.发现还是无法解决问题.然后一个个配置查阅过去 ...

  7. JPA和SpringData知识梳理

    一. JPA,全称Java Persistence API,用于对象持久化的API,定义一套接口,来规范众多的ORM框架,所以它是在ORM框架之上的应用. 下面主要讲JPA在Hibernate基础上的 ...

  8. Pandas重塑和轴向旋转

    重塑和轴向旋转 Se import pandas as pd import numpy as np from pandas import Series data=pd.DataFrame(np.ara ...

  9. Django的rest_framework的权限组件和频率组件源码分析

    前言: Django的rest_framework一共有三大组件,分别为认证组件:perform_authentication,权限组件:check_permissions,频率组件:check_th ...

  10. Scrapy反爬

    1,随机更换 user-agent: 将足够多的user-agent放在settings中,在parse方法中调用 缺点:每一个request中都要调用这个方法 这个是scrapy的流程图. 既然每一 ...