InkPresenter,这个东西再熟悉不过,没错就是手写板,我们可以在它上边想怎么画怎么画,其实他的原理很简单,就是捕捉鼠标的轨迹,然后使用指定的颜色和宽度组成线条,然后不停的记录和显示。

先看个效果

就是一个简单的手写(鼠标).

下面开始详细介绍InkPresenter的使用。

首先看下要使用到的类,以及方法:

1.InkPresenter,InkPresenter成为墨迹控件,继承自Canvas类,它不单单是一个控件,而是一个可以接收SL中输入的接口;

主要属性Strokes,一个集合(StrokeCollection),表示要显示的画笔。

2.Stroke,表示单个墨迹画笔,属性DrawingAttributes表示当前画笔的属性,指定 Stroke 的外观。StylusPoints(StylusPointCollection类型集合),返回Stroke的触笔

接触点。

DrawingAttributes属性如下:

名称 说明
Color                              获取或设置 Stroke 的颜色。
FitToCurve            获取或设置一个值,该值指示是否使用贝塞尔曲线平滑法来呈现 Stroke。
Height            获取或设置用于绘制 Stroke 的触笔的高度。
IgnorePressure            获取或设置一个值,该值指示呈现的 Stroke 的粗细是否会随应用的压力而更改。
IsHighlighter            获取或设置一个值,该值指示 Stroke 看起来是否像一支荧光笔。
StylusTip           获取或设置用于绘制 Stroke 的触笔的形状。
StylusTipTransform                  获取或设置 Matrix,它指定要在触笔笔尖上执行的变换。
Width                            获取或设置用于绘制 Stroke 的触笔的宽度。

有了以上两个类,就可以完成墨迹控件的使用,下面开始看看如何在案例中使用:

  <InkPresenter x:Name="inkTest" Height="400" Width="600"                               Background="AliceBlue"                               MouseMove="inkTest_MouseMove"                               MouseLeftButtonDown="inkTest_MouseLeftButtonDown"                               MouseLeftButtonUp="inkTest_MouseLeftButtonUp">
   </InkPresenter>

可以看到仅仅一个标签就完成了一个InkPresenter的定义,在这里有一点要注意,有些童鞋发现拉过来一个控件之后,包括鼠标的事件代码都写了,可是就是不能画,首先

要确保当前的InkPresenter是否定义了BackGround(或者给InkPresenter添加了其他的元素),其次看看画笔的颜色问题。

下面看下在Inkpresenter中嵌套一个元素:

   <InkPresenter x:Name="inkTest" Height="400" Width="600"                                MouseMove="inkTest_MouseMove"                               MouseLeftButtonDown="inkTest_MouseLeftButtonDown"                               MouseLeftButtonUp="inkTest_MouseLeftButtonUp"><Rectangle RadiusX="15" RadiusY="15" Margin="5" Height="400" Width="600"><Rectangle.Fill><ImageBrush  ImageSource="Chrysanthemum.jpg" Opacity="0.5" ></ImageBrush></Rectangle.Fill></Rectangle></InkPresenter>

可以看到在InkPresenter中嵌套了一个Rectangle,同时指定Rectangle的背景图片,这样就可以在这个图片上进行画东西了,效果也就是本文开头的那副图片。
大家可能注意到了在Ink上定义了三个鼠标事件,没错这个事件也是重点。

MouseMove事件用于记录鼠标在移动的过程中将轨迹写入到Stroke的StylusPoints集合中去;

MouseLeftButtonDown事件,用于捕获鼠标的坐标同时记录一个新的Stroke(新的画笔)开始,标识一个状态,以便在Move事件中进行点的记录;

MouseLeftButtonUp事件用于释放当前的鼠标捕获,同时释放Stroke,标识当前的Stroke已经结束;

UIElement.CaptureMouse()方法用于鼠标捕获当前的元素;

UIElement.ReleaseMouseCapture()方法,如果该元素具有鼠标捕获,则释放鼠标捕获。

