大家好,由于很多原因,我有很长一段时间没有在 CSDN 上分享我的学习成果了,如今终于可以回归分享之路了。

之前在做一个项目的时候,想在一个区域里绘制自己的图形,于是上网搜索资料,无意中找到了 InkCanvas ,但我们最终并没有在项目里使用它,不过它的强大确深深地印在了我的脑海中。之后学院年级会举办一个比赛,本来没打算参加,不过一觉醒来被告知室友已经给我报上名了,无奈之下只得借助 WPF 中的 InkCanvas 来赶出一个作品。

不过这次经历让我熟悉了 InkCanvas 的一些基本使用,之前在网上搜到的资料都不是很满意,于是这里给大家奉上我的学习成果。

首先来简单介绍一下什么是 InkCanvas 。顾名思义, InkCanvas 和 Canvas 有一定的联系,都是一种画布,我们可以在上面绘制我们的图形等等。

那么 InkCanvas 和 Canvas 有什么区别呢?那就是 InkCanvas 集成了一些很方便的功能,使我们不必再用代码去实现那些功能,下面将结合实例讲解如何使用这些功能。

现在先来创建一个 WPF 应用程序,然后创建一个 InkCanvas 标签。

  1. <Window x:Class="Blog_InkCanvas.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="MainWindow" Height="350" Width="525">
  5. <Grid>
  6. <InkCanvas x:Name="inkCanvas"/>
  7. </Grid>
  8. </Window>

运行程序并且按住鼠标左键即可自右绘制墨迹。

InkCanvas 提供的最基本的功能是自由笔,我们这里称显示出来的图形为墨迹,而绘制出来的墨迹实际上是 Stroke 类型,所以我们可以用 Stroke 类型的 DrawingAttributes 属性进行墨迹的一些设置,例如颜色,粗细等等。

那么既然如此,我们就先来改变一下墨迹的颜色,将前面的 XAML 文件对应的后置代码文件的内容修改为如下所示:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Documents;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. using System.Windows.Navigation;
  14. using System.Windows.Shapes;
  15. using System.Windows.Ink;
  16. namespace Blog_InkCanvas
  17. {
  18. /// <summary>
  19. /// MainWindow.xaml 的交互逻辑
  20. /// </summary>
  21. public partial class MainWindow : Window
  22. {
  23. //声明一个 DrawingAttributes 类型的变量
  24. DrawingAttributes drawingAttributes;
  25. public MainWindow()
  26. {
  27. InitializeComponent();
  28. //创建 DrawingAttributes 类的一个实例
  29. drawingAttributes = new DrawingAttributes();
  30. //将 InkCanvas 的 DefaultDrawingAttributes 属性的值赋成创建的 DrawingAttributes 类的对象的引用
  31. //InkCanvas 通过 DefaultDrawingAttributes 属性来获取墨迹的各种设置,该属性的类型为 DrawingAttributes 型
  32. inkCanvas.DefaultDrawingAttributes = drawingAttributes;
  33. //设置 DrawingAttributes 的 Color 属性设置颜色
  34. drawingAttributes.Color = Colors.Red;
  35. }
  36. }
  37. }

再次运行程序,会发现墨迹颜色变成了红色。

接下来我们同样是通过 DrawingAttributes 对象来改变墨迹的各项设置,在上面的代码后面添加如下代码:

  1. //利用 DrawingAttributes 的 Width 和 Height 属性来设置墨迹的宽度和高度
  2. //注意墨迹的宽度和高度是两个概念
  3. //宽度在垂直方向上能显现出来,而高度在水平方向上能显现出来
  4. drawingAttributes.Width = 20;
  5. drawingAttributes.Height = 10;
  6. //利用 DrawingAttributes 的StylusTip 属性可以设置墨迹触笔的形状,默认值是 StylusTip.Ellipse
  7. //将墨迹的宽度和高度都设置为稍大一些可以清楚的看到差别,如果较小则不太容易看出差别
  8. //这里宽度和高度都已经较大了,所以很容易看出差别,读者可以把下面一行代码反复注释或取消注释观察几次
  9. drawingAttributes.StylusTip = StylusTip.Rectangle;

继续运行程序。

InkCanvas 还提供了平滑处理功能。

  1. //将 FitToCurve 属性设置为 true 会在你绘制完一次墨迹后自动利用贝塞尔曲线来对你的墨迹进行平滑处理
  2. //为了使效果更明显,测试时请尽可能地使所绘制的墨迹显得杂乱无章,这样绘制完成后即可看到效果
  3. //这个就不截图演示了
  4. drawingAttributes.FitToCurve = true;

