|
Über seine Parent-Eigenschaft
kann ein UserControl eine ganze Menge über das Formular erfahren,
auf dem es platziert ist. Sie können sämtliche Eigenschaften
auslesen oder setzen - letzteres natürlich nur, wenn es sich nicht
um nur lesbare Eigenschaften des Formulars handelt. Ebenso können
Sie dessen Methoden aufrufen. Ein UserControl können Sie daher auch
zur funktionalen Erweiterung und Kontrolle von Formularen einsetzen.
Auf den ersten Blick scheint das allerdings nur in der Art einer
Einbahnstraße zu funktionieren. Einer der wesentlichen Aspekte der
Kontrolle ist der Empfang von Ereignissen. Offensichtlich scheint
Visual Basic jedoch einem UserControl keine Möglichkeit anzubieten,
als Ereignisempfänger von Formular-Ereignissen zu fungieren. Doch
der Schein trügt - wie so oft, wenn man in VB auf ein "Geht
nicht" zu stoßen glaubt.
Es geht nämlich sehr wohl, allerdings unter der Einschränkung,
dass einem UserControl die Objekttypen möglicher Parent-Objekte
bekannt sein müssen. Diese Einschränkung ist jedoch nur relativ zu
sehen. Wenn Sie nicht genau wissen, welchen Typs das über die
Parent-Eigenschaft erreichbare Objekt sein wird, auf dem ein
UserControl platziert wird, nützt ihnen der mögliche Zugriff auf
die Eigenschaften und Methoden des Parent-Objekts auch recht
herzlich wenig. Zu unterschiedlich können diese Objekte ausfallen.
Schon die Palette der bereits in VB enthaltenen Objekte ist nicht
gerade mager bestückt: Form, MDIForm, UserControl, PropertyPage und
UserDocument. Andere Steuerelemente, auf denen wiederum
Steuerelemente platziert werden können (wie etwa die PictureBox
oder ein Frame) zählen nicht dazu. Sie werden nicht unbedingt als
Parent erkannt und zur Verfügung gestellt. In VB wird
beispielsweise zwischen Container und Parent unterschieden. Das
Formular ist hier Parent sowohl für eine PictureBox als auch für
die auf dieser liegenden Steuerelemente, während für diese die
PictureBox wiederum als Container fungiert. In anderen Anwendungen,
in denen ActiveX-Steuerelemente verwendet werden können, etwa
Microsoft Access, Excel oder Word, sieht die Umgebung aus der Sicht
eines UserControls schon wieder ganz anders aus.
Wie gesagt, unter der Voraussetzung, dass die Verwendung eines
UserControls auf bestimmte Parent-Objekte eingeschränkt wird, kann
es die Parent-Ereignisse empfangen. An sich ist der Kniff hierfür
kein großes Geheimnis. Sie deklarieren einfach eine Objekt-Variable
des gewünschten Objekttyps mit dem Zusatz WithEvents.
Und schon stellt Ihnen VB die Ereignisprozeduren des Parent-Objekts
zur Bearbeitung zur Verfügung.
Private WithEvents eForm As Form
und/oder
Private WithEvents eMDIForm As MDIForm
Allerdings kommen nur dann Ereignisse an, wenn sich das
UserControl im UserMode
befindet (Ambient.UserMode = True). Anderenfalls macht die Zuweisung
wenig Sinn. Die Zuweisung des Parent-Objekts an einen dieser
Ereignisempfänger erfolgt daher im
UserControl_ReadProperties-Ereignis, wenn die Prüfung von
Ambient.UserMode erfolgreich war:
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
With UserControl
If Ambient.UserMode Then
If TypeOf .Parent Is MDIForm Then
Set eMDIForm = .Parent
ElseIf TypeOf .Parent Is Form Then
Set eForm = .Parent
End If
End If
End With
End Sub
Beachten Sie hier die Reihenfolge der Typ-Prüfung. Die Prüfung,
ob das Parent-Objekt ein MDIForm ist, muss unbedingt zuerst
erfolgen. Ein MDIForm wird nämlich von TypeOf
auch immer als Form erkannt, so dass es zuallererst ausgesiebt
werden muss. Wegen der Festlegung des Objekttyps des
Ereignisempfängers ist die Unterscheidung hier jedoch wichtig und
notwendig. Denn die Zuweisung eines MDIForms an den
Ereignisempfänger eForm würde einen Laufzeitfehler auslösen.
Über diese Ereignisempfänger-Variablen haben Sie zugleich auch
Zugriff auf die Eigenschaften und Methoden des jeweiligen Forms.
Wenn Sie jedoch bereits im Design-Modus darauf zugreifen wollen, um
beispielsweise Eigenschaften des betreffenden Forms zu
kontrollieren, über die sowohl Forms als auch MDIForms verfügen,
empfiehlt es sich, zusätzlich eine Objekt-Variable des Typs Form
(wie erwähnt, gilt auch ein MDIForm als Form) anzulegen. Sie
ersparen sich damit die ständigen Unterscheidungen, welche der
beiden Variablen, eForm oder eMDIForm, aktuell belegt ist. Sie
können diese zusätzliche Variable mForm natürlich auch im
Laufzeit-Modus verwenden. Damit die zusätzliche Variable mForm auch
gleich nach dem Neuplatzieren Ihres Controls nutzbar wird, ist die
Zuweisung des UserControl.Parents auch im InitProperties-Ereignis
notwendig, das hierbei anstelle von ReadProperties ausgelöst wird.
Für den Fall, dass ein Anwender das UserControl einmal
versehentlich oder unwissentlich auf einem anderen Objekt platzieren
sollte, erfolgt dann keine Zuweisung an eine der
Ereignisempfänger-Variablen.
Damit ergibt sich folgendes vollständige Grundgerüst zum
Empfang von Form-Ereignissen in einem UserControl:
Private mForm As Form
Private WithEvents eForm As Form
Private WithEvents eMDIForm As MDIForm
Private Sub UserControl_InitProperties()
If TypeOf .Parent Is MDIForm Then
Set mForm = .Parent
ElseIf TypeOf .Parent Is Form Then
Set mForm = .Parent
End If
End Sub
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
With UserControl
If Ambient.UserMode Then
If TypeOf .Parent Is MDIForm Then
Set eMDIForm = .Parent
Set mForm = .Parent
ElseIf TypeOf .Parent Is Form Then
Set eForm = .Parent
Set mForm = .Parent
End If
Else
If TypeOf .Parent Is MDIForm Then
Set mForm = .Parent
ElseIf TypeOf .Parent Is Form Then
Set mForm = .Parent
End If
End If
End With
End Sub
Zur Laufzeit des UserControls können Sie nun bis auf zwei alle
anderen Ereignisse eines Forms bzw. MDIForms empfangen und
bearbeiten. Diese zwei Ausnahmen sind die Ereignisse Initialize und
Terminate. Sie werden ausgelöst, bevor das UserControl geladen wird
bzw. nachdem es bereits entladen worden ist.
Wenn Sie die Form-Ereignisse zusätzlich auch im Code des Forms
bearbeiten, sollten Sie sich niemals darauf verlassen, wer die
Ereignisse zuerst zugestellt bekommt! Offensichtlich erhält zwar
das Form die Ereignisse zuerst und das UserControl erst danach. Aber
schon die weitere Reihenfolge , falls Sie mehrere Form-Ereignisse
empfangende UserControls auf einem Form verwenden, ist
grundsätzlich nicht eindeutig und immer vorhersagbar. Auch wenn sie
in hunderten Läufen beim Mitprotokollieren immer gleich zu sein
scheint - laut Dokumentation (VB und COM) ist sie nicht definiert
und kann sich gegebenenfalls ändern.
Als einfaches, aber recht effektvolles Beispiel für den Nutzen
des Ereignis-Mithörens zeige ich Ihnen zum Schluß, wie ein
UserControl bzw. sein Extender-Objekt
immer automatisch die gesamte Fläche seines Parent-Forms ausfüllen
kann (AutoSize):
Private Sub eForm_Resize()
With eForm
If .WindowState <> vbMinimize Then
Extender.Move 0, 0, .ScaleWidth, .ScaleHeight
End If
End With
End Sub

Korrekturen und Ergänzungen:
12.10.1999: Ergänzung des UserControl-Ereignisses InitProperties.
|