从这里开始,编写后台代码:

        Color currentColor = Colors.Black;//定义默认颜色        Stroke newStroke;//定义全局的画笔,用于在MouseDown中实例化,同时在Up中清空该对象        IsolatedStorageSettings setting = IsolatedStorageSettings.ApplicationSettings;//定义独立缓存,用于保存
        //Ink鼠标移动事件        private void inkTest_MouseMove(object sender, MouseEventArgs e)        {//如果不为空则说明已经按下了鼠标            if (newStroke != null)            {//将鼠标移动中的点的轨迹添加到Stroke的StylusPoints                newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkTest));            }        }         
        //Ink鼠标左键按下事件private void inkTest_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)        {//捕获鼠标(必须的)            inkTest.CaptureMouse();//实例化画笔            newStroke = new Stroke();//设置画笔颜色            newStroke.DrawingAttributes.Color = currentColor;//指定轮廓的颜色            newStroke.DrawingAttributes.OutlineColor = Colors.Black;//将鼠标点下的点添加到画笔中区            newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkTest));//将画笔添加到InkPresenter的Strokes(画笔集合)            inkTest.Strokes.Add(newStroke);        }
        //Ink鼠标左键松开事件private void inkTest_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)        {            newStroke = null;
            //释放鼠标捕获            inkTest.ReleaseMouseCapture();        }

以上代码已经完成了,画图的显示,其实整个原理很简单

在鼠标左键按下时候开始进行鼠标的捕获,同时创建Stroke(画笔),并且将点放到Stroke的StylusPoints中,在此还可以设置Stroke的DrawingAttributes,然后将Stroke添加

到Ink的Strokes中去。

在鼠标的移动事件中,记录这些鼠标经过的点,添加到Stroked的StylusPoints中去。

在鼠标左键放开事件中的任务很简单就是将Stroke对象清空,保证Move事件中不会对空对象(未按下左键)进行操作,同时释放鼠标的捕获.

下面开始进行Ink的保存工作,保存Ink的原理也很简单,将Xaml代码通过程序转换成Xml的形式,保存的最终是将xml文件保存到独立存储中

 private void SaveInk()        {            XElement element = ConvertStrokeToString(inkTest.Strokes);using (IsolatedStorageFile stroage = IsolatedStorageFile.GetUserStoreForApplication())            {using (IsolatedStorageFileStream fs = stroage.CreateFile("Ink.xml"))                {using (StreamWriter sw = new StreamWriter(fs))                    {                        sw.WriteLine(element);                    }                }            }            HtmlPage.Window.Alert("保存成功!");        }

