2010-01-15 28 views
7

In procinto di impazzire con questo problema. Sono sicuro che è così semplice che mi manca, ma non riesco a scoprire come modificare il contenuto di un controllo dei contenuti in Word 2007 con OpenXml SDK v2.0 in C#.Come si modifica il contenuto di un controllo contenuto in Word 2007 con OpenXml SDK 2.0?

Ho creato un documento di Word con un controllo del contenuto di testo normale. Il tag per questo controllo è "FirstName". Nel codice, mi piacerebbe aprire il documento di Word, trovare questo controllo del contenuto e modificare il contenuto senza perdere la formattazione.

La soluzione che ho finalmente avuto modo di lavorare coinvolto trovare il controllo dei contenuti, l'inserimento di una corsa dopo di esso, quindi rimuovendo il controllo dei contenuti in quanto tale:

using (WordprocessingDocument wordProcessingDocument = WordprocessingDocument.Open(filePath, true)) { 
MainDocumentPart mainDocumentPart = wordProcessingDocument.MainDocumentPart; 
SdtRun sdtRun = mainDocumentPart.Document.Descendants<SdtRun>() 
.Where(run => run.SdtProperties.GetFirstChild<Tag>().Val == "FirstName").Single(); 

if (sdtRun != null) { 
sdtRun.Parent.InsertAfter(new Run(new Text("John")), sdtRun); 
sdtRun.Remove(); 
} 

Questo non cambia il testo, ma ho perso tutta la formattazione. Qualcuno sa come posso fare questo?

risposta

6

Ho trovato un modo migliore di fare quanto sopra usando http://wiki.threewill.com/display/enterprise/SharePoint+and+Open+XML#SharePointandOpenXML-UsingWord2007ContentControls come riferimento. I risultati possono variare, ma credo che questo ti porterà fuori ad un buon punto di partenza:

using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filePath, true)) { 
    var sdtRuns = mainDocumentPart.Document.Descendants<SdtRun>() 
     .Where(run => run.SdtProperties.GetFirstChild<Tag>().Val.Value == contentControlTagValue); 

    foreach (SdtRun sdtRun in sdtRuns) { 
     sdtRun.Descendants<Text>().First().Text = replacementText; 
    } 

    wordprocessingDocument.MainDocumentPart.Document.Save(); 
} 

Credo che quanto sopra funziona solo per i controlli Plain contenuto di testo. Sfortunatamente, non si sbarazza del controllo dei contenuti nel documento finale. Se riesco a farlo funzionare, lo posterò.

http://msdn.microsoft.com/en-us/library/cc197932.aspx è anche un buon riferimento se si desidera trovare un controllo di contenuto RTF. Questo parla dell'aggiunta di righe a una tabella che è stata inserita in un controllo di contenuto RTF.

+0

Sembra che questa soluzione non funziona se il controllo dei contenuti è l'unico elemento in un paragrafo (vale a dire non è circondato da altro testo). Come rapido intervento, ho solo messo uno spazio su un lato del controllo dei contenuti. Pubblicherò una soluzione migliore quando ne trovo una. – Jason

3

Il primo approccio per rimuovere lo sdtRun e l'aggiunta di uno nuovo rimuoverà ovviamente la formattazione perché si sta solo aggiungendo un Run ma non il RunStyle. Per conservare la formattazione è necessario creare elementi di correre come

new Run(new RunProperties(new RunStyle(){ Val = "MyStyle" }), 
          new Text("Replacement Text")); 

vostro secondo approccio per sostituire tutti Decendants<Text> lavorerà per Plain Text Content Control solo perché un ricco contenuto di testo di controllo non ha elemento SdtRun. Rich Text Content Control è SdtBlock con elementi SdtContent. Un controllo del contenuto RTF può avere più paragrafi, più esecuzioni e più testi. Quindi il tuo codice, sdtRun.Descendants<Text>().First().Text = replacementText, sarà difettoso per un controllo del contenuto Rich Text. Non esiste un codice di riga per sostituire l'intero testo di un controllo di contenuto avanzato e tuttavia conservare tutta la formattazione.

