Este es el "Problema de Halloween", llamada así porque fue observado por algunos desarrolladores en Halloween, y parecía espeluznante a ellos. Es el problema de usar código declarativo (consultas) con código imperativo (eliminar nodos) al mismo tiempo. Si lo piensas bien, estás iterando a través de una lista vinculada, y si comienzas a eliminar nodos en la lista enlazada, arruinas completamente el iterador. Una manera más simple de evitar este problema es "materializar" los resultados de la consulta en una lista, y luego puede recorrer la lista y eliminar nodos a voluntad. La única diferencia en el siguiente código es que llama a ToList después de llamar al eje Descendientes.
MainDocumentPart mainpart = doc.MainDocumentPart;
IEnumerable<OpenXmlElement> elems = mainPart.Document.Body.Descendants().ToList();
foreach(OpenXmlElement elem in elems){
if(elem is Text && elem.InnerText == "##MY_PLACE_HOLDER##")
{
Run run = (Run)elem.Parent;
Paragraph p = (Paragraph)run.Parent;
p.RemoveAllChildren();
p.Remove();
}
}
Sin embargo, debo tener en cuenta que veo otro error en su código. No hay nada que impida a Word dividir ese nodo de texto en múltiples elementos de texto de múltiples ejecuciones. Aunque en la mayoría de los casos, su código funcionará bien, tarde o temprano usted o un usuario tomarán alguna medida (como seleccionar un personaje y presionar accidentalmente el botón en negrita de la cinta) y luego su código ya no funcionará.
Si realmente quiere trabajar a nivel de texto, a continuación, es necesario utilizar un código como lo que presento en esta pantalla-reparto: http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/08/04/introducing-textreplacer-a-new-class-for-powertools-for-open-xml.aspx
De hecho, probablemente podría utilizar ese código pie de la letra para manejar su caso de uso, creo.
Otro enfoque, más flexible y potente, se detalla en:
http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/06/13/open-xml-presentation-generation-using-a-template-presentation.aspx
Mientras que la pantalla de fundición es de aproximadamente PresentationML, los mismos principios se aplican a WordprocessingML.
Pero aún mejor, dado que está utilizando WordprocessingML, es usar controles de contenido.Por un enfoque de generación de documentos, consulte:
http://ericwhite.com/blog/map/generating-open-xml-wordprocessingml-documents-blog-post-series/
Y para gran cantidad de información acerca del uso de los controles de contenido, en general, ver:
http://www.ericwhite.com/blog/content-controls-expanded
-Eric
En realidad, he hecho .ToList(), porque aparecieron otras complicaciones con anterioridad solución. Además, soy consciente de la división de palabras en varias ejecuciones (esto, aquí, fue un mal ejemplo), por lo que mis marcadores de posición no tienen '_'. Y mis marcadores de posición están codificados, así que, aunque conozco las ventajas del control de contenido, no las utilicé porque no las conozco lo suficiente y tengo un horario corto (mínimo) de proyecto. Gracias por la respuesta, fue muy perspicaz, más completa. –