Schon vor einiger Zeit habe ich über das vorlagenbasierte Erweitern von Tabellen geschrieben. Vor kurzem wurde in einem Kommentar um Hilfe gebeten, den Quellcode in VB.Net umzusetzen. Meine Neugier war nahezu sofort geweckt, wie es wohl tatsächlich in VB.Net aussehen könnte.
So habe ich mich daran gemacht, den Quellcode zu portieren. Die erste Lösung war eine nahe 1:1 Umsetzung des Quellcodes. Einige Änderungen waren notwendig, wie etwa der Aufruf von TypParametern. Aus MyType<MyTypeParamter> wurde unter VB.Net beispielsweise MyType(Of MyTypeParameter).
Das Ergebnis sieht nun wie folgt aus.
Using package As WordprocessingDocument = WordprocessingDocument.Open(fileName, True)
Dim mainDocumentPart As MainDocumentPart = package.MainDocumentPart
Dim document As Document = mainDocumentPart.Document
Dim sdt As SdtBlock = document.Descendants(Of SdtBlock) _
.Where(Function(sdtBLock) sdtBLock.GetFirstChild(Of SdtProperties) _
.GetFirstChild(Of Tag).Val.Value = "Tabelle") _
.First
For i As Integer = 0 To 5
Dim lastRow As DocumentFormat.OpenXml.Wordprocessing.TableRow = sdt.Descendants(Of Table).First.Descendants(Of TableRow).Last
lastRow.InsertAfterSelf( _
New DocumentFormat.OpenXml.Wordprocessing.TableRow( _
New DocumentFormat.OpenXml.Wordprocessing.TableCell(New DocumentFormat.OpenXml.Wordprocessing.Paragraph(New DocumentFormat.OpenXml.Wordprocessing.Run(New DocumentFormat.OpenXml.Wordprocessing.Text(String.Format("Zeile {0}: Zelle 1", (i + 2)))))), _
New DocumentFormat.OpenXml.Wordprocessing.TableCell(New DocumentFormat.OpenXml.Wordprocessing.Paragraph(New DocumentFormat.OpenXml.Wordprocessing.Run(New DocumentFormat.OpenXml.Wordprocessing.Text(String.Format("Zeile {0}: Zelle 2", (i + 2)))))), _
New DocumentFormat.OpenXml.Wordprocessing.TableCell(New DocumentFormat.OpenXml.Wordprocessing.Paragraph(New DocumentFormat.OpenXml.Wordprocessing.Run(New DocumentFormat.OpenXml.Wordprocessing.Text(String.Format("Zeile {0}: Zelle 3", (i + 2))))))))
Next
End Using
Das gefiel mir syntaktisch eigentlich nicht besonders gut. Besonders die LINQ Erweiterungsmethoden mit den anonymen Methoden waren mir ein Dorn im Auge. Also habe ich noch etwas weiter gesucht und mich schließlich für eine Version mit der LINQ Abfrage Syntax entschieden. Dies lässt sich nun meines Erachtens deutlich einfacher lesen. Bedauerlicherweise war ich hierbei nur bedingt erfolgreich.
Wer hier mehr Erfahrung hat und mehr Kürze in die Abfragen bringen kann, soll sich hiermit dazu aufgerufen fühlen! ;-)
Ich hoffe, das hilft fürs erste auch weiter. Ich freue mich immer über solche Anreize, wieder etwas Neues auszuprobieren. :-)
10 Kommentare:
Schön, dass es hierzu ein Beispiel in VB gibt :-). Ich habe es wunderbar für meine Situation verwenden können.
Zwei Fragen sind geblieben:
1. Ich kann leider keine Tabelle nur mit Tabellenkopf verwenden - es muss immer mind. eine Zeile vorhanden sein.
2. Ich habe im docx ein zweites content control (rich text), wie kann ich dort einen einfachen Text zuweisen?
Hallo,
zu 1. Ich verstehe die Frage leider nicht ganz... Das Erweitern der Tabelle geht auch, wenn nur eine Kopfzeile existiert. Vermutlich ist das aber nicht gemeint?
zu 2. Ich sehe da zwei Möglichkeiten. Die erste Möglichkeit ist dem ContentControl ein Tag zuzuweisen und darüber zu identifizieren. Die Zweite geht über die ID des ContentControls im Dokument, die dokumentweit eindeutig ist. Das Einfügen des Textes funktioniert wie üblich...
Gruss Jan
zu 2: habe ich jetzt auch hinbekommen, danke.
zu 1: es ist wirklich so, wenn die Tabelle in der Vorlage nur den Kopf hat, dann kommt der Fehler "Sequence contains no elements" (auf "Dim sdt As SdtBlock..." wird verwiesen).
Ich habe es nur mit Header hinbekommen. Es hört sich für mich ein bisschen danach an, als würde das ContentControl nicht gefunden. Es wäre hier hilfreich, ein bisschen mehr Infos zu der internen Struktur des Vorlagendokument zu haben.
Gruss Jan
ja, das Problem habe ich auch. wenn ich ein neues docx mit einfacher tabelle (1 zeile) erstelle und mit dem vb quellcode von dieser seite arbeite, kommt der gleiche Fehler. Sobald meine Tabelle zwei oder mehr Zeilen hat geht es perfekt.
Ich habe eine Tabelle mit zwei Zeilen und lösche zum Schluss die letze Zeile einfach:
Dim lastRow2 As... (genau wie lastRow)
lastRow2.Remove()
Ich kann es leider immer noch nicht reproduzieren...
Wäre klasse, wenn mir jemand eine docx mit der es zu Reproduzieren ist zur Verfügung stellen könnte.
Gruss Jan
Hallo Jan, vielleicht eine dumme Frage, aber wie kann ich dir ein doxc zukommen lassen?
Stimmt, da fehlte doch was...
Am besten per Email an jan.c.selke@web.de schicken.
Ich habe mir das Dokument mal angesehen.
Das Problem liegt darin, dass das ContentControl nicht die Tabelle umschließt,sondern nur die erste Zeile.
(w:tbl)
(w:tblPr /)
(w:tblGrid /)
(w:sdt)
(w:sdtPr /)
(w:sdtContent)
(w:tr)
...
(/w:tr)
(/w:sdtContent)
(/w:sdt)
(/w:tbl)
Wenn das angepaßt wirt, funktioniert es.
Noch eine Kleinigkeit hinterher:
Wer dem ContentControl einen neuen Tag zuweist (also alles != "Tabelle"), muss natürlich nach dem eigenen Tag suchen.
Kommentar veröffentlichen