[源码下载]

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

作者:webabcd

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

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

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

/*
* 本例通过一个自定义控件来演示 uwp 中可视元素的 Layout 系统
*
* uwp 的 layout 是一个递归系统,本 demo 就递归的一个过程做说明(步骤顺序参见代码注释中的序号)
*
*
* Measure() 的作用是测量尺寸
* Arrange() 的作用是排列元素
*/ using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.Foundation;
using System;
using System.Linq;
using System.Diagnostics;
using System.Collections.Generic; namespace MyControls
{
/// <summary>
/// 一个每行都会自动缩进的 Panel
/// </summary>
public sealed class MyControl2 : Panel
{
// 相对上一行的缩进值
const double INDENT = ; public MyControl2()
{ } // 1、首先爸爸知道自己能够提供的尺寸 availableSize,然后告诉儿子们
protected override Size MeasureOverride(Size availableSize) // 测量出期待的尺寸并返回
{
// 2、儿子们收到 availableSize 后,又结合了自身的实际情况,然后告诉爸爸儿子们所期望的尺寸 desiredSize
List<double> widthList = new List<double>();
Size desiredSize = new Size(, );
foreach (UIElement child in this.Children)
{
// 如果 child 是 FrameworkElement 的话,则当调用其 Measure() 方法时会自动调用其 MeasureOverride() 方法
child.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
widthList.Add(child.DesiredSize.Width);
desiredSize.Height += child.DesiredSize.Height;
} if (this.Children.Count > )
{
desiredSize.Width = widthList.Max();
desiredSize.Width += INDENT * (this.Children.Count - );
} Debug.WriteLine("availableSize: " + availableSize.ToString());
Debug.WriteLine("desiredSize: " + desiredSize.ToString()); return desiredSize;
} // 3、爸爸收到儿子们的反馈后,告诉儿子们自己最终提供的尺寸 finalSize
protected override Size ArrangeOverride(Size finalSize) // 排列元素,并返回呈现尺寸
{
// 4、儿子们根据 finalSize 安排各自的位置,然后爸爸的呈现尺寸也就确定了 renderSize
Point childPosition = new Point(, );
foreach (UIElement child in this.Children)
{
// 如果 child 是 FrameworkElement 的话,则当调用其 Arrange() 方法时会自动调用其 ArrangeOverride() 方法
child.Arrange(new Rect(childPosition, new Size(child.DesiredSize.Width, child.DesiredSize.Height)));
childPosition.X += INDENT;
childPosition.Y += child.DesiredSize.Height;
} Size renderSize = new Size(, );
renderSize.Width = finalSize.Width;
renderSize.Height = childPosition.Y; Debug.WriteLine("finalSize: " + finalSize.ToString());
Debug.WriteLine("renderSize: " + renderSize.ToString()); return finalSize;
}
}
} /*
* 输出结果如下(运行 /Controls/CustomControl/Demo2.xaml 示例)
* availableSize: 800,Double.PositiveInfinity
* desiredSize: 141,120
* finalSize: 800,120
* renderSize: 800,120
*/ /*
* 注:
* UIElement
* 调用 Measure() 方法后会更新 DesiredSize 属性
* 调用 Arrange() 方法后会更新 RenderSize 属性
* UpdateLayout() - 强制 layout 递归更新
*
* FrameworkElement - 继承自 UIElement
* MeasureOverride() - 在 Measure() 中自动调用
* ArrangeOverride() - 在 Arrange() 中自动调用
* ActualWidth 和 ActualHeight 来自 RenderSize,每次 UpdateLayout() 后都会被更新
*/ /*
* 注:
* 1、uwp 的 layout 是一个递归系统
* 2、UIElement 的 InvalidateMeasure() 就是递归调用自己和子辈门的 Measure()
* 3、UIElement 的 InvalidateArrange() 就是递归调用自己和子辈门的 Arrange()
*
* 一个通过 uwp 自带控件说明 layout 的示例,请参见:/Controls/BaseControl/UIElementDemo/LayoutDemo.xaml.cs
*/

Controls/CustomControl/Demo2.xaml

<Page
x:Class="Windows10.Controls.CustomControl.Demo2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows10.Controls.CustomControl"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" xmlns:myControls="using:MyControls"> <Grid Background="Transparent">
<StackPanel Margin="10 0 10 10"> <!--
演示元素的 Layout 系统
本例所用到的自定义控件请参看:MyControls/MyControl2.cs
-->
<myControls:MyControl2 Margin="5" Background="Orange" HorizontalAlignment="Left" Width="800">
<myControls:MyControl2.Children>
<TextBlock Text="aaaaaaaa" Margin="5" />
<TextBlock Text="bbbbbbbb" Margin="5" />
<TextBlock Text="cccccccc" Margin="5" />
<TextBlock Text="dddddddd" Margin="5" />
</myControls:MyControl2.Children>
</myControls:MyControl2> </StackPanel>
</Grid>
</Page>

Controls/CustomControl/Demo2.xaml.cs

