Im ersten Teil ersten Teil habe ich gezeigt, wie man mittels OpenXML und Inhaltssteuerlementen (Content Controls) Word-Templates direkt befüllen kann. In diesem Teil geht es darum, wie man optionale Teile löschen kann und mit (nicht vorhandenen) Bildern umgehen löschen.

Textbereiche löschen

In meinem Template gibt es Bereiche, die nur manchmal befüllt werden müssen und oft ganz gelöscht werden müssen. Das kann man eigentlich mittels Rich-Text-Controls gut umsetzen, in die man weitere Nur-Text-Controls einfügen kann und verbindenden Text. Das sieht dann so aus im Entwicklungsmodus: Ein Richtext-Control mit zwei Nur-Text-Controls

Will man dann den Entwicklungsmodus verlassen, wird man aber mit folgender Warnung beglückt: Warnhinweis Warnhinweis, wenn man ein Richtext-Control mit enthaltenen Steuerelementen speichern will

Die kann man aber insofern ignorieren, dass man im Entwicklungsmodus speichern und das Dokument schließen kann. Danach kann man das Dokument wie gewohnt weiterbearbeiten. Sobald man wieder in den Entwicklungsmodus kommt, kommt die Fehlermeldung wieder, aber jetzt kennen wir ja den Workaround.

Ich habe mehrere Bereiche, die ich, abhängig von einer Variable, löschen möchte. Um diese Bereiche im Dokument zu markieren, nutze ich den Tag der ContenControls (über die Eigenschaften editierbar):

Eigenschaften-Fenster zum setzen des Tag-Namens Eigenschaften-Fenster zum setzen des Tag-Namens

Das mache ich durch folgenden Code:

Public Sub TagAusWordDokumentLoeschen(suchTag As String, fileFolder As String)
    Using wordDoc As WordprocessingDocument = WordprocessingDocument.Open(fileFolder, True)
        For Each contentcontrol In wordDoc.MainDocumentPart.Document.
                Descendants(Of Tag).
                Where(Function(t) Not IsNothing(t) AndAlso t.Val.Value.Contains(suchTag)).
                Reverse()
            contentcontrol.Parent.Parent.Remove()
        Next
    End Using
End Sub

Dieser sucht nach dem entsprechenden Tag und löscht dessen Parent Parent. Wichtig ist hierbei das .Reverse() am Ende des For Each: Da aus der Liste gelöscht wird, muss diese von rückwärts bearbeitet werden, da es sonst zu [nicht ganz unbekannten Problemen(https://coderwall.com/p/prvrnw/remove-items-from-array-while-iterating-over-it)] kommt. Das Löschen des doppelten Parent beruht aktuell zum Teil auf einer sehr guten Heuristik, die bei mir fehlerfrei funktioniert, aber ganz wohl ist mir dabei nicht.

Einfügen von umlaufenden Bildern oder Bildern im Vorder- und Hintergrund

Das einfügen, austauschen und löschen von Bildern klappt mit der im ersten Teil beschriebenen Variante problemlos. Aber nur so lange, bis man auf die abwegige Idee kommt, die Bilder nicht mit dem Text in der Zeile zu positionieren. Bei mir hat dies immer dazu geführt, dass das Dokument repariert werden musste. Der Workaround aus dem MSDN-Forum funktioniert tadellos: Die Bilder als Content Control in eine einfaches Textfeld einfügen mit Text in Zeile und dieses Textfeld dann wie gewünscht positionieren.

Bilder löschen

Das letzte Problem betraf das Löschen von Bildern. Löscht man ein Bild, bleibt der Platzhalter stehen und wird zu allem Übel auch noch auf eine Standardgröße gesetzt, die ca. 45cm groß ist. Mein Workaround hierfür ist ein transparentes PNG 10px10px groß, dass ich stattdessen immer als Base64-String einfüge. Für meinen Anwendungsfall machte dies Sinn, da die Fläche für das Bild dann frei bleiben sollte.

Damit ist das Thema aktuell abgeschlossen. Die einfache Template-Erstellung durch jeden mit Word halbwegs vertrauten Kollegen ist damit zwar leider in weiter Ferne, aber nach meiner Ansicht die performanteste und schönste Lösung mit OpenXML.