C# C“Word互操作:使用内置”;“更新标签”;邮件功能
我的Word C#VSTO插件有助于为邮件合并生成专用标签。邮件标签在文档中创建,标签“表”中的第一个标签以编程方式填充:C# C“Word互操作:使用内置”;“更新标签”;邮件功能,c#,ms-word,office-interop,mailmerge,C#,Ms Word,Office Interop,Mailmerge,我的Word C#VSTO插件有助于为邮件合并生成专用标签。邮件标签在文档中创建,标签“表”中的第一个标签以编程方式填充: Word.Field myField = myCell.Range.Fields.Add(range, missing, missing, missing); myField.Code.Text = " MERGEFIELD MyField "; 现在,当Word为邮件合并创建邮件标签时,它会将字段代码放在下一条记录的位置:它们看起来像Word中的{next}或«next
Word.Field myField = myCell.Range.Fields.Add(range, missing, missing, missing);
myField.Code.Text = " MERGEFIELD MyField ";
现在,当Word为邮件合并创建邮件标签时,它会将字段代码放在下一条记录的位置:它们看起来像Word中的{next}
或«next record»
在Word的“邮件”选项卡中,有一个名为的内置按钮。其Office控件ID为MailMergeUpdateLabels
。如果您打开了邮件标签表,它将将第一个标签中的所有内容复制到每个有效标签空间中。它还确保«Next Record»
字段在第一个标签之后开始,以便邮件合并可以插入下一条记录
/
我需要通过C#以编程方式触发此操作。如果我告诉用户“请转到邮件标签并按下更新标签按钮”,那将是非常无礼的。我可以想出三种方法来解决这个问题:
- 我已经深入研究了C#中单词互操作的MSDN参考。我没有找到这样的方法(而且,
无法完成此任务)myObject.Range.Fields.Update()
- 类似于
updateButton.PerformClick()的内容代码>,但我不知道如何通过互操作公开内置按钮,以便在代码中引用它
- 我已经写了一篇。不幸的是,它非常慢(对于一个包含30个标签的页面,大约7秒)。最耗时的操作似乎是将字段添加到范围中。“更新标签”按钮的效果非常灵活,几乎是即时的
private void InsertIntoCell(Word.Cell cell, bool insertNextField)
{
string[] fieldCodes = { @" NEXT ",
@" MERGEFIELD Name ",
@" MERGEFIELD SerialNumber \b "": "" ",
"\v",
@" MERGEBARCODE Barcode CODE128 " };
cell.Range.Delete();
Word.Range range = cell.Range;
range.Collapse(WdCollapseDirection.wdCollapseStart);
foreach(string fieldCode in fieldCodes)
{
//the NEXT field is the first one in the fieldcodes array
//skip it if the program asks not to insert it
if (!insertNextField)
{
insertNextField = true;
continue;
}
//if the field codes demand a Vertical Tab character
//write it, because word reads it as a newline character
if(fieldCode.Equals("\v"))
{
range.Text = fieldCode;
range.Move(WdUnits.wdCharacter, 1);
continue;
}
Word.Field field = cell.Range.Fields.Add(range, missing, missing, missing);
field.Code.Text = fieldCode;
//move the range to the end of the most recent field
range = field.Result;
range.Collapse(WdCollapseDirection.wdCollapseEnd);
}
//set font, update the fields to make them visible
cell.Range.Font.Size = FIELD_FONT_SIZE;
cell.Range.Fields.Update();
}
同样,这条路很慢。我可以使用选择并以编程方式复制粘贴(是的,使用用户的剪贴板),但这看起来很脏。即使如此,更新标签仍具有优越性,因为如果用户删除了它,它“知道”在哪里放置«下一条记录»
我最好奇的是选项2将如何实现。如果向我展示了如何将“更新标签”按钮暴露给点击,我可以学习将任何按钮暴露给模拟点击。是的,选项1和选项2都可以。这两种方法都有点晦涩难懂,所以您没有遇到它们也就不足为奇了 选项1:由于某些奇怪的原因,该命令未包含在标准对象模型中。但是它可以通过后期绑定的
WordBasic
对象模型访问。(实际上,Word中的所有命令都有一个相应的WordBasic
实现,因为在幕后仍然运行所有命令。但它们没有文档记录…)
VB语言可以直接使用它。但是,C#无法直接处理后期绑定对象,因此需要PInvoke:
object wordBasic = wdApp.GetType().InvokeMember("WordBasic", BindingFlags.GetProperty, null, wdApp, null);
wordBasic.GetType().InvokeMember("MailMergePropagateLabel", BindingFlags.InvokeMethod, null, wordBasic, null);
选项2:所有Office应用程序都可以访问共享对象模型的命令栏。最初,它负责菜单和工具栏用户界面(pre Office 2007)。在Office2007中,功能区UI取代了该功能区,保留该对象是为了向后兼容,扩展对象是为了与功能区UI进行有限的交互
这些“新”方法之一是ExecuteMso
,它执行一个按钮命令,就像它被点击一样:
wdApp.CommandBars.ExecuteMso("MailMergeUpdateLabels");
考虑到我必须交叉引用VB文档才能找到C#Interop等价物,PInvoke似乎是一个超级大国。关于ExecuteMso,我应该相信MSOID在不同版本的Word中保持(相对)不变,还是应该只相信WordBasic对象模型的连续性?@Phil我认为两者都同样可靠。虽然我从未测试过,但在执行速度上可能会有极小的差异。PInvoke的缺点是没有智能感知。好处是不依赖于PIA,这使得它非常独立于版本,即使没有安装PIA,它也可以工作。(如今,它们是默认安装的,但情况并非总是如此。)