Non ho capito cosa intendi con "non si sbarazza del controllo dei contenuti nel documento finale"? Ho pensato che il tuo requisito qui è quello di modificare il testo (contenuto) solo mantenendo il controllo dei contenuti e la formattazione.

1

Ho anche dovuto trovare e sostituire il testo nei footer. Si possono trovare utilizzando il seguente codice:

using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(file.PhysicalFile.FullName, true)) { 
    foreach (FooterPart footerPart in wordprocessingDocument.MainDocumentPart.FooterParts) { 
     var footerPartSdtRuns = footerPart.Footer.Descendants<SdtRun>() 
      .Where(run => run.SdtProperties.GetFirstChild<Tag>().Val.Value == contentControlTag); 

     foreach (SdtRun sdtRun in footerPartSdtRuns) { 
      sdtRun.Descendants<Text>().First().Text = replacementTerm; 
     } 
    } 

    wordprocessingDocument.MainDocumentPart.Document.Save(); 
} 
3

Un ottimo modo per capire come ottenere il risultato desiderato è quello di utilizzare lo strumento del documento del riflettore che viene fornito con l'Open XML SDK 2.0 ....

Ad esempio, si potrebbe:

  1. nella finestra di dialogo per ciascuno dei controlli contenuti nel documento Proprietà, selezionare la casella "Elimina controllo di contenuto quando i contenuti sono modificati".
  2. Inseriscili e salvalo come nuovo documento.
  3. Utilizzare il riflettore per confrontare l'originale e la versione salvata.
  4. Premi il pulsante mostra/nascondi codice e ti mostrerà il codice necessario per trasformare l'originale nella versione compilata.

Non è perfetto, ma è incredibilmente utile. Puoi anche guardare direttamente il markup di entrambi i documenti e vedere le modifiche che hanno causato il riempimento dei controlli.

Questo è un modo un po 'fragile per farlo perché Wordprocessing ML può essere complicato; è facile rovinarlo. Per semplici controlli di testo, mi basta usare questo metodo:

private void FillSimpleTextCC(SdtRun simpleTextCC, string replacementText) 
    { 
     // remove the showing place holder element  
     SdtProperties ccProperties = simpleTextCC.SdtProperties; 
     ccProperties.RemoveAllChildren<ShowingPlaceholder>(); 

     // fetch content block Run element    
     SdtContentRun contentRun = simpleTextCC.SdtContentRun; 
     var ccRun = contentRun.GetFirstChild<Run>(); 

     // if there was no placeholder text in the content control, then the SdtContentRun 
     // block will be empty -> ccRun will be null, so create a new instance 
     if (ccRun == null) 
     { 
      ccRun = new Run(
       new RunProperties() { RunStyle = null }, 
       new Text()); 
      contentRun.Append(ccRun); 
     } 

     // remove revision identifier & replace text 
     ccRun.RsidRunProperties = null; 
     ccRun.GetFirstChild<Text>().Text = replacementText; 

     // set the run style to that stored in the SdtProperties block, if there was 
     // one. Otherwise the existing style will be used.    
     var props = ccProperties.GetFirstChild<RunProperties>(); 
     if (props != null) 
     if (props != null) 
     { 
      RunStyle runStyle = props.RunStyle; 
      if (runStyle != null) 
      { 
       // set the run style to the same as content block property style. 
       var runProps = ccRun.RunProperties; 
       runProps.RunStyle = new RunStyle() { Val = runStyle.Val }; 
       runProps.RunFonts = null; 
      } 
     } 
    } 

Speranza che aiuta in qualche modo. : D

+0

È stato rimosso per alcuni giorni, ma lo rivisiterò presto e esaminerò i suggerimenti sopra riportati. Grazie – Jason

1

Un'altra soluzione sarebbe quella

 SdtRun rOld = p.Elements<SdtRun>().First(); 

     string OldNodeXML = rOld.OuterXml; 
     string NewNodeXML = OldNodeXML.Replace("SearchString", "ReplacementString"); 

     SdtRun rNew = new SdtRun(NewNodeXML); 


     p.ReplaceChild<SdtRun>(rNew, rOld); 
Problemi correlati