WPF实现WORD 2013墨迹批注功能

简介: 1 前言         WORD 2013可以使用墨迹在文档上面标注,本文讲述通过WPF第三方控件实现类似主要功能如下:          名称 描述 墨迹标注 不论是否触摸屏环境下可以开始墨迹功能,并实现鼠标/触摸在文档任意位置绘制痕迹 墨迹痕迹保存 绘制的墨迹能够完...

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

相关文章
|
20天前
|
C# 机器学习/深度学习 搜索推荐
WPF与机器学习的完美邂逅:手把手教你打造一个具有智能推荐功能的现代桌面应用——从理论到实践的全方位指南,让你的应用瞬间变得高大上且智能无比
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)应用中集成机器学习功能,以开发具备智能化特性的桌面应用。通过使用Microsoft的ML.NET框架,本文演示了从安装NuGet包、准备数据集、训练推荐系统模型到最终将模型集成到WPF应用中的全过程。具体示例代码展示了如何基于用户行为数据训练模型,并实现实时推荐功能。这为WPF开发者提供了宝贵的实践指导。
26 0
|
20天前
|
开发者 C# UED
WPF与多媒体:解锁音频视频播放新姿势——从界面设计到代码实践,全方位教你如何在WPF应用中集成流畅的多媒体功能
【8月更文挑战第31天】本文以随笔形式介绍了如何在WPF应用中集成音频和视频播放功能。通过使用MediaElement控件,开发者能轻松创建多媒体应用程序。文章详细展示了从创建WPF项目到设计UI及实现媒体控制逻辑的过程,并提供了完整的示例代码。此外,还介绍了如何添加进度条等额外功能以增强用户体验。希望本文能为WPF开发者提供实用的技术指导与灵感。
40 0
|
20天前
|
存储 开发者 C#
WPF与邮件发送:教你如何在Windows Presentation Foundation应用中无缝集成电子邮件功能——从界面设计到代码实现,全面解析邮件发送的每一个细节密武器!
【8月更文挑战第31天】本文探讨了如何在Windows Presentation Foundation(WPF)应用中集成电子邮件发送功能,详细介绍了从创建WPF项目到设计用户界面的全过程,并通过具体示例代码展示了如何使用`System.Net.Mail`命名空间中的`SmtpClient`和`MailMessage`类来实现邮件发送逻辑。文章还强调了安全性和错误处理的重要性,提供了实用的异常捕获代码片段,旨在帮助WPF开发者更好地掌握邮件发送技术,提升应用程序的功能性与用户体验。
23 0
|
20天前
|
C# 开发者 Windows
WPF遇上Office:一场关于Word与Excel自动化操作的技术盛宴,从环境搭建到代码实战,看WPF如何玩转文档处理的那些事儿
【8月更文挑战第31天】Windows Presentation Foundation (WPF) 是 .NET Framework 的重要组件,以其强大的图形界面和灵活的数据绑定功能著称。本文通过具体示例代码,介绍如何在 WPF 应用中实现 Word 和 Excel 文档的自动化操作,包括文档的读取、编辑和保存等。首先创建 WPF 项目并设计用户界面,然后在 `MainWindow.xaml.cs` 中编写逻辑代码,利用 `Microsoft.Office.Interop` 命名空间实现 Office 文档的自动化处理。文章还提供了注意事项,帮助开发者避免常见问题。
65 0
|
20天前
|
API C# Shell
WPF与Windows Shell完美融合:深入解析文件系统操作技巧——从基本文件管理到高级Shell功能调用,全面掌握WPF中的文件处理艺术
【8月更文挑战第31天】Windows Presentation Foundation (WPF) 是 .NET Framework 的关键组件,用于构建 Windows 桌面应用程序。WPF 提供了丰富的功能来创建美观且功能强大的用户界面。本文通过问题解答的形式,探讨了如何在 WPF 应用中集成 Windows Shell 功能,并通过具体示例代码展示了文件系统的操作方法,包括列出目录下的所有文件、创建和删除文件、移动和复制文件以及打开文件夹或文件等。
36 0
|
20天前
|
C# Windows 监控
WPF应用跨界成长秘籍:深度揭秘如何与Windows服务完美交互,扩展功能无界限!
【8月更文挑战第31天】WPF(Windows Presentation Foundation)是 .NET 框架下的图形界面技术,具有丰富的界面设计和灵活的客户端功能。在某些场景下,WPF 应用需与 Windows 服务交互以实现后台任务处理、系统监控等功能。本文探讨了两者交互的方法,并通过示例代码展示了如何扩展 WPF 应用的功能。首先介绍了 Windows 服务的基础知识,然后阐述了创建 Windows 服务、设计通信接口及 WPF 客户端调用服务的具体步骤。通过合理的交互设计,WPF 应用可获得更强的后台处理能力和系统级操作权限,提升应用的整体性能。
42 0
|
1月前
|
前端开发 C# 容器
WPF/C#:实现导航功能
WPF/C#:实现导航功能
38 0
|
开发框架 前端开发 JavaScript
WPF+ASP.NET SignalR实现简易在线聊天功能
WPF+ASP.NET SignalR实现简易在线聊天功能
187 0
|
自然语言处理 编译器 C#
【WPF】实现动态切换语言(国际化)以及动态换肤功能
以下内容,手把手从搭建到最终实现,完成多语言切换以及换装功能。
414 0
【WPF】实现动态切换语言(国际化)以及动态换肤功能
|
前端开发 C# 图形学
【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示
Wpf开发过程中,最经常使用的功能之一,就是用户控件(UserControl)了。用户控件可以用于开发用户自己的控件进行使用,甚至可以用于打造一套属于自己的UI框架。依赖属性(DependencyProperty)是为用户控件提供可支持双向绑定的必备技巧之一,同样用处也非常广泛。
886 0
【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示