WPF实现WORD 2013墨迹批注功能 |
您所在的位置:网站首页 › 墨迹功能是什么 › WPF实现WORD 2013墨迹批注功能 |
1 前言
WORD 2013可以使用墨迹在文档上面标注,本文讲述通过WPF第三方控件实现类似主要功能如下: 名称描述墨迹标注不论是否触摸屏环境下可以开始墨迹功能,并实现鼠标/触摸在文档任意位置绘制痕迹墨迹痕迹保存绘制的墨迹能够完整在word中保存墨迹参数设置设置墨迹的颜色和线条粗细墨迹擦除提供擦除工具,可以擦除已经绘制的墨迹 2 环境及三方组件 名称描述DevExpress V16.2使用其RichEditor控件作为word文档查看和编辑控件Aspose.Word在保存word文档时,调整墨迹痕迹的一些属性.NetFrameWork 4.5.net运行库环境 3 实现思路 首先来看一下word中如何开启墨迹。这个就要说微软不地道了,微软规定了只有在触摸屏的windows环境下才会默认显示墨迹按钮,使用鼠标的就默认不显示,当然我们也可以在选项中强制加上,然后没有啥用,因为使用鼠标的用户会发现“开始墨迹书写”按钮是灰色的,而触屏下是可用的,如下图。 我们先摒弃这个梗不说,为什么要自己开发一个墨迹功能呢,可能是因为office太贵了,一般客户买不起或者不想买,于是就要开发一个包含word基本功能的替代品,也有可能是我们开发软性时候需要集成word类似的功能,或者其他种种原因,所以还是决定自己开发(模仿)一个word的墨迹功能。废话少说,下面来一步一步的分析和设计墨迹功能实现思路。 首先,我找到一个在触摸屏上面写好一些文字的文档,在非触摸屏电脑上打开,选中墨迹,这时候工具栏中“图片”选项卡被激活了,可见所谓的“墨迹”实际上只是将手写痕迹保存为类似图片存储起来了,如下图。
总结一下,墨迹保存为图片的主要属性有这样: 1.允许重叠(好像默认插入图片是不允许重叠的) 2.绝对位置(应该是左上角的坐标位置吧) 3.浮于文字上方(这个肯定的,避免扰乱文字布局)
有了这些属性,我大胆设想如果我使用电子手写板插件,将手写痕迹保存下来,然后赋予这些属性,应该也可以达到墨迹的效果。 现在到了框架选型的阶段,首先我需要一个能够打开和编辑word的UI组件,然后我还需要一个电子手写板插件,最后将他们组合起来。这里我选择了DEV V1.6.2 的WPF版本和WPF的InkCanvas组件,这俩我都在实际中用过,比较熟悉。 打开DEV自带的Demo,很容易就看到了word的演示,代码也很简单,如下图。 下一步要做的就是将这个组件和InkCanvas结合起来,通过点击某个按钮触发InkCanvas覆盖到文档上面,然后再使用某个按钮事件触发将InkCanvas关闭或者隐藏掉,同时获取InkCanvas的痕迹保存为图片,再插入到文档指定位置就好了。详细实现代码参考第4部分。 4 主要代码先看看UI部分的布局,将InkCanvas嵌入到Dev的word文档组件中。 1 2 3 4 5 6 7 8 9 10 11 12 13 14这一部分除了红框中的,其他的都是直接copy的DEV官方demo中的,红框的目的也是将手写板控件放置在文档内容页上面,默认是隐藏的,需要的时候再代码控制显示就好。 现在先弄俩按钮,“开始批注”和“停止批注”,来触发和停止墨迹功能。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45这个直接在界面上面增加一个“dxr:RibbonPage ”就可以了,里面增加对应的按钮和一些设置项目。 下面是开始批注代码。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class StartPenCommand : System.Windows.Input.ICommand { public event EventHandler CanExecuteChanged; public bool CanExecute( object parameter) { return true ; } public void Execute( object parameter) { MainWindow window = parameter as MainWindow; window.StartPen( true ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /// /// 开始批注 /// /// public void StartPen( bool start) { this .richEditControl1.ActiveView.ZoomFactor = 1; startPenItem.IsEnabled = !start; endPenItem.IsEnabled = start; eraserItem.IsEnabled = !start; penColor.IsEnabled = start; penLine.IsEnabled = start; var cursor= new Cursor( new MemoryStream(Resource.MetroBusy)); if (!start) this .mainCanvas.Cursor = cursor; this .mainCanvas.Visibility = start ? Visibility.Visible : Visibility.Hidden; }停止批注代码。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class EndPenCommand : System.Windows.Input.ICommand { public event EventHandler CanExecuteChanged; public bool CanExecute( object parameter) { return true ; } public void Execute( object parameter) { MainWindow window = parameter as MainWindow; window.StartPen( false ); } }然后是一个监听,在InkCanvas痕迹绘制就在对应文档增加一笔痕迹。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 //画笔绘制事件 this .mainCanvas.StrokeCollected += (s, o) => { Stroke item = new Stroke() { Color = lineColor, LineWidth = lineWidth, Points = new List() }; System.Windows.Ink.Stroke stroke = mainCanvas.Strokes[0]; for ( int i = 0; i = pageInfo.Bounds.X && editPoint.X = pageInfo.Bounds.Y && editPoint.Y x.Rows.Any(y => y.Boxes.Any(z => z.Type == LayoutType.PageBreakBox)))) //if (this.richEditControl1.Document.HtmlText.Contains("cs1B16EEB5")) /*if (hasPageBlock) { //有分页符 if (pageIndex >0) { LayoutPage preLayoutPage = this.richEditControl1.DocumentLayout.GetPage(pageIndex - 1); if ( !preLayoutPage.PageAreas.FirstOrDefault().Columns.Any(x =>x.Rows.Any(y => y.Boxes.Any(z => z.Type == LayoutType.PageBreakBox)))) { //前一页没有分页符 documentPosition = this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start); } else { //前一页有分页符 documentPosition = this.richEditControl1.Document.CreatePosition( layoutPage.MainContentRange.Start); DocumentRange documentRange = this.richEditControl1.Document.CreateRange(documentPosition, 1); this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange); documentPosition = documentRange.End; this.richEditControl1.Document.Delete(documentRange); } } else { documentPosition = this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start); } //if (pageIndex == pageCount - 1) //{ // //if (!layoutPage.PageAreas.FirstOrDefault().Columns.Any(x => x.Rows.Any(y => y.Boxes.Any(z=>z.Type == LayoutType.ParagraphMarkBox)))) // //{ // // DocumentRange documentRange = this.richEditControl1.Document.CreateRange(documentPosition, 1); // // this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange); // // documentPosition = documentRange.End; // // this.richEditControl1.Document.Delete(documentRange); // //} // documentPosition = // this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start + // layoutPage.MainContentRange.Length); // DocumentRange documentRange = // this.richEditControl1.Document.CreateRange(documentPosition, 1); // this.richEditControl1.Document.InsertDocumentContent(documentPosition, documentRange); // documentPosition = documentRange.End; // this.richEditControl1.Document.Delete(documentRange); //} //else //{ // documentPosition = this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start); //} } else { //无分页符 documentPosition = this.richEditControl1.Document.CreatePosition(layoutPage.MainContentRange.Start); }*/ var focusControl = richEditControl1.FocusElement; var controls = GetCanvasControls(focusControl); //根据相对位置坐标绘制图片 foreach (FrameworkElement box in controls) { Console.WriteLine(box.Name); if (box.Name == "SuperRoot" ) { if (box.ActualHeight == 0) { } else { Canvas canva = box as Canvas; var point = box.GetPosition( this .richEditControl1); if (point.Y > (-1) * canva.ActualHeight && point.Y |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |