Startseite > Archiv > Objekte an der Oberfläche: Windows Forms

Objekte an der Oberfläche: Windows Forms

 // FOCUS
Objekte an der Oberfläche: Windows Forms
Ralf Morgenstern
» Obwohl immer mehr Unternehmen immer mehr interne Informationen Web-basiert im Intranet bereitstellen, werden nach wie vor Fat- beziehungsweise Rich-Clients benötigt. Bislang wurden viele Clients mit Visual Basic oder mit den MFC und Visual C++ entwickelt, – zwei Sprachen, zwei APIs. Windows Forms kann von allen .NET-Sprachen benutzt werden und vereint die Vorzüge der beiden klassischen Systeme. Ein hoher Fun-Faktor ist zudem garantiert.
| 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.
» Über den Autor
Ralf Morgenstern ist Berater bei der TRIA IT-consulting München GmbH und Autor zahlreicher Publikationen zu den Themen Visual Basic, VBA, C++, XML sowie zu verschiedenen .NET-Themen.
Ralf.Morgenstern@t-online.de
Login
Sie sind nicht eingeloggt.

Login & Registrierung
Abo bestellen




Anzeige







Newsletter
Tragen Sie Ihre E-Mailadresse für den kostenlosen Newsletter von dotnetpro ein.


Umfrage
Verwenden Sie Application Lifecycle Management?





Ergebnis anzeigen