OwnWordRange

Unabhängig von der installierten Word-Version sein

Schon mal versucht, von Visual Basic auf Word zuzugreifen? Also einfach Word Interop verwenden. Auf den ersten Blick könnte man sich denken das das ja cool funktioniert. Alle notwendigen Word-Objekte stehen zur Verfügung, man kann Dokumente öffnen, per Code was reinschreiben und sie wieder schließen oder offen lassen.

Das Problem beginnt, wenn der Anwender eine andere Word-Version besitzt...

Also bräuchte man eine Bibliothek, die Zugriff auf die wichtigsten Word-Funktionen unabhängig von der Word-Version erlaubt. Und das unter Verzicht auf Word-Libraries.

Eine eigene Interop-Library für Microsoft Word

Meine Ansprüche sind nicht so hoch. Die eigene Anwendung sollte folgendes können:

  • Word-Dokumente oder -Vorlagen mit oder ohne Dokumentenvorlage erstellen und öffnen.
  • ein Dokument oder nur Bookmarks im Dokument mit Absätzen, Tabellen und Bookmarks ausfüllen können.
  • Im Word-Dokument hätte ich gerne einen verborgenen Abschnitt, in dem ich Dokument-spezifische Eigenschaften im Textformat unterbringen kann.

Zwei Dinge sind zu tun:

  1. Man braucht eine Klasse, die unabhängig von der installierten Word-Version Word-Dokumente öffnen und bearbeiten kann.
  2. Weil man ohne Word-Referenzen arbeitet, braucht man ein Objektmodell, das dem von Word ähnlich ist und mit dem man den Aufbau von Absätzen, Tabellen und formatiertem Text definieren kann.

Den Zugriff auf Word habe ich in meiner Library gekapselt. Die verwendeten Word-Objekte werden über Late Binding erstellt, bearbeitet und wieder frei gegeben.

Die in der Library nach Außen sichtbaren Klassen, Eigenschaften und Funktionen sollen möglichst so heißen, wie die in Word verwendeten. So kann man mit VBA-Kenntnissen recht einfach einen Inhalt für ein Word-Dokument definieren. Um von diesem Objektmodell eine Vorstellung zu haben, hier mal ein paar Inhalte der Klassenstruktur:

Es existiert eine Klasse Range, die Auflistungen für Tabellen, Absätze, Bookmarks... enthält:

Class Range

  • ReadOnly Property Tables() As Tables
  • ReadOnly Property Paragraphs() As Paragraphs
  • ReadOnly Property Bookmarks() As Bookmarks
  • ReadOnly Property Breaks() As Breaks

Jede dieser Auflistungen verfügt über eine oder mehrere Add -Methode(n), die ein Objekt zum Range hinzufügen und dieses Objekt zurück geben. Zum Beispiel:

Class Tables

  • Public Function Add(NumRows As Integer, NumColumns As Integer) As Table

Die Klasse Table hat dann wieder eigene Eigenschaften, die den Aufbau einer Word-Tabelle beschreiben.

Class Table

  • ReadOnly Property ColumnCount() As Integer
  • ReadOnly Property RowCount() As Integer
  • ReadOnly Property Cell(RowIndex As Integer, ColumnIndex As Integer) As Cell
  • Property Alignment() As WdRowAlignment
  • Property AutoFitBehavior() As WdAutoFitBehavior

Interessant ist hier die Klasse Cell, die wieder ein eigenes Range-Objekt enthält.

Class Cell

  • Property VerticalAlignment() As WdCellVerticalAlignment
  • ReadOnly Property Borders() As TableCellBorders
  • Property MergeTo() As Cell

Die Klassen, die im Word-Dokument Inhalt verändern sollen, haben eine gemeinsame Write-Methode:

  • Friend Sub Write(WordRange As Object)

Erstellt oder verändert werden Dokumente ausschließlich über Methoden der Klasse DocumentCreator.

Class DocumentCreator

  • Shared Function CreateDocument(Rng As Range, Path As String, Optional TemplatePath As String = "")
  • Shared Function OpenDocument(Path As String)

(Die Klasse DocumentCreator enthält übrigens zusätzlich als Property IsWordInstalled und als Event IsWordInstalled_Changed, um eine Anwendung darüber zu informieren, ob Word installiert ist, und wenn nicht, zu ermöglichen, Word-spezifische Funktionen zu deaktivieren.

Nun kann man Dokument-Inhalt für Word so beschreiben:

***
Dim RngAs New Range
DimPar As Paragraph
Dim Tbl As Table
Dim Rng1 As Range
Rng.Bookmarks.Add("SendersAddress")
Rng.Paragraphs.Add()
Rng.Breaks.Add(WdBreakType.wdSectionBreakContinuous)
Rng.Paragraphs.Add()
Tbl = Rng.Tables.Add(2, 1)
Tbl.Columns(0).PreferredWidth = CentimetersToPoints(8)
Rng1 = Tbl.Cell(0, 0).Range
Rng1.Bookmarks.Add("RecipientAddress")
Rng1.Format.Alignment = WdParagraphAlignment.wdAlignParagraphLeft
Rng1 = Tbl.Cell(1, 0).Range
Rng1.Bookmarks.Add( "SendersAddressLine")
Tbl.Cell(1, 0).Borders.TopBorder = WdLineStyle.wdLineStyleSingle
***

Das sieht doch fast schon so aus, wie Word-VBA. Und realisiert wird das als Word-Dokument durch die Klasse DocumentCreator (Methoden siehe oben).
Zugegeben, diese Klassenhierarchie erlaubt nur weniges von dem, was in Word möglich ist. Sie entspricht auch nur meinen eigenen Anforderungen. Man kann sie aber leicht ausbauen. Das Demo-Programm ist ganz schick geworden, man sollte es sich ansehen.

Wünsche Spaß beim Ausprobieren.

Word-Dokumente ohne Interop