Windows Community Toolkit 3.0 - InfiniteCanvas
概述
InfiniteCanvas 是一个 Canvas 控件,它支持无限画布的滚动,支持 Ink,文本,格式文本,画布缩放操作,撤销重做操作,导入和导出数据。
这是一个非常实用的控件,在“来画视频” UWP 应用的绘画功能中,也用到了这个控件,它对不同画笔的选择,橡皮擦,直尺和圆形尺,文字输入和字体选择等都提供了很便捷的支持,而且支持导入和导出数据,可以很方便的创作绘画作品,并能导出和分享给别人。
下面是 Windows Community Toolkit Sample App 的示例截图和 code/doc 地址:

Windows Community Toolkit Doc - InfiniteCanvas
Windows Community Toolkit Source Code - InfiniteCanvas
Namespace: Microsoft.Toolkit.Uwp.UI.Controls; Nuget: Microsoft.Toolkit.Uwp.UI.Controls;
开发过程
代码结构分析
首先来看 InfiniteCanvas 的代码结构,组成如下:
- Commands - InfiniteCanvas 对应的所有命令,包括 redo/undo,Ink,Text 等,如上面示例图中 Toolbar 上所示;
- Controls - InfiniteCanvas 的主要控件都在这个文件夹里;
- Drawables - Text 和 Ink 主要的绘制功能在这个文件夹里;
- JsonConverters - 序列化和反序列化的主要功能,以及自定义的 Ink 属性等;
- InfiniteCanvas.Events.cs - InfiniteCanvas 的主要事件处理逻辑;
- InfiniteCanvas.TextBox.cs - InfiniteCanvas 添加文字的文本框控件处理逻辑;
- InfiniteCanvas.cs - InfiniteCanvas 控件的主要处理逻辑;
- InfiniteCanvas.xaml - InfiniteCanvas 控件的 XAML 样式文件;

InfiniteCanvas 整体类结构很清晰,每个类的功能也很明确,下面我们选取几个重要的类来做分析。
1. InfiniteCanvasCreateInkCommand
Command 文件夹的每一个类都比较简单,我们找一个创建 Ink 命令看一下;该类实现了 IInfiniteCanvasCommand 这个接口,实现了 Execute() 和 Undo() 两个方法;Command 初始化也很简单,创建一个 InkDrawable 对象,初始化 drawableList 对象,执行创建时加入该 drawable,撤销时把它从 drawableList 中去掉。
internal class InfiniteCanvasCreateInkCommand : IInfiniteCanvasCommand
{
private readonly List<IDrawable> _drawableList;
private readonly InkDrawable _drawable;
public InfiniteCanvasCreateInkCommand(List<IDrawable> drawableList, IReadOnlyList<InkStroke> strokes)
{
_drawable = new InkDrawable(strokes);
_drawableList = drawableList;
}
public void Execute()
{
_drawableList.Add(_drawable);
}
public void Undo()
{
_drawableList.Remove(_drawable);
}
}
2. InfiniteCanvasTextBox
用于 InfiniteCanvas 的文本框控件,从下图的结构中可以看到完整的文本框属性定义方法,包括设置文字,设置编辑区域尺寸,文字变化的处理,光标位置的限制等。

来看一下判断光标能够下移一行的 CannotGoDown() 方法,按照换行符来切割文字行,如果只有一行则不可下移;当前选择的结束,在最后一行时,也不可下移,其他情况都可以下移;
internal bool CannotGoDown()
{
var lines = _editZone.Text.Split('\r');
)
{
return true;
}
);
if ((_editZone.Text.Length - lastLine.Length) <= (_editZone.SelectionStart + _editZone.SelectionLength))
{
return true;
}
return false;
}
3. InfiniteCanvasVirtualDrawingSurface
用于渲染 Ink 和 Text 的虚拟 drawing surface,它有几个部分类组成:

主要的处理逻辑,是利用 Commands 来操作 Ink 和 Text 的渲染执行和撤销操作,计算渲染的尺寸空间,组织渲染的内容。
4. InkDrawable 和 TextDrawable
Ink 和 Text 可绘画元素的绘画逻辑,分别来看一下两个类的组成:

