WPF实现WORD 2013墨迹批注功能

简介: 原文:WPF实现WORD 2013墨迹批注功能1 前言         WORD 2013可以使用墨迹在文档上面标注,本文讲述通过WPF第三方控件实现类似主要功能如下:          名称 描述 墨迹标注 不论是否触摸屏环境下可以开始墨迹功能,并实现鼠标/触摸在文档任意位置...
原文: 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
                 < Grid  x:Name = "mainGrid" >
                     < dxre:RichEditControl  x:Name = "richEditControl1"  BarManager = "{Binding ElementName=barManager1, Mode=OneTime}"  Ribbon="{Binding 
                     ElementName = ribbonControl1 Mode = OneTime }"   MouseMove = "richEditControl1_MouseMove"   MouseLeave = "RichEditControl1_OnMouseLeave" 
                     MouseUp = "richEditControl1_MouseUp"  />
                     < InkCanvas  x:Name = "mainCanvas"  Visibility = "Hidden" >
                         < InkCanvas.DefaultDrawingAttributes >
                             < DrawingAttributes  Color = "Red"  FitToCurve = "True"  Height = "4"  IgnorePressure = "False"  IsHighlighter = "False" 
                             StylusTip = "Ellipse"  StylusTipTransform = "Identity"  Width = "4" />
                         </ InkCanvas.DefaultDrawingAttributes >
                         < InkCanvas.Background >
                             < SolidColorBrush  Color = "White"  Opacity = "0.01" />
                         </ InkCanvas.Background >
                     </ InkCanvas >
                 </ Grid >

        这一部分除了红框中的,其他的都是直接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  x:Name = "penPage"  Caption = "批注" >
                             < dxr:RibbonPageGroup  x:Name = "penEvent"  Caption = "画笔"  ShowCaptionButton = "False" >
                                 < dxb:BarButtonItem  x:Name = "startPenItem"  LargeGlyph = "pack://application:,,,/Resources/pen.png"   GlyphSize="L
                                 arge"  Content = "开始批注" />
                                 < dxb:BarButtonItem   x:Name = "endPenItem"  LargeGlyph = "pack://application:,,,/Resources/pen_red.png"  GlyphSize="
                                 Large"  Content = "停止批注"  IsEnabled = "False" />
                                 < dxb:BarButtonItem   x:Name = "eraserItem"  LargeGlyph = "pack://application:,,,/Resources/eraser.png"  GlyphSize="
                                 Large"  Content = "擦除"  IsEnabled = "True" />
                             </ dxr:RibbonPageGroup >
                             < dxr:RibbonPageGroup  x:Name = "penSetting"  Caption = "画笔设置"  ShowCaptionButton = "False" >
 
                                 < dxre:BarSplitButtonColorEditItem  x:Name = "penColor"  Content = "画笔颜色"  LargeGlyph="pack://application:,,,
                                 /Resources/pallet.png"  RibbonStyle = "Large"  IsEnabled = "False" >
                                     < dxb:PopupControlContainerInfo >
                                         < dxe:ColorEdit  ChipSize = "Large"  Name = "penColorEdit"  ChipMargin = "5"  ColumnCount = "5"  
                                         ShowMoreColorsButton = "False"  ShowDefaultColorButton = "False"  ShowNoColorButton = "True" 
                                         ShowBorder = "False" >
                                             < dxe:ColorEdit.Palettes >
                                                 < dxre:CharactersBackgroundColorPaletteCollection />
                                             </ dxe:ColorEdit.Palettes >
                                         </ dxe:ColorEdit >
                                     </ dxb:PopupControlContainerInfo >
                                 </ dxre:BarSplitButtonColorEditItem >
 
                                 < dxre:BarSplitButtonEditItem  x:Name = "penLine"  Content = "画笔线宽"  LargeGlyph = "Resources/penline.png"  IsEnab
                                 led = "False" >
                                     < dxb:PopupControlContainerInfo  x:Name = "cccc" >
                                         < dxe:ListBoxEdit  Name = "penLineEdit"  ShowBorder = "False"  ShowCustomItems = "False" >
                                             < dxe:ListBoxEditItem  Content = "1" />
                                             < dxe:ListBoxEditItem  Content = "2" />
                                             < dxe:ListBoxEditItem  Content = "3" />
                                             < dxe:ListBoxEditItem  Content = "4" />
                                             < dxe:ListBoxEditItem  Content = "5" />
                                             < dxe:ListBoxEditItem  Content = "6" />
                                             < dxe:ListBoxEditItem  Content = "7" />
                                             < dxe:ListBoxEditItem  Content = "8" />
                                             < dxe:ListBoxEditItem  Content = "9" />
                                             < dxe:ListBoxEditItem  Content = "10" />
                                             < dxe:ListBoxEditItem  Content = "12" />
                                             < dxe:ListBoxEditItem  Content = "14" />
                                         </ dxe:ListBoxEdit >
                                     </ dxb:PopupControlContainerInfo >
                                 </ dxre:BarSplitButtonEditItem >
                             </ dxr:RibbonPageGroup >
                         </ dxr:RibbonPage >

        这个直接在界面上面增加一个“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
         /// <summary>
         /// 开始批注
         /// </summary>
         /// <param name="start"></param>
         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< float []>()
                 };
 
                 System.Windows.Ink.Stroke stroke = mainCanvas.Strokes[0];
 
                 for  ( int  i = 0; i < stroke.Clone().StylusPoints.Count; i++)
                 {
                     var  pt = stroke.StylusPoints[i];
                     item.Points.Add( new  float [2] { ( float )pt.X, ( float )pt.Y });
                 }
                 mainCanvas.Strokes.Clear();
 
                 DrawStroke(item);
             };
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/// <summary>
         /// 绘制痕迹
         /// </summary>
         /// <param name="stroke"></param>
         private  void  DrawStroke(Stroke stroke)
         {
             if  (stroke.Points.Count < 3)
                 return ;
 
             float  minX =  float .MaxValue;
             float  maxX = 0;
             float  minY =  float .MaxValue;
             float  maxY = 0;
 
             float  width = 0;
             float  height = 0;
 
             for  ( int  i = 0; i < stroke.Points.Count; i++)
             {
                 var  pt = stroke.Points[i];
                 if  (pt[0] < minX)
                     minX = pt[0];
                 if  (pt[0] > maxX)
                     maxX = pt[0];
                 if  (pt[1] < minY)
                     minY = pt[1];
                 if  (pt[1] > maxY)
                     maxY = pt[1];
             }
 
             width = maxX - minX;
             height = maxY - minY;
 
             Bitmap bmp =  new  Bitmap(( int )width + stroke.LineWidth+10, ( int )height + stroke.LineWidth+10);
             Graphics g = Graphics.FromImage(bmp);
             g.SmoothingMode = SmoothingMode.HighQuality;
 
             Pen pen =  new  Pen(System.Drawing.Color.FromArgb(255, stroke.Color.R, stroke.Color.G, stroke.Color.B),
                 stroke.LineWidth);
 
             System.Drawing.PointF[] points =  new  System.Drawing.PointF[stroke.Points.Count];
             for  ( int  i = 0; i < stroke.Points.Count; i++)
             {
                 var  pt = stroke.Points[i];
                 //var pt2 = stroke.Points[i + 1];
 
                 var  x1 = ( float )(pt[0] - minX + stroke.LineWidth);
                 var  y1 = ( float )(pt[1] - minY + stroke.LineWidth);
                 //var x2 = (float)(pt2[0] - minX);
                 //var y2 = (float)(pt2[1] - minY);
 
                 //g.DrawLine(pen, x1, y1, x2, y2);
 
                 points[i] = ( new  PointF(x1, y1));
             }
 
             g.DrawCurve(pen, points);
 
             //标注起点坐标
             var  startPoint =  this .mainCanvas.PointToScreen( new  System.Windows.Point(minX, minY));
             //标注起点坐标相对于文本控件的位置
             var  editPoint =  this .richEditControl1.PointFromScreen(startPoint);
 
             //总页码
             int  pageCount = ((DevExpress.XtraRichEdit.PageBasedRichEditView)richEditControl1.ActiveView).PageCount;
 
             ////是否有分页符
             //bool hasPageBlock = false;
             //for (int i = 0; i < pageCount; i++)
             //{
             //    LayoutPage layoutPage = this.richEditControl1.DocumentLayout.GetPage(i);
             //    if (!hasPageBlock)
             //    {
             //        hasPageBlock = layoutPage.PageAreas.FirstOrDefault().Columns.Any(x => x.Rows.Any(y => y.Boxes.Any(z => z.Type == LayoutType.PageBreakBox)));
             //        break;
             //    }
             //}
 
             //获取当前可见页
             var  pageInfos = richEditControl1.ActiveView.GetVisiblePageLayoutInfos();
             foreach  (PageLayoutInfo pageInfo  in  pageInfos)
             {
                 if  (pageInfo.Bounds.Y > (-1) * pageInfo.Bounds.Height)
                 {
 
                     //画笔起点是否在当前可见页
                     if  (editPoint.X >= pageInfo.Bounds.X && editPoint.X <= pageInfo.Bounds.X + pageInfo.Bounds.Width &&
                         editPoint.Y >= pageInfo.Bounds.Y && editPoint.Y <= pageInfo.Bounds.Y + pageInfo.Bounds.Height)
                     {
 
                         //当前可见页
                         int  pageIndex = pageInfo.PageIndex;
                         LayoutPage layoutPage =  this .richEditControl1.DocumentLayout.GetPage(pageIndex);
 
                         DocumentPosition documentPosition;
                         if  (layoutPage.MainContentRange.Length == 1 && pageIndex == pageCount - 1)
                         {
                             //最后一页,且是分页符空白页
                             documentPosition =
                                   this .richEditControl1.Document.CreatePosition(
                                       layoutPage.MainContentRange.Start + 1);
                             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 +
                                                                               layoutPage.MainContentRange.Length / 2);
                         }
 
                         //if (layoutPage.PageAreas.FirstOrDefault().Columns.Any(x => 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 < canva.ActualHeight)
                                     {
                                         try
                                         {
                                             System.Windows.Point gridPoint = canva.PointFromScreen(startPoint);
 
                                             if  (gridPoint.Y < canva.ActualHeight && gridPoint.Y > 0 &&
                                                 gridPoint.X < canva.ActualWidth && gridPoint.X > 0)
                                             {
                                                 Shape shape =
                                                     this .richEditControl1.Document.InsertPicture(documentPosition, bmp);
                                                 shape.TextWrapping = TextWrappingType.InFrontOfText;
                                                 shape.HorizontalAlignment = ShapeHorizontalAlignment.None;
 
                                                 //shape.RelativeHorizontalPosition = ShapeRelativeHorizontalPosition.Column;
                                                 //shape.RelativeVerticalPosition = ShapeRelativeVerticalPosition.Paragraph;
                                                 shape.ZOrder = zIndex;
                                                 zIndex++;
 
                                                 shape.Name =  "penLink" ;
 
                                                 shape.Offset =  new  PointF(( float )((gridPoint.X - stroke.LineWidth) * 3.12),
                                                     ( float )((gridPoint.Y - stroke.LineWidth) * 3.12));
 
 
 
                                                 break ;
                                             }
                                         }
                                         catch  (Exception ex)
                                         {
 
                                         }
                                     }
 
 
                                 }
                             }
                         }
                         break ;
                     }
                 }
             }
         }

 

 

 

 