/*
* 本例用于演示元素的 Layout 系统
*/ using Windows.UI.Xaml.Controls; namespace Windows10.Controls.CustomControl
{
public sealed partial class Demo2 : Page
{
public Demo2()
{
this.InitializeComponent();
}
}
}

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

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MyControls"> <Style TargetType="local:MyControl3">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl3"> <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<TextBlock Name="textBlock" Foreground="White" FontSize="24" />
</StackPanel> <VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="border" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="Green" />
</Storyboard>
</VisualState> <VisualStateGroup.Transitions>
<VisualTransition To="PointerOver" GeneratedDuration="0:0:1">
<VisualTransition.GeneratedEasingFunction>
<ElasticEase EasingMode="EaseInOut" />
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border> </ControlTemplate>
</Setter.Value>
</Setter>
</Style> </ResourceDictionary>

/MyControls/MyControl3.cs

/*
* 开发一个自定义控件,用于演示控件模板和事件处理的相关知识点
*/ using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Input; namespace MyControls
{
/// <summary>
/// 自定义控件
/// </summary>
public sealed class MyControl3 : Control
{
public MyControl3()
{
this.DefaultStyleKey = typeof(MyControl3);
} // ApplyTemplate() - 强制加载控件模板,一般不用调用(因为控件模板会自动加载)。有一种使用场景是:当父控件应用控件模板时要求子控件必须先应用控件模板以便父控件使用时,则可以先调用子控件的此方法
// GetTemplateChild() - 查找控件模板中的指定名字的元素
// override OnApplyTemplate() - 应用控件模板时调用
protected override void OnApplyTemplate()
{
base.OnApplyTemplate(); TextBlock textBlock = (TextBlock)GetTemplateChild("textBlock");
if (this.Background is SolidColorBrush)
{
textBlock.Text = $"background: {((SolidColorBrush)this.Background).Color}";
} VisualStateManager.GoToState(this, "Normal", false);
} // override GoToElementStateCore() - VisualState 转换时调用(此方法仅在自定义 ContentPresenter 并将其应用于 GridView 或 ListView 的 ItemContainerStyle 时才会被调用)
// 参见:/Controls/CollectionControl/ItemsControlDemo/MyItemPresenter.cs
protected override bool GoToElementStateCore(string stateName, bool useTransitions)
{
return base.GoToElementStateCore(stateName, useTransitions);
} // 在 Control 中有很多可 override 的事件处理方法,详见文档
protected override void OnPointerEntered(PointerRoutedEventArgs e)
{
VisualStateManager.GoToState(this, "PointerOver", true);
} protected override void OnPointerExited(PointerRoutedEventArgs e)
{
VisualStateManager.GoToState(this, "Normal", false);
}
}
}

Controls/CustomControl/Demo3.xaml

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

Controls/CustomControl/Demo3.xaml.cs

/*
* 本例用于演示自定义控件的控件模板和事件处理的相关知识点
*/ using Windows.UI.Xaml.Controls; namespace Windows10.Controls.CustomControl
{
public sealed partial class Demo3 : Page
{
public Demo3()
{
this.InitializeComponent();
}
}
}

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. java利用泛型实现不同类型可变参数

    public class VP { public <T> void printMsg(T... args){ for (T t:args){ System.out.println(&quo ...

  2. PHPsocket、CURL、File_get_contents采集

    1.socket采集.采用最底层的,它只是建立一个长连接,然后我们自己构造http协议字符串去发送请求.例如想获取这个页面内容(http://tv.youku.com/?spm=a2hww.20023 ...

  3. javascript中let和var的区别

    let是es6中新增命令,也是用来声明变量的,可能很多小伙伴都像我一样,定义变量的时候都会用var而很少用到let,那么,let和var到底有什么区别呢? let和var的区别体现在作用域上.var的 ...

  4. 关于Bootstrap的入门知识

    问:Bootstrap是什么? 答:开源的前端框架,就是一些事先写好的css.js等. 问:Bootstrap在哪儿下载? 答:官方(https://getbootstrap.com/),中文(htt ...

  5. 剑指offer例题——反转链表

    题目描述 输入一个链表,反转链表,输出新链表的表头 程序编写 将链表反转 public class Solution { public ListNode ReverseList(ListNode he ...

  6. 高性能迷你React框架anujs1.0.8发布

    本版本由于得到业务线同学的大力支持,掀出许多问题,因此改进地方良多,为anujs在完美替换React的道路上前进了不少.现在anujs经测试可以运行于IE7中.至少怎么做可以参看官网,https:// ...

  7. DJango 基础 (1)

    django基础 知识点: 基本认知 工具准备 新建项目 目录及文件说明 开发服务器 创建视图函数 新建应用(app) 1.基本认知 Django是用Python开发的一个免费开源的Web框架,可以用 ...

  8. CSS文本超出指定行数省略显示

    单行: overflow: hidden; text-overflow: ellipsis; white-space: nowrap; 2行: font-size: 17px;overflow: hi ...

  9. yum -y install php-mysql 版本冲突

    yum -y install  php-mysql 版本冲突 2018年09月02日 19:16:59 乐于技术分享 阅读数:640   [root@itop yum.repos.d]# yum -y ...

  10. vue-if和v-show区别

    vue-if和vue-show都是对条件进行判断,一直不明白他们的区别,知道看到了官方文档中的解释: v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和 ...