背水一战 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 系统, 控件模板, 事件处理的更多相关文章
- 背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性
[源码下载] 背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性 作者:webabcd 介绍背水一战 Windows 10 之 控件(自定义控件) 自定义控件 ...
- 背水一战 Windows 10 (75) - 控件(控件基类): FrameworkElement - 基础知识, 相关事件, HorizontalAlignment, VerticalAlignment
[源码下载] 背水一战 Windows 10 (75) - 控件(控件基类): FrameworkElement - 基础知识, 相关事件, HorizontalAlignment, Vertical ...
- 背水一战 Windows 10 (72) - 控件(控件基类): UIElement - UIElement 的位置, UIElement 的布局, UIElement 的其他特性
[源码下载] 背水一战 Windows 10 (72) - 控件(控件基类): UIElement - UIElement 的位置, UIElement 的布局, UIElement 的其他特性 作者 ...
- 背水一战 Windows 10 (37) - 控件(弹出类): MessageDialog, ContentDialog
[源码下载] 背水一战 Windows 10 (37) - 控件(弹出类): MessageDialog, ContentDialog 作者:webabcd 介绍背水一战 Windows 10 之 控 ...
- 背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox
[源码下载] 背水一战 Windows 10 (29) - 控件(文本类): RichTextBlock, RichTextBlockOverflow, RichEditBox 作者:webabcd ...
- 背水一战 Windows 10 (7) - 控件 UI: VisualState, VisualStateManager, 控件的默认 UI
[源码下载] 背水一战 Windows 10 (7) - 控件 UI: VisualState, VisualStateManager, 控件的默认 UI 作者:webabcd 介绍背水一战 Wind ...
- 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中的元素
[源码下载] 背水一战 Windows 10 (76) - 控件(控件基类): Control - 基础知识, 焦点相关, 运行时获取 ControlTemplate 和 DataTemplate 中 ...
- 背水一战 Windows 10 (74) - 控件(控件基类): UIElement - 与 CanDrag 相关的事件, 与 AllowDrop 相关的事件
[源码下载] 背水一战 Windows 10 (74) - 控件(控件基类): UIElement - 与 CanDrag 相关的事件, 与 AllowDrop 相关的事件 作者:webabcd 介绍 ...
- 背水一战 Windows 10 (73) - 控件(控件基类): UIElement - 拖放的基本应用, 手动开启 UIElement 的拖放操作
[源码下载] 背水一战 Windows 10 (73) - 控件(控件基类): UIElement - 拖放的基本应用, 手动开启 UIElement 的拖放操作 作者:webabcd 介绍背水一战 ...
随机推荐
- 系统计划 Cron作业 为什么/etc/crontab /etc/cron.d /etc/cron.* 那么多的定义方式????
当我们要增加全局性的计划任务时,一种方式是直接修改/etc/crontab.但是,一般不建议这样做,/etc/cron.d目录就是为了解决这种问题而创建的.例如,增加一项定时的备份任务,我们可以这样处 ...
- maven的单元测试中没有
原因:BaseTest没有找到单元测试造成的 增加一个空的单元测试 @Testpublic void testNothing(){} 异常现象:在maven项目执行mvn install 或mvn t ...
- PL2303 USB转串口 com
PL2303 USB转串口 com PL-2303 XA/HXA chip http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=225&pc ...
- python练习题_01
1.执行python的两种方式 答:1.通过解释器执行1.py 2.通过cmd执行python,再执行1.py 2.简述位与字节的的关系 答:8位=1字节(计算机处理时以字节为单位,存储时以位为单位) ...
- 尚硅谷springboot学习31-jdbc数据连接
可以使用JdbcTemplate操作数据库,可以在启动的时候自动建表,更新数据表 配置依赖 <dependency> <groupId>org.springframework. ...
- MySQL innodb_autoinc_lock_mode 详解
innodb_autoinc_lock_mode这个参数控制着在向有auto_increment 列的表插入数据时,相关锁的行为: 通过对它的设置可以达到性能与安全(主从的数据一致性)的平衡 [0]我 ...
- test case VS test scenario
---恢复内容开始--- 1. test case: how to test --如何测试 test scenario: what to be tested --测试什么 2. test scen ...
- C++ 11 创建和使用 unique_ptr
unique_ptr 不共享它的指针.它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法.只能移动unique_ptr.这意味着,内存资 ...
- GCD - Extreme (II) (欧拉函数妙用)
https://cn.vjudge.net/problem/UVA-11426 题意:求 解题思路:我们可以定义一个变量dis[n],dis[n]意为1~(n-1)与n的gcd(最大公约数)的总和,那 ...
- stark组件开发之列表页面应用示例
已经解决的,自定义的扩展函数,功能.但是 不可能返回. 一个 固定的页面把! 应该是,点击那条 记录之后的编辑, 就会跳转到相应的,编辑页面.所以 这个标签的 <a href="/ ...