2013-05-27 44 views
1

我正在玩VSTO,更精確地說是用C#和一個「Microsoft Word」應用程序加載項。我希望以編程方式創建嵌套字段。我想出了下面的源代碼(用於測試目的):用Word.Interop創建一個嵌套字段

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(); 
    } 

雖然提供的代碼覆蓋的要求,它有一些主要問題(如你可以看到,如果讀了一些代碼註釋),例如:

  1. 它不健壯,因爲它依賴於應用程序的UI狀態。
  2. 是冗長的。這個任務並不複雜,imo。
  3. 這並不容易理解(重構可以幫助,但通過解決問題1和2,這個缺點應該會消失)。

我在WWW上做了一些研究,但還沒有找到一個乾淨的解決方案。

所以,我的問題是:

  • 有人可以提供(可選的)C#源代碼,這是更穩健比我那讓我嵌套字段添加到「Microsoft Word中」的文件?
+1

我現在不能做代碼,但有一些提示:獲取選擇範圍並始終使用範圍;將範圍的TextRetrievalMode.IncludeFieldCodes設置爲true可能有助於避免大部分UI狀態問題(當您試圖將一組字段轉換爲文本時,肯定會這樣做;始終插入空字段代碼,然後添加字段文本(以及任何內容(如果需要的話);從字段的文本表示開始(例如{IF「{MERGEFIELD myfield}」=「abc」「{REF something}」「{REF other thing}」並按順序處理,每個字段分別插入一個字段當你點擊一個「}」 – 2013-05-28 11:56:11

+1

(如果你想在這個字段中代表普通的「{」和「}」字符,你還需要一個「轉義」字符 或者,爲這組嵌套字段生成OpenXML並使用Range對象的InsertXML方法來插入它,我沒有這樣做,但我可以想象它可能會導致一些相當優雅的C#代碼。OTOH可能不容易驗證這些字段在指向你插入它們,或者它們將在該位置正確運行。 – 2013-05-28 11:59:40

回答

0

我創建了一個通用的實現,用VSTO爲Microsoft Word創建非嵌套和嵌套字段。你可以在this Gist中看到相關的源代碼。我已將文章Nested Fields in VBA中的VBA源代碼移植到C#並應用了一些改進。

仍然不完美(需要一些額外的錯誤處理),但遠遠優於具有Selection對象的解決方案,該對象依賴於用戶界面的狀態!