C# VSTO Word、PPT踩坑
参考我的VSTO之路(四):深入介绍Word开发 - Justin Zhang - 博客园 (cnblogs.com)
1、Slides (unknown member): Invalid request. Clipboard is empty or contains data which may not be pasted here.
场景:接到一个需求,需要将一个本地PPT的所有页复制粘贴到当前PPT
使用代码
Microsoft.Office.Interop.PowerPoint.Presentation source = PPTapp.Presentations.Open(sourcePptFile, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse); int sourceSlideRange = source.Slides.Count; int forStart = 1 ; int forEnd = sourceSlideRange ; for (int i = forStart; i <= forEnd; ++i) { Microsoft.Office.Interop.PowerPoint.Slide srcSlide = source.Slides[i]; source.Slides[i].Copy(); target.Slides.Paste(target.Slides.Count + 1); target.Slides[target.Slides.Count].FollowMasterBackground = MsoTriState.msoFalse; }
但是会报错Slides (unknown member): Invalid request. Clipboard is empty or contains data which may not be pasted here.,可能原因是是因为复制粘贴太快,剪切板异常导致的。(网上搜了很多资料,找不到具体原因)
开发中发现每次复制粘贴代码执行后界面不会立即刷新,会等待一段时间。特别是当前页面有弹窗时,复制粘贴只有当弹窗关闭后激活ppt才会生效。
因此尝试在每次复制粘贴后弹出一个弹窗,300毫秒(多次测试300比较合适,再短会有异常)后自动关闭,保证每次复制粘贴都会激活ppt窗体。
附上代码:
AtuoCloseWindow
<Window x:Class="AtuoCloseWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:PowerPointAIAddIn.Controls" mc:Ignorable="d" Height="0" Width="0" WindowStyle="None" BorderThickness="0"> <Grid> </Grid> </Window>
using System; using System.Windows; using System.Windows.Threading; namespace Controls { /// <summary> /// AtuoCloseWindow.xaml 的交互逻辑 /// </summary> public partial class AtuoCloseWindow : Window { DispatcherTimer dt { get; set; } public AtuoCloseWindow() { InitializeComponent(); this.Loaded += AtuoCloseWindow_Loaded; } private void AtuoCloseWindow_Loaded(object sender, RoutedEventArgs e) { dt = new DispatcherTimer(); dt.Interval = new TimeSpan(0, 0, 0, 0, 300); dt.Tick += Dt_Tick; dt.Start(); } private void Dt_Tick(object sender, EventArgs e) { dt.Stop(); this.Close(); } } }
复制代码
Microsoft.Office.Interop.PowerPoint.Presentation source = PPTapp.Presentations.Open(sourcePptFile, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse); int sourceSlideRange = source.Slides.Count; int forStart = 1 ; int forEnd = sourceSlideRange ; for (int i = forStart; i <= forEnd; ++i) { Microsoft.Office.Interop.PowerPoint.Slide srcSlide = source.Slides[i]; source.Slides[i].Copy(); target.Slides.Paste(target.Slides.Count + 1); target.Slides[target.Slides.Count].FollowMasterBackground = MsoTriState.msoFalse; var win = new AtuoCloseWindow(); win.Left = 0; win.Top = 0; win.ShowDialog(); }
2、添加右键菜单
参考VSTO 为Office已有右键菜单添加自己的菜单项(word,Excel) (shuzhiduo.com)
CommandBarButton GKJDButton; CommandBarButton RSJCButton; CommandBarButton FXYJButton; CommandBarButton RSJCButton1; CommandBarButton ZXSCButton; CommandBarButton NRJYButton; private void AddRightMenu() { CommandBar mzBar = Globals.ThisAddIn.Application.CommandBars["Text"]; //word文档已有的右键菜单Text CommandBarControls bars = mzBar.Controls; foreach (CommandBarControl temp_contrl in bars) { //如果已经存在就删除 if (temp_contrl.Tag == contractFXYJ || temp_contrl.Tag == contractGKJD || temp_contrl.Tag == contractRSJC + "1") { temp_contrl.Delete(); } } GKJDButton = bars.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, Missing.Value, true) as CommandBarButton; if (GKJDButton != null) { //概括解读 GKJDButton.Tag = contractGKJD; GKJDButton.BeginGroup = true; GKJDButton.Enabled = false; GKJDButton.Caption = contractGKJD; GKJDButton.Style = MsoButtonStyle.msoButtonIconAndCaption; GKJDButton.Click -= new _CommandBarButtonEvents_ClickEventHandler(ContractRightBtnCommand_Click); GKJDButton.Click += new _CommandBarButtonEvents_ClickEventHandler(ContractRightBtnCommand_Click); } RSJCButton = bars.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, Missing.Value, true) as CommandBarButton; if (RSJCButton != null) { //润色纠错 RSJCButton.Tag = contractRSJC + "1"; RSJCButton.Caption = contractRSJC; RSJCButton.Enabled = false; RSJCButton.Style = MsoButtonStyle.msoButtonIconAndCaption; RSJCButton.Click -= new _CommandBarButtonEvents_ClickEventHandler(ContractRightBtnCommand_Click); RSJCButton.Click += new _CommandBarButtonEvents_ClickEventHandler(ContractRightBtnCommand_Click); } FXYJButton = bars.Add(MsoControlType.msoControlButton, Missing.Value, Missing.Value, Missing.Value, true) as CommandBarButton; if (FXYJButton != null) { //风险预警 FXYJButton.Tag = contractFXYJ; FXYJButton.Caption = contractFXYJ; FXYJButton.Enabled = false; FXYJButton.Style = MsoButtonStyle.msoButtonIconAndCaption; FXYJButton.Click -= new _CommandBarButtonEvents_ClickEventHandler(ContractRightBtnCommand_Click); FXYJButton.Click += new _CommandBarButtonEvents_ClickEventHandler(ContractRightBtnCommand_Click); } }
- 需要添加的CommandBarButton一定要设置为公有变量,不然会有灵异的bug 切记!切记!切记!
- Office2016右键预点击事件WindowBeforeRightClick有bug,需要打补丁,不然触发不了(c# - WindowBeforeRightClick doesn't work - Stack Overflow https://support.microsoft.com/en-us/kb/3114855)
3、TextBox无法粘贴回车
WPF编程,TextBox回车换行的一种方法 (xjx100.cn)
往TextBox复制文本时,若文本有回车,回车后面的文本会无法复制。
解决办法:将TextBox的AcceptsReturn属性设置设为True,
将 TextWrapping 属性设置为 Wrap 会导致输入的文本在到达 TextBox 控件的边缘时换至新行,必要时会自动扩展 TextBox 控件以便为新行留出空间。 将 AcceptsReturn 属性设置为 true 会导致在按 Return 键时插入新行,必要时会再次自动扩展 TextBox 以便为新行留出空间。