|
| Windows folgt, wenn es um das GUI geht, einem einfachen
Prinzip: Jedes GUI-Element ist ein Fenster. Dabei spielt es keine Rolle, ob es
sich um eine Schaltfläche, eine Baumansicht oder eine Texteingabe handelt. Ein
UI-Element kann sich auch aus mehreren Fenstern zusammensetzen, aber letztlich
steht irgendwo ein Fenster.
In Windows Forms wird ein Fenster durch die Klasse Control
repräsentiert. Sie ist die Wurzel aller Fensterklassen und stellt grundlegende
Funktionen bereit, wie Hintergrundfarbe, Sichtbarkeit oder Text, und bildet
zudem die Nachrichtenverarbeitung auf Eventhandler ab. Teilweise wird hier nur
ein Prototyp vorgegeben, teilweise wird eine Standardverarbeitung
implementiert. Der markanteste Prototyp betrifft das Paint-Ereignis: Die Klasse
Control zeichnet sich nicht, das müssen abgeleitete Steuerelemente individuell
übernehmen. Anders verhält sich das Resize-Ereignis, das verschiedene
Layoutmechanismen bereitstellt, auf die alle von Control abgeleiteten Klassen
zurückgreifen können.
Die Standardklassen
Windows verfügte schon immer über einige vordefinierte
Fensterklassen, wie Schaltflächen, Listenfelder oder einfache
Texteingabefelder. Visual Basic hat diese Elemente als „eingebaute“
Steuerelemente angeboten. Windows Forms stellt sie über von Control abgeleitete
Klassen bereit: Button, ListBox, TextBox und so weiter.
Nachdem immer mehr komplexe Steuerelemente wie Toolbars oder
Baumansichten (Treeviews) entwickelt wurden, hat Microsoft das Standardangebot
erweitert und solche Elemente in Windows aufgenommen. C++-Programmierer können
sie direkt über das API oder die MFC ansprechen, in Visual Basic werden sie
über ActiveX Controls integriert. Dort gibt es sozusagen eine
Zwei-(Fenster-)Klassen-Gesellschaft. Eigene Steuerelemente lassen sich in
Visual Basic nur als ActiveX Controls entwickeln.
Windows Forms stellt die natürliche Gleichheit wieder her,
indem auch Treeviews und Toolbars von Control abstammen, es also nur noch einen
Typ von (Fenster-)Klassen gibt. Eigene Steu-erelemente werden ebenfalls von
Control abgeleitet.
Applikationsfenster und Dialoge
Für Applikationsfenster ist die Klasse Form vorgesehen, die
auch die Basis für Dialoge bildet. Jedes Windows-Forms-Programm arbeitet also
in der Regel mindestens mit einem Formular beziehungsweise einer von Form
abgeleiteten Klasse.
Windows Forms trägt aber einem wesentlichen Konzept von
Windows stärker Rechnung, als Visual Basic das getan hat: Fenster reagieren auf
Nachrichten, die kontinuierlich abgefragt werden müssen. Während Sie in Visual
Basic ohne Verrenkungen nur die Nachrichten benutzen konnten, die auf
Ereignisseabgebildet wurden, stehen Ihnen in Windows Forms (unabhängig von der
Programmiersprache) einige Verfahren zur Verfügung, um direkt und unabhängig
von Ereignissen auf Nachrichten zu reagieren. Die Message-Loop wird von Windows
Forms bereitgestellt, Sie müssen sich nur an geeigneter Stelle in die
Nachrichtenbearbeitung einklinken. Alle grundlegenden Operationen sind in der
Klasse Application gekapselt, deren Run-Methode ein geeigneter Einstiegspunkt
für GUI-basierte .NET-Programme ist.
Das erste Programm
Listing
1 zeigt ein Windows-Forms-Programm, das dem prominenten „Hello World“
recht nahe kommt. Es öffnet ein Anwendungsfenster, in dessen Titelzeile der
Text „Hello WinForms“ steht (Bild
1). Die Eigenschaft, um diesen Text zu setzen, ist Text, das ist ein
erster Unterschied zu Visual Basic, wo die entsprechende Eigenschaft Caption
heißt. Sie kompilieren das Programm auf der Kommandozeile mit:
vbc WinApp1.vb /r:System.dll
/r:System.Windows.Forms.dll
Es benötigt zwei der .NET-System-DLLs, die Sie über die
Option /r einbinden. Sie entspricht dem Setzen eines Verweises in Visual Studio
.NET. Das Listing enthält den kompletten Code für das Programm, es werden keine
zusätzlichen beschreibenden Daten benötigt, wie sie typischerweise in den
frm-Dateien von Visual Basic zu finden sind. Sie können das UI einer Anwendung
allein durch Anweisungen zusammenbauen. Einfacher ist das meist mit den
Designern von Visual Studio .NET, aber diese generieren letztlich auch nur
Code, der das UI zusammenbaut.
Ein einfacher Bildbetrachter
Listing
2 zeigt einen einfachen Bildbetrachter (Bild
2). Zu diesem Zweck wird die Anwendung aus
Listing 1 um einige Elemente erweitert: ein Menü, eine PictureBox und
einen Datei-Öffnen-Dialog.
Das Hinzufügen der PictureBox ist repräsentativ für den
Aufbau eines UIs in Windows Forms: Eine Instanzvariable – hier pic – nimmt
einen dauerhaften Verweis auf ein Steuerelement auf, über den es zur Laufzeit
des Programms angesprochen werden kann. Im Konstruktor (oder einer anderen
geeigneten Stelle im Programm) wird eine Instanz des Steuerelements erzeugt und
dessen Eigenschaften und Methoden werden verwendet, um das Steuerelement zu
konfigurieren. Damit das Steuerelement zum Formular – oder allgemeiner gesagt
zum Container – gehört, muss es zur Controls-Collection hinzugefügt werden.
Formulare, also Form-Klassen, sind nur ein möglicher Container-Typ; Panels,
TabPages und so weiter können ebenfalls Controls aufnehmen.
In diesem Fall wird nur eine Eigenschaft der PictureBox
verwendet: Dock. Rufen Sie sich kurz das Erscheinungsbild von Visual Studio
oder der Visual-Basic-IDE ins Gedächtnis; bestimmte Bedienelemente oder
Ausgabefenster sind an einer der Seiten des Hauptfenster angedockt. Das
bedeutet, dass unabhängig davon, wie Sie die Größe oder Position des
Hauptfensters verändern, diese Elemente immer am jeweiligen Rand haften
bleiben. Diesen Mechanismus stellt Windows Forms zur Verfügung.
Sie können Steuerelemente an den vier Außenseiten eines
Containers andocken und ein weiteres Element für die restliche Fläche vorsehen.
Da das Hauptfenster des Bildbetrachters keine anderen Steuerelemente aufnimmt,
füllt die PictureBox den gesamten Innenbereich aus. Der entsprechende
Dockingstil ist damit Fill.
Ein Menü lässt sich einfach per Hand aufbauen. Zuerst legen
Sie ein Hauptmenü beziehungsweise Applikationsmenü an, indem Sie eine Instanz
der Klasse MainMenu erzeugen. Danach verwenden Sie dann nur noch die Klasse
MenuItem für die einzelnen Menüeinträge. Dabei spielt es keine Rolle, ob Sie
Einträge der obersten Ebene anlegen, die immer sichtbar ist, oder
untergeordnete Einträge. Das MainMenu-Objekt weisen Sie der Menu-Eigenschaft
des Formulars zu, um es anzuwenden.
MenuItem verfügt über mehrere überladene Konstruktoren, wobei
die einfachste Variante lediglich den anzuzeigenden Text als Parameter
erwartet. Nun soll aber beim Anklicken eines Menüpunktes eine bestimmte Aktion
ausgeführt werden. Sie müssen also die MenuItem-Instanz noch mit einem
Eventhandler verknüpfen. Um diesen Vorgang zu verstehen, müssen Sie einige
grundlegende Mechanismen des .NET Frameworks verinnerlichen:
Events basieren auf dem Delegate-Mechanismus. Ein Delegate
ist ein Prototyp, der lediglich die Signatur einer Methode vorgibt, jedoch
keine Implementierung. Wenn Sie dabei an Schnittstellendeklarationen denken,
liegen Sie richtig. C-/C++-Programmierer können sich einen Delegate auch als
Funktionszeiger auf eine Callback-Funktion vorstellen.
Im .NET Framework ist ein Basis-Delegate vorgegeben, an dem sich alle
Eventhandler orientieren sollen. Das ist eine reine Vereinbarung, kein Compiler
oder sonstiges Tool kann das Einhalten dieser Vorgabe prüfen – es bietet sich
aber an. Dieser Prototyp ist:
Public Delegate Sub EventHandler (ByVal sender As
Object, ByVal e As EventArgs)
Der Aufbau ist einfach: Der erste Parameter verweist auf den
Auslöser beziehungsweise Absender des Ereignisses. Der zweite Parameter enthält
bei Bedarf weitere Angaben zu dem Ereignis. Da diese sehr unterschiedlich
ausfallen können, wurde mit EventArgs eine Basisklasse festgelegt, von der
spezifische Argument-Klassen abgeleitet werden können. Der Delegate für
Tastatureingaben sieht zum Beispiel wie folgt aus:
Public Delegate Sub
KeyPressEventHandler(ByVal sender As Object, ByVal e As KeyPressEventArgs)
Einem Ereignis kann mehr als ein Eventhandler zugeordnet
werden.
Es gibt verschiedene Verfahren, ein Ereignis mit einem
Ereignisbehandler zu verknüpfen, zum Beispiel die Anweisung AddHandler. In
vielen Fällen nehmen aber die Konstruktoren schon Verweise auf einen besonders
prägnanten Eventhandler auf, zum Beispiel für das Click-Ereignis von
Schaltflächen oder Menüs. MenuItem stellt einen Konstruktor bereit, der neben
dem Beschriftungstext auch einen Eventhandler als zweiten Parameter akzeptiert.
Die Methode muss dem EventHandler-Delegate entsprechen, einen Verweis erhalten
Sie mit AddressOf.
Neben einem Separator verwendet der Bildbetrachter zwei
Menüpunkte: einen zum Öffnen eines Bildes und einen zum Schließen der
Anwendung. Der Separator wird – und hier bewegen Sie sich auf vertrauten Bahnen
– durch einen Bindestrich gekennzeichnet. Die Methode CloseApp schließt das
Hauptfenster und damit die Anwendung. Die Anwendung wird beendet, weil der
Run-Methode der Application-Klasse eine Instanz von MyForm als Hauptfenster
übergeben wurde.
Zum Öffnen der Datei wird ein Datei-Öffnen-Dialog verwendet,
der über die Klasse OpenFileDialog bereitgestellt wird. Über die
Filter-Eigenschaft wird eine Auswahlliste mit Dateitypen festgelegt, dann wird
der Dialog mit ShowDialog angezeigt. ShowDialog zeigt stets einen modalen
Dialog an. Das Praktische daran ist, dass ShowDialog einen vernünftigen Wert
zurückgibt, anhand dessen Sie feststellen können, wie der Dialog geschlossen
wurde: OK-Schaltfläche oder Abbruch-Schaltfläche beziehungsweise Enter- oder
Esc-Taste. Das gilt nicht nur für vorgegebene Dialoge, sondern auch für eigene.
Dialoge
Dialoge basieren ebenfalls auf der Klasse Form.
Typischerweise setzen Sie die Eigenschaft FormBorderStyle auf FixedDialog und
schalten die MinimizeBox und MaximizeBox über die gleichnamigen Eigenschaften
aus. In Listing
3 behält FormBorderStyle den Standardwert, um einige andere
Möglichkeiten demonstrieren zu können.
Der Dialog enthält ein Textfeld sowie zwei Schaltflächen.
Wird der Dialog in der Größe verändert, soll sich die Breite des Eingabefeldes
stets an die Breite des Dialogfensters anpassen. Die OK-Schaltfläche soll in
der linken unteren Ecke verankert werden, die Abbrechen-Schaltfläche in der
rechten unteren Ecke. Um das zu realisieren, wird die Anchor-Eigenschaft der
Steuerelemente so gesetzt, dass Anker an den entsprechenden Fensterrändern
„ausgeworfen“ werden. Ein Anker bedeutet, dass der Anfangsabstand zu den
festgelegten Rändern konstant bleibt, unabhängig von den Abmessungen des
Containers, hier des Dialogs. Letztlich werden die Schaltflächen bei jeder
Größenänderung neu positioniert – das übernimmt aber Windows Forms (Bild
3), Sie selbst setzen nur die Anchor-Eigenschaft entsprechend Ihrer
Anforderungen. Zudem wird die Breite des Textfeldes jeweils angepasst, deren
Position bleibt aber konstant.
Die Schaltflächen werden im Zuge der Initialisierung
positioniert und auf eine bestimmte Größe gesetzt. Bleibt nur, die Abmessungen
des Formulars mit der benötigten Größe der Arbeitsfläche (des
Client-Rectangles) in Einklang zu bringen. Aber statt die Abmessungen des
Formulars zu berechnen, setzen Sie mit SetClientSizeCore einfach die
Abmessungen des Arbeitsbereichs und überlassen das Berechnen der gesamten
Fenstergröße Windows Forms. Falls Sie doch mal wissen möchten, wie hoch eine
Titelzeile oder eine Menüzeile ist, können Sie das über die Eigenschaften
CaptionHeight und MenuHeight der Klasse SystemInformation feststellen.
Damit ShowDialog zu den Schaltflächen passende Werte
zurückgibt, setzen Sie die Eigenschaft DialogResult der Klasse Button
entsprechend deren Bestimmung. Das führt aber nur dazu, dass beim Anklicken
einer Schaltfläche mit der Maus der zugeordnete DialogResult-Wert zurückgegeben
wird, es berücksichtigt nicht die Tastatur. Um den Dialog mit der Enter-
beziehungsweise Esc-Taste zu schließen, setzen Sie die Eigenschaften
AcceptButton und CancelButton.
Bleibt noch die Frage, wie Sie im Dialog erfasste Werte an
den Aufrufer zurückgeben. Prinzipiell könnten Sie die Steuerelemente öffentlich
deklarieren und über deren Eigenschaften die Werte abfragen. Das öffnet aber
auch einige Hintertürchen für unbeabsichtigte Manipulationen. Deshalb ist es
besser, Eingabewerte über korrespondierende Eigenschaften zurückzugeben. Im
Beispiel ist das die Eigenschaft InputText, die den im Textfeld erfass-ten Text
zurückgibt.
System.Drawing
Beim Setzen der Size- und Location-Eigenschaften, mit denen
Größe und Position festgelegt werden, kommen die Strukturen Size und Point zum
Einsatz, die im System.Drawing-Namespace definiert sind, zusammen mit einigen
anderen häufig benötigten Datentypen. Primär enthält System.Drawing grafische
Ausgabefunktionen und kapselt das GDI+ für das .NET Framework. Datentypen wie
Point, Rectangle, Color oder Font werden auch in Web-Applikationen verwendet,
sind also nicht an die Bereiche Drawing oder Windows Forms gebunden. Um diese
Elemente nutzen zu können, müssen Sie das entsprechende Assembly referenzieren.
Komplexer: ein Dateibetrachter
Ein weiteres Beispiel soll den Reigen neuer Möglichkeiten
abrunden. Statt nur je ein Bild anzeigen zu können, soll ein erweiterbarer
Dateibetrachter entstehen, der unterschiedliche Dateiformate anzeigen kann.
Ergänzend zu den fest eingebauten Betrachtern, sollen weitere durch zusätzliche
Assemblies hinzugefügt werden können. Diese Assemblies können Viewer-Objekte
enthalten, die vom Dateibetrachter wie die fest eingebauten Viewer behandelt
werden.
Die Oberfläche des Programms XViewer (Bild
4 ), ist in zwei Bereiche eingeteilt: Links steht ein Tab-Control,
rechts stehen die Viewer, von denen aber immer nur einer sichtbar ist. Die
beiden Bereiche sind durch ein Splitter-Control getrennt, das es erlaubt, die
Breite der Elemente zu ändern. Für beide Bereiche ist ein Panel vorgesehen, das
die Steuerelemente des Bereichs aufnimmt. Dieses Verfahren hat sich im Laufe
der Zeit bewährt, da Änderungen leichter durchzuführen sind.
Um diese Funktionalität zu realisieren, setzen Sie die
Dock-Eigenschaften des Splitters und der Panels. Für das linke Panel und das
Splitter-Control verwenden Sie DockStyle.Left, das Viewer-Panel wird auf
DockStyle.Fill gesetzt. Außerdem ist wichtig, in welcher Reihenfolge die
Steuerelemente zur Controls-Collection hinzugefügt werden – experimentieren Sie
etwas, und Sie werden die interessantesten Layouteffekte erzielen.
Das Tab-Control hat zwei Seiten. Eine Seite nimmt eine Liste
auf, die die geöffneten Dateien enthält. Die zweite Seite enthält
Steuerelemente zum Auswählen einer Datei. Das obere Element zeigt in einer
Baumansicht Verzeichnisse an, das untere die Dateien des ausgewählten
Verzeichnisses, zwischen den beiden liegt wiederum ein Splitter-Control. Die
Dock-Eigenschaft wird vergleichbar dem eben beschriebenen Szenario gesetzt,
allerdings kommt statt DockStyle.Left nun DockStyle.Top zum Einsatz.
Die Dateiliste enthält immer die geöffneten Dateien, so dass
einfach zwischen den einzelnen Viewern umgeschaltet werden kann. Es handelt
sich um ein Listenfeld, das als Einträge Referenzen auf die Viewer enthält.
Listbox-Items sind in Windows Forms vom Typ Object, so dass ein Listenfeld
beliebige Typen aufnehmen kann. Die textuelle Anzeige des Listenfeldes wird
durch Aufrufen der Funktion ToString ermittelt. Daher sollten alle Viewer diese
Funktion in geeigneter Weise überschreiben.
Die Verzeichnis- und Dateiauswahl erfolgt über eine von der
Treeview- und Listview-Klasse abgeleitete Klasse, die um einige Eigenschaften
und Methoden erweitert wurde. Die Verzeichnisanzeige zeigt anfangs alle
Laufwerke an. Da das Durchlaufen aller Verzeichnisse dieser Laufwerke zum
Aufbauen eines kompletten Verzeichnisbaumes zu langwierig wäre, wird hier ein
Trick angewandt: Es wird nur die zur aktuellen Anzeige benötigte
Verzeichnisebene sowie eine darunter liegende abgefragt. Um feststellen zu
können, welche Ebene schon einmal durchlaufen wurde, wird ein Flag gesetzt. Die
Tag-Eigenschaft eines Knotens in der Baum-ansicht erhält den Wert true, wenn
die Verzeichnisliste schon einmal gelesen wurde. Die Eigenschaften sind an die
von Visual Basic bekannten Steuerelemente für die Verzeichnis- und Dateiauswahl
angelehnt. Diese Elemente stehen Ihnen übrigens nach wie vor zur Verfügung, sie
werden nur standardmäßig nicht in der Toolbox angezeigt.
Wie kann die Anwendung XViewer nun beliebige Dateibetrachter
(Viewer) einbinden und verwenden? Um das zu realisieren, werden drei Techniken
kombiniert:
Die .NET-spezifische späte Bindung, um Objekte aus Assemblies
(hier einfach DLLs) zu laden.
Attribute, um die relevanten Typen (Klassen) in den geladenen Assemblies zu
kennzeichnen.
Schnittstellen, um unterschiedliche Steuerelemente einheitlich ansprechen zu
können.
Im .NET Framework enthalten Applikationen normalerweise
Referenzen auf die zur Ausführung benötigten Assemblies. Sie können Assemblies
aber auch dynamisch zur Laufzeit des Programms nachladen, ohne dass ein
statischer Verweis darauf exis-tiert. Das ist mit der API-Funktion LoadLibrary
vergleichbar. LoadLibrary lädt eine DLL, so dass Sie mit GetProcAddress Zeiger
auf vorhandene Funktionen erfragen können. .NET erlaubt es Ihnen,
Typinformationen zu den Datentypen in einem geladenen Assembly zu ermitteln.
Über diese Typinformationen können Sie Instanzen erzeugen und deren Methoden
und Eigenschaften nutzen. Das ist vergleichbar mit dem Erzeugen eines
COM-Objekts mit CreateInstance oder CreateObject.
Folgende Codesequenz lädt ein Assembly, erzeugt eine Instanz
von Form, unabhängig davon, ob das Windows-Forms-Assembly in der Anwendung
referenziert wird (der Pfad muss evtl. angepasst werden):
Dim asm As System.Reflection.Assembly =
System.Reflection.Assembly.LoadFrom( _
"C:\WINNT\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll")
Dim t As Type = asm.GetType("System.Windows.Forms.Form")
Dim frm As Object = Activator.CreateInstance(t)
Nun gilt es eine Frage zu klären: Welche Assemblies soll die
Anwendung XViewer laden? Das ließe sich über eine Konfigurationsdatei
festlegen, oder es werden einfach alle DLLs im Anwendungsverzeichnis geladen.
XViewer arbeitet nach der zweiten Variante. Daraus resultiert die zweite Frage:
Welche Klassen in einem Assembly sind XViewer-kompatible Viewer-Objekte?
Auftritt Attribute!
Attribute sind benutzerdefinierte Metadaten, mit denen Sie
Klassen, Methoden und so weiter ausschmücken können. Sie definieren ein eigenes
Attribut, indem Sie eine Klasse von System.Attribut ableiten und mit eigenen
Funktionen ausstatten. Das Attribut XViewerAttribute wird benutzt, um Typen als
Viewer zu kennzeichnen und gleichzeitig einige Informationen über den
Betrachter bereitzustellen. Neben einer Beschreibung nimmt das Attribut auch
die Dateierweiterungen der anzeigbaren Dateiformate auf.
Im XViewer werden eingebaute (interne) und externe Viewer
gleich behandelt. Alle werden durch den Erkennungsprozess geschleust. Der
einzige Unterschied besteht darin, dass für die internen Viewer kein Assembly
geladen, sondern das aktuell ausgeführte referenziert wird.
So weit, so gut. Die verfügbaren Viewer sind bekannt und
können instanziert werden. Aber wie lädt Viewer A eine Datei? Und macht Viewer
B das auf die gleiche Weise?
Um eine einheitliche Verwendung zu erreichen, wird eine
Schnittstelle definiert, die festlegt, wie die Load-Funktion auszusehen hat.
Zudem sieht diese Schnittstelle ein Verfahren vor, um weitere Operationen
durchführen zu können. Dabei wird zwischen Standardoperationen und
individuellen Funktionen unterschieden. XViewer unterstützt das Setzen von
Vordergrund- und Hintergrundfarbe sowie eines Fonts durch Dialoge. Da alle
Viewer von Control abgeleitet sein müssen, können die entsprechenden
Eigenschaften direkt genutzt werden. Die Viewer müssen lediglich angeben, ob
sie diese Operationen unterstützen – für einen Bildbetrachter ist das Setzen
eines Fonts nicht sinnvoll.
Für individuelle Operationen liefern die Viewer ein
String-Array mit Kommandos zurück. Diese werden einfach in Menüpunkten
angezeigt und bei Auswahl über eine weitere Funktion an die Viewer
zurückgereicht, die dann selbst die notwendigen Schritte unternehmen. Für den
Bildbetrachter wird auf diese Weise eine Stretch-Funktion bereitgestellt. Das
Verfahren ist sehr einfach und bietet trotzdem einige Möglichkeiten.
ActiveX
In den letzten Jahren wurde viel Energie in die Entwicklung
von ActiveX-Controls gesteckt. .NET arbeitet mit anderen Techniken, was
immerhin den Vorteil hat, das Sie ohne Registry auskommen. Die Mühen waren
allerdings nicht vergebens, denn Sie können ActiveX-Komponenten in
.NET-Applikationen nutzen und damit auch ActiveX-Controls in
Windows-Forms-Programmen.
XViewer ist mit einem HTML-Viewer ausgestattet, der auf dem
WebBrowser-Steuerelement basiert. Um es zu verwenden, erzeugen Sie mit dem
SDK-Tool aximp eine Wrapperklasse.
Das direkte Referenzieren des WebBrowser-Steuerelements über
Visual Studio .NET mündete leider in einem für diesen Zweck ungeeigneten
Wrapper, so dass Sie nicht ohne aximp auskommen.
Die Wrapperklasse können Sie weitgehend so verwenden wie ein
normales Windows-Forms-Steuerelement. Allerdings müssen Sie einige
Methodenaufrufe im Sandwichverfahren absichern. Rufen Sie zuerst BeginInit,
dann die Methoden, dann EndInit auf.
Projektstruktur
XViewer setzt sich aus mehreren Komponenten zusammen, der
Applikation selbst und einer Windows-exe, die auch schon einen Text- und
Bildbetrachter enthält. Damit Viewer die Schnittstelle implementieren und das
Attribut benutzen können, müssen Sie das Assembly referenzieren, das diese
definiert. Da Sie keine exe referenzieren können, stehen die Basiselemente in
einer Klassenbibliothek. Der HTML-Viewer ist in einem eigenen Projekt
realisiert, genau wie die Verzeichnis- und die Dateiliste. Die beiden Listen
sind von generellem Interesse und auch für andere Projekte interessant. Um
Abhängigkeiten leicht beherrschen zu können, wurden die Pfade für die erzeugten
Dateien auf ein gemeinsames bin-Verzeichnis umgestellt. Das macht den Umgang
mit solchen Komponenten einfacher, die ActiveX-Steuerelemente verwenden, weil
dann auch die Wrapper-Klassen für die ActiveX-Steuerelemente im
Anwendungsverzeichnis liegen müssen.
Ausblick
In der nächsten Ausgabe wird es intensiver um die Entwicklung
von Custom Controls gehen. Bislang basierten alle Controls auf bestehenden
Steuerelementen, manchmal fangen Sie aber auch bei null an. Dann wird die
Design-Time-Unterstützung richtig interessant, und auch ein tieferer Einblick
in das Message-Handling steht an. |
 |
 |