我的C# VSTO外接程序帮助生成邮件合并的专用标签.邮件标签是在文档中创建的,标签“表”中的第一个标签是以编程方式填充的:
Word.Field myField = myCell.Range.Fields.Add(range, missing, missing, missing);
myField.Code.Text = " MERGEFIELD MyField ";现在,当Word为邮件合并创建邮件标签时,它会将字段代码放在下一个记录所在的位置:它们在Word中看起来像{ NEXT }或«Next Record»。
在Word的"Mailings“选项卡中,有一个名为更新标签的内置按钮。其Office为MailMergeUpdateLabels。如果打开了邮件标签表,它将将第一个标签中的所有内容复制到每个有效的标签空间中。它还确保«Next Record»字段在第一个标签之后开始每个标签,以便邮件合并可以插入下一个记录。
我需要通过C#以编程方式触发此操作。如果我告诉用户“请转到mailings选项卡并按”更新标签“按钮”,那将是非常厚颜无耻的。我可以想出三种方法来解决这个问题:
- I've done a deep dive through the MSDN reference for Word Interop in C#. I have found no such method (and no, `myObject.Range.Fields.Update()` does not accomplish this.).
- Something like `updateButton.PerformClick();`, but I have no idea how to expose the built-in button through Interop so that I could reference it in my code.
- I already wrote one. Unfortunately, it's very slow (~7 seconds for a page of 30 labels). The most time-consuming operation seems to be adding the fields to the ranges. The "Update Labels" button's effect is very flexible and near-instantaneous.
作为参考,下面是我用来填充单个标签单元格的方法:
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();
}再说一遍,这条路很慢。我可以使用选择和编程复制粘贴(是的,使用用户的剪贴板),但这似乎很脏。即使如此,更新标签仍然优越,因为如果«Next Record»被用户删除,它“知道”放在哪里。
我对选项2的实现方式很好奇。如果向我展示了如何将“更新标签”按钮公开给单击,我可以学习向模拟单击公开任何按钮。
发布于 2018-08-26 06:23:55
是的,可以同时使用选项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:所有应用程序都可以访问共享对象模型的CommandBars部分。最初,这是负责菜单和工具栏的用户界面(预Office 2007).在Office 2007中,该对象被Ribbon取代,该对象被保留为向后兼容性,并扩展为与Ribbon的有限交互。
这些“新”方法之一是ExecuteMso,它执行按钮命令,就像单击了按钮一样:
wdApp.CommandBars.ExecuteMso("MailMergeUpdateLabels");https://stackoverflow.com/questions/52022278
复制相似问题