InkCanvas 还有两个属性,一个是 IsHeighlighter ,另一个是 IgnorePressure ,这两个属性都是布尔值,前者是判断墨迹是否有荧光笔效果,后者是判断墨迹的粗细是否随压力的增大而增大。

  1. //设置 IsHighlighter 属性为 true ,则墨迹显示的时候看上去像是荧光笔
  2. //官方文档上说这样做会使 Stroke 变的透明一些,可以显示覆盖住的墨迹,但是我感觉不太像透明,大家可以自己试试,也欢迎纠正
  3. drawingAttributes.IsHighlighter = false;
  4. //按照微软官方文档上的说法,设置 IgnorePressure 属性为 true墨迹粗细会随压力的增大而增大
  5. //但同时也说了 XAML 一般不使用此属性,我也实在找不到如何利用鼠标来进行压力的变化
  6. //所以这里我想大家做个了解应该就可以了
  7. drawingAttributes.IgnorePressure = true;

前面介绍了 InkCanvas 墨迹的一些属性,但是 InkCanvas 的强大远远不止这些,它还有几个非常好用的功能。请看如下代码:

  1. <Window x:Class="Blog_InkCanvas.MainWindow"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="MainWindow" Height="350" Width="525">
  5. <Grid>
  6. <Grid.RowDefinitions>
  7. <RowDefinition Height="9*"/>
  8. <RowDefinition/>
  9. </Grid.RowDefinitions>
  10. <InkCanvas x:Name="inkCanvas" Grid.Row="0"/>
  11. <Grid Grid.Row="1">
  12. <Grid.ColumnDefinitions>
  13. <ColumnDefinition/>
  14. <ColumnDefinition/>
  15. <ColumnDefinition/>
  16. <ColumnDefinition/>
  17. <ColumnDefinition/>
  18. </Grid.ColumnDefinitions>
  19. <RadioButton Click="RadioButton_Click" Grid.Column="0">绘制墨迹</RadioButton>
  20. <RadioButton Click="RadioButton_Click" Grid.Column="1">按点擦除</RadioButton>
  21. <RadioButton Click="RadioButton_Click" Grid.Column="2">按线擦除</RadioButton>
  22. <RadioButton Click="RadioButton_Click" Grid.Column="3">选中墨迹</RadioButton>
  23. <RadioButton Click="RadioButton_Click" Grid.Column="4">停止操作</RadioButton>
  24. </Grid>
  25. </Grid>
  26. </Window>

将主页面 XAML 代码修改如上面,并在原来的后置 .cs 文件的构造函数之后添加如下方法:

  1. //更改 InkCanvas 对象的 EditingMode 属性,可以改变要在 InkCanvas 上执行的操作
  2. //该属性的值是一个 InkCanvasEditingMode 枚举,常见功能如下
  3. private void RadioButton_Click(object sender, RoutedEventArgs e)
  4. {
  5. if((sender as RadioButton).Content.ToString() == "绘制墨迹")
  6. {
  7. //绘制墨迹
  8. inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
  9. }
  10. else if((sender as RadioButton).Content.ToString() == "按点擦除")
  11. {
  12. //使用橡皮擦按点擦除墨迹
  13. inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
  14. }
  15. else if ((sender as RadioButton).Content.ToString() == "按线擦除")
  16. {
  17. //使用橡皮擦按绘制的墨迹将某一笔墨迹擦除掉,注意是某一笔,如果多次绘制但是有交叉也是不可以的
  18. inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
  19. }
  20. else if ((sender as RadioButton).Content.ToString() == "选中墨迹")
  21. {
  22. //选中某一笔墨迹,进行拖动和缩放以及按 Delete 键删除,注意是某一笔
  23. inkCanvas.EditingMode = InkCanvasEditingMode.Select;
  24. }
  25. else if ((sender as RadioButton).Content.ToString() == "停止操作")
  26. {
  27. //不做任何
  28. inkCanvas.EditingMode = InkCanvasEditingMode.None;
  29. }
  30. }

InkCanvas 的EditingMode 属性还有其他几个值,但是基本的就是这几个了,详细信息请参看 MSDN 。运行程序,并选择相应功能,即可看到效果。

利用 InkCanvas 不仅可以完成 Canvas 的功能,还可以非常方便地使用其他一些操作,对于绘图类功能开发来说非常好用。

另外有一点需要注意,在 InkCanvas 上绘制的 Stroke 墨迹并不是 InkCanvas 对象 Children 集合类型属性里的元素,所有用该属性的 Clear() 方法是不能清除已绘制上去的墨迹的。

本文就到此结束了,希望大家多多批评指正,谢谢!

