C# 使用Word.Interop创建嵌套字段

C# 使用Word.Interop创建嵌套字段,c#,ms-word,ms-office,vsto,C#,Ms Word,Ms Office,Vsto,我现在正在玩VSTO,更确切地说是C#和“MicrosoftWord”应用程序外接程序。我确实希望以编程方式创建嵌套字段。我提出了以下源代码(用于测试目的): 尽管提供的代码涵盖了这些要求,但它存在一些主要问题(如您阅读一些代码注释时所见),例如: 它并不健壮,因为它依赖于应用程序的UI状态 这是冗长的。任务并没有那么复杂,依我看 这并不容易理解(重构可能会有所帮助,但通过解决问题1和2,这个缺点应该会消失) 我在WWW上做了一些研究,但还没有找到一个干净的解决方案 所以,我的问题是: 有人能

我现在正在玩VSTO,更确切地说是C#和“MicrosoftWord”应用程序外接程序。我确实希望以编程方式创建嵌套字段。我提出了以下源代码(用于测试目的):

尽管提供的代码涵盖了这些要求,但它存在一些主要问题(如您阅读一些代码注释时所见),例如:

  • 它并不健壮,因为它依赖于应用程序的UI状态
  • 这是冗长的。任务并没有那么复杂,依我看
  • 这并不容易理解(重构可能会有所帮助,但通过解决问题1和2,这个缺点应该会消失)
  • 我在WWW上做了一些研究,但还没有找到一个干净的解决方案

    所以,我的问题是:

    • 有人能提供(替代)C#源代码吗?它比我的源代码更健壮,允许我向“Microsoft Word”文档中添加嵌套字段

    我创建了一个通用实现,用于使用VSTO for Microsoft Word创建非嵌套字段和嵌套字段。您可以在Gist中看到相关的源代码。我已将文章中的VBA源代码移植到C#并应用了一些改进


    仍然不完美(需要一些额外的错误处理),但远比使用
    选择
    对象的解决方案要好,后者取决于用户界面的状态

    我现在无法编写代码,但有一些提示:获取选择的范围并始终使用范围;将范围的TextRetrievalMode.IncludeFieldCodes设置为true可能有助于避免大多数(如果不是所有)UI状态问题(当您尝试将一组字段转换为文本时,它肯定会这样做;始终插入空字段代码,然后添加字段文本(以及其他任何内容,如果必要);从字段的文本表示开始(例如。{如果“{MERGEFIELD myfield}”=“abc”“{REF something}”“{REF other thing}”并按顺序处理,则每次点击“}”时插入一个字段(如果要表示普通的“{”和“}”,还需要一个“转义”字符)字段中的字符。或者,为嵌套字段集生成OpenXML,并使用Range对象的InsertXML方法插入它。我没有这样做,但我可以想象,这可能会产生一些相当优雅的C#代码。在插入字段时,验证字段是否合法可能并不容易,或者此时,它们将在该位置正常工作。
    public partial class ThisAddIn
    {
        private void ThisAddIn_Startup(object sender, EventArgs e)
        {
            // TODO This is just a test.
            this.AddDocPropertyFieldWithinInsertTextField("Author", ".\\\\FileName.docx");
        }
    
        private void AddDocPropertyFieldWithinInsertTextField(string propertyName, string filePath)
        {
            // TODO Horrible, since we rely on the UI state.
            this.Application.ActiveWindow.View.ShowFieldCodes = true;
    
            Word.Selection currentSelection = this.Application.ActiveWindow.Selection;
    
            // Add a new DocProperty field at the current selection.
            currentSelection.Fields.Add(
                Range: currentSelection.Range,
                Type: Word.WdFieldType.wdFieldDocProperty,
                Text: propertyName,
                PreserveFormatting: false
            );
    
            // TODO The following fails if a DocProperty with the specified name does not exist.
    
            // Select the previously inserted field.
            // TODO This is horrible!
            currentSelection.MoveLeft(
                Unit: Word.WdUnits.wdWord,
                Count: 1,
                Extend: Word.WdMovementType.wdExtend
            );
    
            // Create a new (empty) field AROUND the DocProperty field.
            // After that, the DocProperty field is nested INSIDE the empty field.
            // TODO Horrible again!
            currentSelection.Fields.Add(
                currentSelection.Range,
                Word.WdFieldType.wdFieldEmpty,
                PreserveFormatting: false
            );
    
            // Insert text BEFORE the inner field.
            // TODO Horror continues.
            currentSelection.InsertAfter("INCLUDETEXT \"");
    
            // Move the selection AFTER the inner field.
            // TODO See above.
            currentSelection.MoveRight(
                Unit: Word.WdUnits.wdWord,
                Count: 1,
                Extend: Word.WdMovementType.wdExtend
            );
    
            // Insert text AFTER the nested field.
            // TODO See above.
            currentSelection.InsertAfter("\\\\" + filePath + "\"");
    
            // TODO See above.
            this.Application.ActiveWindow.View.ShowFieldCodes = false;
    
            // Update the fields.
            currentSelection.Fields.Update();
        }