我们看一下两个类的 Draw 方法:
Draw() - InkDrawable:
获得 Strokes 中每个线条的每个点,加入到集合中,从点集合创建线条,最后生成新的 Stroke 列表;遍历完成后,把新的 Stroke 列表用于 drawingSession 的 DrawInk 方法来实现绘制;
public void Draw(CanvasDrawingSession drawingSession, Rect sessionBounds)
{
var finalStrokeList = new List<InkStroke>(Strokes.Count);
foreach (var stroke in Strokes)
{
var points = stroke.GetInkPoints();
var finalPointList = new List<InkPoint>(points.Count);
foreach (var point in points)
{
finalPointList.Add(MapPointToToSessionBounds(point, sessionBounds));
}
StrokeBuilder.SetDefaultDrawingAttributes(stroke.DrawingAttributes);
var newStroke = StrokeBuilder.CreateStrokeFromInkPoints(finalPointList, stroke.PointTransform);
finalStrokeList.Add(newStroke);
}
drawingSession.DrawInk(finalStrokeList);
}
Draw() - TextDrawble:
设置 Canvas 中文本的格式,使用文本和格式设置的 textLayout 来用于 drawingSession 的 DrawTextLayout 方法实现绘制;根据字体大小设置横向偏移 HorizontalMarginBasedOnFont,固定的纵向偏移 verticalMargin;
public void Draw(CanvasDrawingSession drawingSession, Rect sessionBounds)
{
;
CanvasTextFormat format = new CanvasTextFormat
{
FontSize = FontSize,
WordWrapping = CanvasWordWrapping.NoWrap,
FontWeight = IsBold ? FontWeights.Bold : FontWeights.Normal,
FontStyle = IsItalic ? FontStyle.Italic : FontStyle.Normal
};
CanvasTextLayout textLayout = new CanvasTextLayout(drawingSession, Text, format, 0.0f, 0.0f);
drawingSession.DrawTextLayout(textLayout, (float)(Bounds.X - sessionBounds.X + HorizontalMarginBasedOnFont), (float)(Bounds.Y - sessionBounds.Y + verticalMargin), TextColor);
}
5. InfiniteCanvas
InfiniteCanvas 是主要逻辑处理,由 InfiniteCanvas.cs,InfiniteCanvas.Events.cs,InfiniteCanvas.TextBox.cs 三个部分类组成。
- 其中 InfiniteCanvas.cs 这个类中主要是实现 OnApplyTemplate(),DependencyProperty 处理,控件的定义,事件注册,Canvas 的基础事件处理等,InfiniteCanvas 中实现了一个 InkCanvas 所以可以实现各种笔触的笔迹绘制;
- InfiniteCanvas.Events.cs 主要是 Canvas 中的各种按钮点击等事件处理;
- InfiniteCanvas.TextBox.cs 主要是 Canvas 中 TextBox 控件对应的控件定义和事件处理;
调用示例
InfiniteCanvas 控件的调用非常简单,下面看看 XAML 中的调用:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<controls:InfiniteCanvas Name="canvas" IsToolbarVisible="True"/>
</Grid>
</Page>
总结
到这里我们就把 Windows Community Toolkit 3.0 中的 InfiniteCanvas 的源代码实现过程讲解完成了,希望能对大家更好的理解和使用这个功能有所帮助。InfiniteCanvas 控件在绘画类场景中有非常多的应用,控件默认实现了多种笔触的绘画,橡皮,文字,redo undo 等重要功能,开发者也可以根据 InfiniteCanvas 的实现自定义 Toolbar 的样式和更多的绘画笔触,不同的笔画保存方式等。
最后,再跟大家安利一下 WindowsCommunityToolkit 的官方微博:https://weibo.com/u/6506046490, 大家可以通过微博关注最新动态。
衷心感谢 WindowsCommunityToolkit 的作者们杰出的工作,感谢每一位贡献者,Thank you so much, ALL WindowsCommunityToolkit AUTHORS !!!
Windows Community Toolkit 3.0 - InfiniteCanvas的更多相关文章
- Windows Community Toolkit 3.0 新功能 在WinForms 和 WPF 使用 UWP 控件
本文告诉大家一个令人震惊的消息,Windows Community Toolkit 有一个大更新,现在的版本是 3.0 .最大的提升就是 WinForm 和 WPF 程序可以使用部分 UWP 控件. ...
- Windows Community Toolkit 4.0 - DataGrid - Part03
概述 在上面一篇 Windows Community Toolkit 4.0 - DataGrid - Part02 中,我们针对 DataGrid 控件的 Utilities 部分做了详细分享.而在 ...
- Windows Community Toolkit 4.0 - DataGrid - Part02
概述 在上面一篇 Windows Community Toolkit 4.0 - DataGrid - Part01 中,我们针对 DataGrid 控件的 CollectionView 部分做了详细 ...
- Windows Community Toolkit 4.0 - DataGrid - Part01
概述 在上面一篇 Windows Community Toolkit 4.0 - DataGrid - Overview 中,我们对 DataGrid 控件做了一个概览的介绍,今天开始我们会做进一步的 ...
- Windows Community Toolkit 4.0 - DataGrid - Overview
概述 Windows Community Toolkit 4.0 于 2018 月 8 月初发布:Windows Community Toolkit 4.0 Release Note. 4.0 版本相 ...
- Windows Community Toolkit 3.0 - UniformGrid
概述 UniformGrid 控件是一个响应式的布局控件,允许把 items 排列在一组均匀分布的行或列中,以填充整体的可用显示空间,形成均匀的多个网格.默认情况下,网格中的每个单元格大小相同. 这是 ...
- Windows Community Toolkit 3.0 - Gaze Interaction
概述 Gaze Input & Tracking - 也就是视觉输入和跟踪,是一种和鼠标/触摸屏输入非常不一样的交互方式,利用人类眼球的识别和眼球方向角度的跟踪,来判断人眼的目标和意图,从而非 ...
- Windows Community Toolkit 3.0 - CameraPreview
概述 Windows Community Toolkit 3.0 于 2018 年 6 月 2 日 Release,同时正式更名为 Windows Community Toolkit,原名为 UWP ...
- 与众不同 windows phone (44) - 8.0 位置和地图
[源码下载] 与众不同 windows phone (44) - 8.0 位置和地图 作者:webabcd 介绍与众不同 windows phone 8.0 之 位置和地图 位置(GPS) - Loc ...
随机推荐
- 关于最新笔记本机型预装win8如何更换为win7的解决办法
关于最新笔记本机型预装win8如何更换为win7的解决办法 目前新出的很多机型出厂自带的都是win8系统,可能有些人用不习惯,想更换为win7系统,但是由于这些机型主板都采用UEFI这种接口(硬盘分区 ...
- JAVA项目从运维部署到项目开发(二.ZooKeeper)
一.zookeeper的相关介绍 点击查看 二.下载.安装与配置 1.ZooKeeper官网下载地址(点击跳转),当前稳定版本为V3.4.12.Liniux下可以在指定目录,使用wget命令下载. h ...
- CSS杂谈(2)
opacity 属性设置元素的不透明级别. 语法 opacity: value|inherit; 值 描述 value 规定不透明度.从 0.0 (完全透明)到 1.0(完全不透明). i ...
- EOS智能合约开发(二):EOS创建和管理钱包
上节介绍了EOS智能合约开发之EOS环境搭建及启动节点 那么,节点启动后我们要做的第一件事儿是什么呢?就是我们首先要有账号,但是有账号的前提是什么呢?倒不是先创建账号,而是先要有自己的一组私钥,有了私 ...
- iOS 让视图UIView 单独显示某一侧的边框线
有时候需要让view显示某一侧的边框线,这时设置layer的border是达不到效果的.在网上查阅资料发现有一个投机取巧的办法,原理是给view的layer再添加一个layer,让这个layer充当边 ...
- JaveScript 中使用 XSLT转换XML文档
我们经常将数据存储在XML 中,在展示的时候需要转换为其它的形式,这里介绍使用XSLT 对XML数据进行转换. 要学习XSLT对XML的转换,需要先了解三个文件. 第一个是存储数据的XML文件:emp ...
- 一、Selenium 工作原理
1.Selenium介绍 Selenium是用于测试Web应用程序用户界面UI的常用框架.端对端的功能测试.并且在一个多个浏览器中操作. 目前Seienium 组件主要包括Selenium IDE ...
- [Hive_add_3] Hive 进行简单数据处理
0. 说明 通过 Hive 对 duowan 数据进行简单处理 1. 操作流程 1.1 建表 create table duowan(id int, name string, pass string, ...
- C# -- 使用XmlDocument或XDocument创建xml文件
使用XmlDocument或XDocument创建xml文件 需引用:System.Xml; System.Xml.Linq; 1.使用XmlDocument创建xml(入门案例) static vo ...
- JS页面打印
平常浏览网页和文档的时候,随处可见打印两个字,有时候不小心点到或者快捷键触发到,就会弹出一个打印的页面,上边显示的打印机是GoldGrid Virtual Printer,这是计算机的虚拟打印机,打印 ...