2010-01-15 30 views
7

A punto de volverse loco con este problema. Estoy seguro de que es tan simple que me lo estoy perdiendo, pero no puedo saber cómo cambiar el contenido de un control de contenido en Word 2007 con OpenXml SDK v2.0 en C#.¿Cómo se cambia el contenido de un control de contenido en Word 2007 con OpenXML SDK 2.0?

He creado un documento de Word con un control de contenido de texto sin formato. La etiqueta para este control es "Nombre". En el código, me gustaría abrir el documento de Word, encontrar este control de contenido y cambiar el contenido sin perder el formato.

La solución finalmente llegué al trabajo consistía en encontrar el control de los contenidos, la inserción de una carrera después de que, después de retirar el control de contenido como tal:

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

Esto hace cambiar el texto, pero pierde todo el formato. ¿Alguien sabe cómo puedo hacer esto?

Respuesta

6

He encontrado una mejor manera de hacer lo anterior utilizando http://wiki.threewill.com/display/enterprise/SharePoint+and+Open+XML#SharePointandOpenXML-UsingWord2007ContentControls como referencia. Sus resultados pueden variar, pero creo que esto le baje a un buen comienzo:

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

Creo que lo anterior sólo funcionará para los controles de contenido de texto sin formato. Desafortunadamente, no elimina el control de contenido en el documento final. Si lo hago, lo publicaré.

http://msdn.microsoft.com/en-us/library/cc197932.aspx es también una buena referencia si desea encontrar un control de contenido de texto enriquecido. Éste se refiere a agregar filas a una tabla que se colocó en un control de contenido de texto enriquecido.

+0

Parece que esta solución no funcionará si el control de contenido es el único elemento en un párrafo (es decir, no está rodeado por otro texto). Como trabajo rápido, coloqué un espacio en un lado del control de contenido. Publicaré una mejor solución cuando encuentre una. – Jason

3

Su primer enfoque para eliminar el sdtRun y ​​agregar uno nuevo obviamente eliminará el formato porque solo está agregando un Run pero no el RunStyle. Para conservar el formato debe crear elementos de correr como

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

Su segundo enfoque para reemplazar todo Decendants<Text> trabajará para el Control de contenido de texto sin formato sólo por un contenido de texto enriquecido de control no tiene elemento SdtRun. Rich Text Content Control es SdtBlock con elementos SdtContent. Un control de contenido de texto enriquecido puede tener múltiples párrafos, múltiples ejecuciones y múltiples textos. Por lo tanto, su código, sdtRun.Descendants<Text>().First().Text = replacementText, tendrá defectos para un control de contenido de texto enriquecido. No hay un código de línea para reemplazar todo el texto de un control de contenido enriquecido y conservar todo el formato.

No entendí lo que quiere decir con "no se deshace del control de contenido en el documento final"? Pensé que su requisito aquí es cambiar el texto (contenido) solo conservando el control de contenido y el formato.

1

También tuve que buscar y reemplazar texto en los pies de página. Los puede encontrar utilizando el siguiente código:

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

Una excelente manera de encontrar la manera de lograr el resultado deseado es utilizar la herramienta de reflector documento que viene con el Open XML SDK 2.0 ....

por ejemplo, usted podría:

  1. en el diálogo Propiedades para cada uno de los controles de contenido en el documento, marque la casilla "Eliminar el control de contenido cuando los contenidos son editados".
  2. Completar y guardar como un nuevo documento.
  3. Utilice el reflector para comparar la versión original y la versión guardada.
  4. Pulse el botón mostrar/ocultar código y le mostrará el código requerido para convertir el original en la versión completa.

No es perfecto, pero es increíblemente útil. También puede simplemente mirar directamente el marcado de cualquiera de los documentos y ver los cambios que causaron el relleno de los controles.

Esta es una forma algo frágil de hacerlo porque Wordprocessing ML puede ser complicado; es fácil arruinarlo. Para los controles de texto simples, simplemente uso este método:

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

Espero que ayude de alguna manera. : D

+0

Me salí de esto por unos días, pero volveré a revisarlo pronto y veré las sugerencias anteriores. Gracias – Jason

1

Otra solución sería

 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); 
Cuestiones relacionadas