5 总结

        最终实现效果如下图。

 

源码和更多资源请访问:http://88gis.cn/web/pages/blog/blogInfo.html?id=95e5139d-5dcc-4600-bcca-355ae6ac8a8f

目录
相关文章
|
C#
WPF 界面实现多语言支持 中英文切换 动态加载资源字典
原文:WPF 界面实现多语言支持 中英文切换 动态加载资源字典 1、使用资源字典,首先新建两个字典文件en-us.xaml、zh-cn.xaml。定义中英文的字符串在这里面【注意:添加xmlns:s="clr-namespace:System;assembly=mscorlib】 zh-cn.
2869 0
|
C# 数据可视化 开发工具
WPF实现选项卡效果(1)——使用AvalonDock
原文:WPF实现选项卡效果(1)——使用AvalonDock 简介   公司最近一个项目,软件采用WPF开发,需要实现类似于VS的选项卡(或者是浏览器的选项卡)效果。
2111 0
|
IDE C# 开发工具
WPF钟表效果实现
中WPF中的RotateTransform实现UI元素的旋转,并模拟钟表的秒针、分针和时针。
1123 0
WPF钟表效果实现
|
IDE 编译器 C#
WPF实现强大的动态公式计算
数据库可以定义表不同列之间的计算公式,进行自动公式计算,但如何实现行上的动态公式计算呢?行由于可以动态扩展,在某些应用场景下将能很好的解决实际问题。本文就探讨一下如何在WPF中实现一种基于行字段的动态公式计算。
990 0
WPF实现强大的动态公式计算
|
网络协议 C# 移动开发
C# WPF上位机实现和下位机TCP通讯
C# WPF上位机实现和下位机TCP通讯下位机使用北京大华程控电源DH1766-1,上位机使用WPF。实现了电压电流实时采集,曲线显示。上午在公司调试成功,手头没有程控电源,使用TCP服务端模拟。昨天写的TCP服务端正好排上用场。
2335 0
|
C#
WPF特效-实现3D足球效果
原文:WPF特效-实现3D足球效果 WPF 实现 3D足球效果,效果图如下:  每个面加载不同贴图。                                                          ...
856 0
|
算法 C# 容器
WPF特效-实现弧形旋转轮播图
原文:WPF特效-实现弧形旋转轮播图        项目遇到,琢磨并实现了循环算法,主要处理循环替换显示问题       (如:12张图组成一个圆弧,但总共有120张图需要呈现,如何在滑动中进行显示块的替换,并毫无卡顿)        处理的自己感觉比较满意,记录一下。
2040 0
|
C#
wpf采用Xps实现文档显示、套打功能
原文:wpf采用Xps实现文档显示、套打功能 近期的一个项目需对数据进行套打,用户要求现场不允许安装office、页面预览显示必须要与文档完全一致,xps文档来对数据进行处理。Wpf的DocumentView 控件可以直接将数据进行显示,xps也是一种开放式的文档,如果我们能够替换里面的标签就最终实现了我们想要的效果。
1730 0
|
C# 开发工具 git
WPF实现选项卡效果(3)——自定义动态添加的AvalonDock选项卡内容
原文:WPF实现选项卡效果(3)——自定义动态添加的AvalonDock选项卡内容 简介   在前面一篇文章里面,我们实现了AvalonDock选项卡的动态添加,但是对于选项卡里面的内容,我们并没有实现任何有用的功能。
1292 0
|
C# 开发工具 git
WPF实现选项卡效果(2)——动态添加AvalonDock选项卡
原文:WPF实现选项卡效果(2)——动态添加AvalonDock选项卡 简介   在前面一篇文章里面,我们使用AvalonDock实现了类似于VS的选项卡(或者浏览器的选项卡)效果。
1692 0