该方法传递一个StrokeCollection 类型的参数,也就是Ink的Strokes属性,通过循环处理形成Xml节点

 private XElement ConvertStrokeToString(StrokeCollection originStrokes)        {//添加命名空间            string xmlnsString = "";

            XNamespace xmls = xmlnsString;            XElement XStroke = new XElement(xmls + "StrokeCollection", new XAttribute("xmlns", xmlnsString));//创建笔画            XElement mystroke;//遍历当前Ink上的所有Stroke            foreach (Stroke item in originStrokes)            {//实例化XElement对象,并且把Stroke的属性一一对应放到XElement节点中去                mystroke = new XElement(xmls + "Stroke",new XElement(xmls + "Stroke.DrawingAttributes",new XElement(xmls + "DrawingAttributes",new XAttribute("Color", item.DrawingAttributes.Color),new XAttribute("OutlineColor", item.DrawingAttributes.OutlineColor),new XAttribute("Width", item.DrawingAttributes.Width),new XAttribute("Height", item.DrawingAttributes.Height))));//定义StylusPoint节点                XElement mypoints = new XElement(xmls + "Stroke.StylusPoints");//遍历Stroke的StylusPoints                foreach (StylusPoint sp in item.StylusPoints)                {                    XElement mypoint = new XElement(xmls + "StylusPoint",new XAttribute("X", sp.X),new XAttribute("Y", sp.Y));                    mypoints.Add(mypoint);                }//StylusPoint节点添加到Stroke节点中                mystroke.Add(mypoints);//将Stroke节点添加到根节点中                XStroke.Add(mystroke);            }return XStroke;        }

下面这个方法用于加载Xml(从独立存储中),将Xml转换为Ink所需的对象,返回Ink的Strokes对象所需的StrokeCollection类型

 private StrokeCollection ConvertStringToStroke(string xmlName)        {            StrokeCollection strokeCollection = new StrokeCollection();            XNamespace xmlnsString = "";//使用独立存储来得到保存的Ink文件xml            using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())            {//打开指定的文件                using (IsolatedStorageFileStream fs = storage.OpenFile(xmlName, FileMode.Open, FileAccess.Read))                {//得到读取流                    using (StreamReader sr = new StreamReader(fs))                    {string content = sr.ReadToEnd();//加载xml                        XElement document = XElement.Parse(content);//得到所有的Stroke标签                        var strokes = from stroke in document.Elements(xmlnsString + "Stroke") select stroke;//遍历Stroke节点                        foreach (XElement item in strokes)                        {//得到DrawingAttribute节点                            XElement drawingAttribute = item.Element(xmlnsString + "Stroke.DrawingAttributes").Element(xmlnsString + "DrawingAttributes");//实例化Stroke                            Stroke newStroke = new Stroke();//实例化Stroke的StylusPoint                            StylusPoint point = new StylusPoint();//实例化 StylusPointCollection                            StylusPointCollection pointCollection = new StylusPointCollection();//实例化DrawingAttributes                            DrawingAttributes attribute = new DrawingAttributes();//赋值给DrawingAttributes对象                            attribute.Color = ReturnColorFromString(drawingAttribute.Attributes("Color").First().Value);                            attribute.OutlineColor = ReturnColorFromString(drawingAttribute.Attributes("OutlineColor").First().Value);                            attribute.Width = Convert.ToDouble(drawingAttribute.Attributes("Width").First().Value);                            attribute.Height = Convert.ToDouble(drawingAttribute.Attributes("Height").First().Value);                            newStroke.DrawingAttributes = attribute;

//得到StylusPointCollection集合                            var styluspoints = from p in item.Element(xmlnsString + "Stroke.StylusPoints").Elements(xmlnsString + "StylusPoint") select p;//遍历StylusPointCollection节点                            foreach (XElement pointElement in styluspoints)                            {                                point.X = Convert.ToDouble(pointElement.Attribute("X").Value);                                point.Y = Convert.ToDouble(pointElement.Attribute("Y").Value);                                pointCollection.Add(point);                            }//赋值给Stroke的StylusPoints                            newStroke.StylusPoints = pointCollection;//将Stroke添加到strokeCollection                            strokeCollection.Add(newStroke);                        }                    }                }            }return strokeCollection;        }

由于需要保存颜色则写了自定义方法:

将RGB码转换为Color类型对象

 public Color ReturnColorFromString(string color)        {string alpha = color.Substring(1, 2);string red = color.Substring(3, 2);string green = color.Substring(5, 2);string blue = color.Substring(7, 2);

byte alphaByte = Convert.ToByte(alpha, 16);byte redByte = Convert.ToByte(red, 16);byte greenByte = Convert.ToByte(green, 16);byte blueByte = Convert.ToByte(blue, 16);return Color.FromArgb(alphaByte, redByte, greenByte, blueByte);        }

到这里简单的Ink操作,保存以及加载都已ok,望多多指教,另附上源码下载

[InkDemo]

转载于:https://www.cnblogs.com/ListenFly/archive/2011/10/23/2219672.html

Silverlight中的InkPresenter(可以保存、加载)相关推荐

  1. Matlab停在载入界面,试图在Matlab用户界面中实现保存/加载对象功能时遇到了困难...

    我尝试在Matlab(R2009A)用户界面中实现保存/加载函数.我的对象实现了一个布局函数,它为对象生成一个用户界面.我正在尝试实现保存/加载按钮的回调."保存"按钮起作用,并将 ...

  2. unity保存加载慢_掌握Unity 5中的保存和加载功能

    unity保存加载慢 Thanks to Vincent Quarles for kindly helping to peer review this article. 感谢Vincent Quarl ...

  3. 【GDScript】保存/加载物品装备数据

    > Godot 3.3 rc6 接着上个文章 [Godot]加载文件数据 我们开始给装备栏和物品栏制作保存数据的功能.(文末有文件项目链接) 我们在 FileManager.gd 脚本里添加如下 ...

  4. word2vec模型训练保存加载及简单使用

    目录 word2vec模型训练保存加载及简单使用 一 word2vec简介 二.模型训练和保存及加载 模型训练 模型保存和加载 模型的增量训练 三.模型常用API 四.文本相似度计算--文档级别 wo ...

  5. orb_slam3实现保存/加载地图功能and发布位姿功能

    1.保存/加载地图 先说方法:在加载的相机参数文件.yaml的最前面加上下面两行就行. System.LoadAtlasFromFile: "MH01_to_MH05_stereo_iner ...

  6. Unity中使用代码将预制加载到场景

    Unity中使用代码将预制加载到场景 大家知道, 在日常修改预制的时候很方便, 我们将预制从资源文件夹往场景上"一拖", 然后就可以进行修改, 然后应用保存即可. 但是如果某些需求 ...

  7. android progressdialog 背景色,怎么在android中利用ProgressDialog实现一个加载效果

    怎么在android中利用ProgressDialog实现一个加载效果 发布时间:2020-12-07 17:00:07 来源:亿速云 阅读:77 作者:Leah 怎么在android中利用Progr ...

  8. docker保存linux镜像,docker导入导出容器和保存加载镜像

    系统环境:centos7.4 版本: # docker -v 1.docker容器导入导出 (1)查看:# docker ps -a (2)导出---export # docker export we ...

  9. R语言保存加载工作空间或者工作空间数据对象实战(Save Load RData Workspace)

    R语言保存加载工作空间或者工作空间数据对象实战(Save & Load RData Workspace) 目录 R语言保存加载工作空间或者工作空间数据对象实战(Save & Load ...

最新文章

  1. 使用ROS和TensorFlow进行深度学习
  2. sqlserver ADO.net 查询数据库加锁,事务提交
  3. OpenCASCADE绘制测试线束:数据交换命令之XDE 图层命令
  4. JavaScript通过 new FileReader() 获取图片base64 无组件上传图片
  5. ASP.NET MVC3 系列教程 - 部署你的WEB应用到IIS 6.0
  6. 深入java虚拟机(二) 对象的创建
  7. hash算法_hash一致性算法
  8. SDOI2017 树点涂色
  9. oracle 没有debug权限,开启Oracle的debug级别日志
  10. 计算机桌面图标损坏,win7系统的电脑桌面图标受到损坏要如何修复
  11. Raid5数据恢复算法原理- raid5数据恢复案例
  12. 用数据分析头部微信公众号到底有多牛
  13. Arduino的控制(一):Arduino步进电机六轴机械手(油管搬)
  14. 链接、图像、列表、计数器
  15. 商务英语基础: 口语 | Essential Business English: Speaking
  16. 两台电脑共享鼠标键盘
  17. python字符串常用方法变量名命名规范
  18. python用来初始化对象属性的是_猪行天下之Python基础——8.1 类与对象
  19. 什么是邓宁-克鲁格效应(The Dunning-Kruger Effect)?
  20. 老吕架构-2022~2021年文章索引

热门文章

  1. Java面向对象基础学习笔记(构造、重载、继承、多态、抽象类、接口、模块)
  2. 力扣有没有java_力扣题解
  3. 一键开启微信“开关头像”,快试试!
  4. 翁恺老师C语言学习笔记(十一)字符串
  5. 今日恐慌与贪婪指数为70 贪婪程度有所缓解
  6. 观点:比特币新一轮突破“即将到来”
  7. SAP License:SAP RKE_HZSTMP标准时间转EXCEL日期方法
  8. 那些机器学习中无法衍生的强规则变量有吗?
  9. 风控人最容易被误解的一个风险管理板块
  10. 「BZOJ2190」[SDOI2008] 仪仗队 - 欧拉函数