C# C“Word互操作:使用内置”;“更新标签”;邮件功能

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 C#VSTO插件有助于为邮件合并生成专用标签。邮件标签在文档中创建,标签“表”中的第一个标签以编程方式填充:

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#以编程方式触发此操作。如果我告诉用户“请转到邮件标签并按下更新标签按钮”,那将是非常无礼的。我可以想出三种方法来解决这个问题:

  • 触发“更新标签”按钮通过Word Interop使用的相同方法。

    • 我已经深入研究了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,它也可以工作。(如今,它们是默认安装的,但情况并非总是如此。)