|
Es gibt Steuerelemente, die zur Laufzeit unsichtbar bleiben und
keinerlei funktionalen Bezug zu dem Container (Form, UserControl
usw.) haben, auf dem sie platziert sind. Solche Steuerelemente sind
etwa das Timer- und das CommonDialogs-Steuerelement. Wie im Artikel "Form-lose
Standard-Dialoge" gezeigt, lassen sich die
Standard-Dialoge aus letzterem Steuerelement sogar aufrufen, ohne
dass das Projekt ein Form enthalten müsste. Mit einem kleinen Trick
können Sie auch Ihren eigenen, zur Laufzeit unsichtbaren
Steuerelementen zu einer solchen doppelten Nutzbarkeit verhelfen.
Seit Visual Basic 6 ist es nämlich möglich, von außen
instanzierbare Klassen (Instancing = MultiUse [5]) in
einem ActiveX-Steuerelement-Projekt anzulegen. Somit wäre der
naheliegendste Weg, die Funktionalität des Steuerelements
zusätzlich auch noch in einer instanzierbaren Klasse anzubieten.
Doch warum sollten Sie sich doppelte Arbeit mit doppelten Code, und
wiederum doppelte und fehlerträchtige Arbeit bei späteren
Änderungen machen? Die Lösung lautet: Packen Sie die
Funktionalität allein in diese Klasse.
Nehmen wir einmal an, die Funktionalität bestünde darin, beim
Aufruf der Methode "Testen" eine MessageBox anzuzeigen.
Nennen wir die Klasse beispielsweise "CFormless", während
das Steuerelement selbst "Formless" heißt.
Public Sub Testen()
MsgBox "Testen"
End Sub
Zur Verwendung im ursprünglichen Sinne als zur Laufzeit
unsichtbares Steuerelement (Eigenschaft InvisibleAtRuntime =
True) instanzieren Sie im UserControl ein Objekt dieser
Klasse und rufen Sie deren Funktionen auf, wenn auf die
Eigenschaften und Methoden des Steuerelements zugegriffen wird.
Private mFormless As CFormless
Public Sub Testen()
mFormless.Testen
End Sub
Private Sub UserControl_Initialize()
Set mFormless = New CFormless
End Sub
Private Sub UserControl_Terminate()
Set mFormless = Nothing
End Sub
Soll die Funktionalität jedoch in einem Projekt ohne Form
genutzt werden, nehmen Sie in dieses Projekt einen Verweis auf die
OCX-Datei (über den Verweise-Dialog, nicht über den
Komponenten-Dialog der Werkzeugsammlung!) auf, instanzieren ein
Objekt der Klasse CFormless und rufen nun die Methode
"Testen" auf.
Public Sub Main()
Dim nFormLess As CFormless
Set nFormLess = New CFormless
nFormLess.Testen
End Sub
Soweit, so gut - dies ist die Lösung auf die einfache Weise.
Aber warum einfach, wenn es auch ein wenig komplizierter geht? Der
Punkt ist nämlich der, dass nun im Objekt-Katalog immer beide
Objekte auftauchen, beide mit allen Eigenschaften und Methoden. Für
den Verwender mag dies ein wenig verwirrend sein. Welches Objekt
soll oder muss er wann verwenden? Machen Sie es ihm doch ein wenig
einfacher - indem Sie sich scheinbar ein klein wenig mehr Arbeit
machen: Lassen Sie die Eigenschaften und Methoden der zusätzlichen
Klasse verschwinden.
Wie das gehen soll? Nun, es mag ein wenig verwickelt aussehen,
ist aber dennoch simpel. Anstatt die gleichen Eigenschaften und
Methoden wie beim UserControl öffentlich anzulegen, implementieren
Sie sie als Schnittstelle, die auf dem UserControl beruht:
Implements Formless
Private Sub Formless_Testen()
MsgBox "Testen"
End Sub
Mehr Arbeit als die zusätzliche "Implements"-Zeile ist
das nicht. Und unterm Strich ist es sogar noch weniger (schließlich
sagte ich ja einige Zeilen weiter oben "scheinbar"!). Denn
nun steht die Schnittstelle im Code-Modul zur Verfügung und Sie
können jede einzelne Prozedur der Schnittstelle bequem und ohne
Tipparbeit (die Sie anderenfalls hätten) aus der rechten
Auswahlliste des Code-Moduls der Klasse auswählen, nachdem Sie die
Schnittstelle in der linken Auswahlliste markiert haben. Darüber
hinaus zwingt Sie Visual Basic letzten Endes sogar dazu, auch nur ja
keine Prozedur zu vergessen.
Im UserControl ändert sich dagegen nur eine einzige Zeile, die
der Deklaration des Objekt-Variablen für die Klasse:
Private mFormless As Formless
Da Sie nun auch vom UserControl aus seine eigene, in der Klasse
implementierte Schnittstelle verwenden wollen, deklarieren Sie die
Objekt-Variable mit dem Namen des Steuerelements, so zu sagen als
"sich selbst" (oder wie auch immer man das bezeichnen
könnte...). Sie finden das gar nicht so verwickelt? Um so besser -
dann haben sie wahrscheinlich das Prinzip der
Schnittstellen-Implementierung bestens verstanden. Wenn nicht, ist
das vielleicht ein Ansatz und Anlass für Sie, sich einmal näher
damit zu befassen. Funktionieren tut das aber trotzdem und auf jeden
Fall.
Der Verwender sieht nun im Objekt-Katalog das Objekt CFormless
völlig "nackt" und wird nicht viel damit anzufangen
wissen. Sie müssen ihm lediglich erklären, dass er in einem
Projekt ohne Forms die benötigte Objekt-Variable zur Instanzierung
(genau so, wie Sie selbst in Ihrem UserControl) mit dem Namen des
UserControls deklarieren muss, und dass er (auch wie im UserControl)
trotzdem ein CFormless-Objekt instanzieren muss:
Public Sub Main()
Dim nFormLess As Formless
Set nFormLess = New CFormless
nFormLess.Testen
End Sub
Das daraufhin in der Objekt-Variablen steckende Objekt ist dann
zwar von der Klasse CFormless instanziert, verhält sich aber
hundertprozentig wie das Steuerelement selbst, das nach wie vor
unverändert verwendet werden kann. Der einzige Unterschied ist
natürlich, dass alle steuerelement-typischen Eigenschaften und
Methoden wie Left, Top oder Move und ZOrder fehlen. Aber diese sind
sowieso nicht Bestandteile Ihres Steuerelements, sondern werden
über das Extender-Objekt von der jeweiligen Container-Umgebung (in
unserem Fall Visual Basic) automatisch hinzugefügt, wenn das
Steuerelement tatsächlich als Steuerelement in die Werkzeugsammlung
geladen wird.
Dies ist übrigens auch der Grund dafür, dass ein Verwender
Ihres nach diesem Prinzip gebauten Steuerelements in einem Projekt
nicht beide Verfahren mischen kann. Das Steuerelement kann nur
entweder in die Werkzeugsammlung geladen und auf einem Form (oder
einem anderen Container) platziert, oder aber als Verweis
aufgenommen und dementsprechend verwendet werden. Beides
gleichzeitig geht nicht.
Damit Sie die Beispielprojekte (je eines mit und ohne Form)
problemlos testen können, führen Sie bitte das heruntergeladene
Setup aus. Das Beispiel ohne Form kann nicht ausgeführt werden,
ohne dass das kompilierte OCX registriert ist. Dies gilt auch für
Ihre eigenen Entwicklungen nach dem hier vorgestellten Prinzip.
|