WPF InkCanvas 画图 基础使用教程的更多相关文章

  1. [WPF系列]从基础起步学习系列计划

    引言 WPF技术已经算不什么新技术,一搜一大把关于WPF基础甚至高级的内容.之前工作中一直使用winform所以一直没有深入学习WPF,这次因项目中使用了WPF技术来实现比较酷的展示界面.我在这里只是 ...

  2. WPF InkCanvas 毛笔效果

    原文:WPF InkCanvas 毛笔效果 1.先来看看InkCanvas的一般用法: <InkCanvas>     <InkCanvas.DefaultDrawingAttrib ...

  3. SOA体系结构基础培训教程-规范标准篇

    引子:本文是<SOA体系结构基础培训教程>第3章<SOA标准与规范>课件,版权所有,转载请注明出处. 随着SOA在业界的应用日益广泛,SOA的标准化问题也成为各界日益关注的焦点 ...

  4. [置顶] IOS 基础入门教程

    IOS 基础入门教程 教程列表: IOS 简介 IOS环境搭建 Objective C 基础知识 创建第一款iPhone应用程序 IOS操作(action)和输出口(Outlet) iOS - 委托( ...

  5. Python基础入门教程

    Python基础入门教程 Python基础教程 Python 简介 Python环境搭建 Python 基础语法 Python 变量类型 Python 运算符 Python 条件语句 Python 循 ...

  6. SOA体系结构基础培训教程

    SOA体系结构基础培训教程-规范标准篇 引子:本文是<SOA体系结构基础培训教程>第3章<SOA标准与规范>课件,版权所有,转载请注明出处. 随着SOA在业界的应用日益广泛,S ...

  7. Angularjs 2 绝对零基础的教程(1):从安装配置开始

    写在前面 适合人群: 1. 愿意未来从事前端工作,并以此开拓自己未来职业 2. 有任何一种编程语言基础 3. 喜欢简单粗暴学一门实用的技术,而不是做科研. Angular 2 比 Angular 1 ...

  8. React Native基础&入门教程:初步使用Flexbox布局

    在上篇中,笔者分享了部分安装并调试React Native应用过程里的一点经验,如果还没有看过的同学请点击<React Native基础&入门教程:调试React Native应用的一小 ...

  9. 【转】IAR Embedded Workbench for ARM 8.22.1 基础使用教程

    @2018-12-15 [小记] IAR Embedded Workbench for ARM 8.22.1 基础使用教程

随机推荐

  1. brctl 的使用

    brctl  作用: 用来进行以太网桥接(bridge)的管理 主要用法如下: root@hbg:/# brctl --helpBusyBox v1.22.1 (2016-02-24 11:41:04 ...

  2. yii框架中关于控制器中filter过滤器和外部action的使用

    在yii框架中,控制器的过滤器分为执行前和执行后,这里举例是在执行控制器前的过滤. 需要在components/文件夹下定义公共的TestAction.php文件,并且实现run()方法.这个acti ...

  3. FZU 1894 志愿者选拔 单调队列

    训练赛的题…… 暴力一波明显超时…… 最近刚学stl 感觉是优先队列 但还是太会用…… 以后可以试一下优先队列…… 比赛之后百度了一下 发现是单调队列…… 看起来挺简单的 也算个模版题吧…… 总之思路 ...

  4. digitalocean最新优惠码赠送10美元

    digitalocean是我非常喜欢的vps服务商,目前手头还有十来个digitalocean vps服务器.用了三年多digitalocean后,我发现digitalocean一点小技巧.比如,如果 ...

  5. Visual Studio 2013 新增web项目IIS Express的64位版   转载来源http://www.cnblogs.com/jianyus/p/3524335.html

    使用Visual Studio 2012开发SharePoint的应该都遇到过下面的错误“SharePoint 在32位进程中不受支持”,而怎么修改目标平台都不好使,因为VS 2012所配备的IIS ...

  6. A - 小彭玉的扫荡食堂计划

    A - 小彭玉的扫荡食堂计划 Time Limit: 20000/10000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Others) ...

  7. python多线程,多进程

    线程是公用内存,进程内存相互独立 python多线程只能是一个cpu,java可以将多个线程平均分配到其他cpu上 以核为单位,所以GIL(全局锁,保证线程安全,数据被安全读取)最小只能控制一个核,很 ...

  8. sql 将表B中不存在表A的数据 插入到表A中

    insert into tableA select * from tableB b where not exists(select 1 from tableA a where a.id = b.id) ...

  9. Flask -- 使用数据库(Sqlite3)、用户注册、登录注销、修改密码

    # 使用sqlite数据库 import sqlite3from contextlib import closing app.config.update( DATABASE = 'my.db', #相 ...

  10. android命令行网络时间同步

    一.简介 Android基于Linux平台的开源手机操作系统. 二.原理 既然是Linux,那就应该支持linux的各种命令行,高度的可配置,但实验发现Android是Google的一个高度阉割版的l ...