ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 17.05.2001

Diese Seite wurde zuletzt aktualisiert am 17.05.2001
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für den Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

Control-Parade

Zurück...


Anzeige

(-hg) mailto:hg_ctlsonproppage@aboutvb.de

Steuerelemente wie das ListView- oder das TreeView-Steuerelement aus den Microsoft Common Controls machen es vor, wie man ein Partner-Steuerelement zu einem Steuerelement auswählen kann. Dort können Sie nämlich im Eigenschaften-Dialog das zur Darstellung der Symbole gewünschte (und benötigte) ImageList-Steuerelement aus einer Liste (Combo) der auf dem Eltern-Form (bzw. -Container) vorhandenen ImageList-Steuerelemente auswählen.

Eine Auswahl von Steuerelemementen des übergeordneten Containers in einer Eigenschaftenseite eines UserControls

Eine Auswahl von Steuerelemementen des übergeordneten Containers in einer Eigenschaftenseite eines UserControls

Das Prinzip ist eigentlich recht einfach. Denn die Eigenschaft ParentControls des UserControls liefert alle Objekte des Containers (Forms), auf dem es platziert ist, in einer Collection. Sie brauchen nur noch die Objekte des gesuchten Steuerelement-Typs herauszufischen und darunter das gewünschte auswählen zu lassen.

Dazu versehen Sie Ihr UserControl mit einer Friend-Methode (Function), über die von einer Eigenschaftenseite (Propertypage) aus die ParentControls-Eigenschaft zur Verfügung gestellt wird.

Friend Function FormControls() As VBRUN.ParentControls
  Set FormControls = UserControl.ParentControls
End Function

Im Ereignis SelectionChanged in der Eigenschaftenseite können Sie dann diese Collection auslesen, aussieben und die Namen der passenden Steuerelemente in eine ListBox oder ein eine ComboBox einfügen.

Private Sub PropertyPage_SelectionChanged()
  Dim nObj As Object

  With cboImageLists
    .Clear
    .AddItem "[keine]"
    For Each nObj In SelectedControls(0).FormControls
      If TypeOf nObj Is ImageList Then
        .AddItem nObj.Name
      End If
    Next
  End With
  Changed = False
End Sub

Zumindest sollte das eigentlich theoretisch so gehen. Der erste Haken dabei ist, dass die Friend-Methode FormControls offensichtlich nicht verfügbar zu sein scheint. Das liegt daran, dass in einer Eigenschaftenseite ein UserControl von "außen" gesehen wird, wie auch zur Laufzeit von einem Container-Projekt aus. Und Friend-Methoden oder -Eigenschaften sind von dort aus nicht sichtbar.

Statt dessen müssen Sie zunächst eine Variable des Typs Ihres UserControls anlegen und dieser das in SelectedControls(0) zur Verfügung stehende Objekt zuweisen. Damit werden auch die Friend-Elemente greifbar, gewissermaßen über die "Friend-Schnittstelle".

Private Sub PropertyPage_SelectionChanged()
  Dim nUC As ucWithImageList
  Dim nObj As Object

  Set nUC = SelectedControls(0)
  With cboImageLists
    .Clear
    .AddItem "[keine]"
    For Each nObj In nUC.FormControls
      If TypeOf nObj Is ImageList Then
        .AddItem nObj.Name
      End If
    Next
  End With
  Changed = False
End Sub

Ein weiterer Haken zeigt sich, falls sich unter den gesuchten Steuerelementen einige aus einem Steuerelementfeld (Control-Array) befinden sollten. Sie können zwar auch die Namen dieser Steuerelemente einlesen. Doch können Sie sie in der Liste dann nicht mehr voneinander unterscheiden - die typische Kennzeichnung mit dem in Klammern dahintergesetzten Index fehlt noch. Holen wir also auch dies noch nach:

Private Sub PropertyPage_SelectionChanged()
  Dim nUC As ucWithImageList
  Dim nObj As Object
  Dim nName As String
  
  Set nUC = SelectedControls(0)
  With cboImageLists
    .Clear
    .AddItem "[keine]"
    For Each nObj In nUC.FormControls
      If TypeOf nObj Is ImageList Then
        If nObj.Index > -1 Then
          nName = nObj.Name & "(" & nObj.Index & ")"
        Else
          nName = nObj.Name
        End If
        .AddItem nName
      End If
    Next
  End With
  Changed = False
End Sub

Das klappt nun schon ganz prächtig. Nun stellt sich die Frage, wie Sie die dann getroffene Auswahl Ihrem UserControl bekannt machen. Wie sie oben gesehen haben, begnügen wir uns damit, lediglich die Namen der ausgesiebten Steuerelemente in die ComboBox einzulesen. Die betreffenden Steuerelemente selbst interessieren uns gar nicht weiter - mit dem Ende des SelectionChanged-Ereignisses sind sie ja wieder vergessen.

Der erste Gedanke wäre, Ihr UserControl mit einer Friend-Eigenschaft zu versehen, der Sie den Namen des ausgewählten Steuerelements übergeben könnten. Dort wäre lediglich wieder das zu dem Namen gehörende Steuerelement aus der ParentControls-Collection herauszufischen und einer Variablen innerhalb des UserControls zuzuweisen.

Damit wären wir schon beim nächsten Problem. Denn wie würden Sie das gewählte Steuerelement im PropertyBag (für das Gespann WriteProperties/ReadProperties) ablegen wollen, damit sich das UserControl daran erinnert?

Die direkte Übergabe eines Steuerelements an das PropertyBag ist leider nicht auf die Weise möglich, wie Sie es etwa von einem Picture- oder einem Font-Objekt her gewohnt sind. Auch dort können Sie lediglich den Namen des Steuerelements ablegen und wieder zurückbekommen. Schon aus diesem Grunde liegt es nahe, den Gedanken einer reinen Ablage als String, sowohl in der UserControl-internen Variablen, als auch im PropertyBag, weiter zu verfolgen.

Wie Sie wissen, kennt ein UserControl zwei verschiedene Laufzeit-Zustände. Zum einen die Laufzeit zur Entwicklungszeit des Containers, zum anderen die "richtige" Laufzeit in der kompilierten (bzw. Debug-)Laufzeit-Version des Containers. Die Auswahl über eine Eigenschaftenseite als auch das Ablegen im PropertyBag (WriteProperties) sind nur zur Entwicklungs-Laufzeit relevant. In diesem Zustand des UserControls können wir uns also auf die Verwaltung eines Namens in String-Form beschränken. Treffen Sie also die klare Unterscheidung - dies ist anhand der UserMode-Eigenschaft des Ambient-Objekts möglich -, und Sie benötigen das gewählte Steuerelement dann auch nur noch zur Container-Laufzeit als tatsächliches Steuerelement-Objekt.

Wenn Sie nun aber schon einmal dabei sind, das betreffende Steuerelement einmal in String-Form und einmal in Objekt-Form zu behandeln und die notwendigen Mechanismen vorzusehen und zu entwickeln, können Sie Ihr UserControl mit einem Feature ausstatten, das so kein direktes Vorbild hat. Nämlich zum einen der Möglichkeit, die öffentliche Eigenschaft, über die auf das ausgewählte Steuerelement zugegriffen werden soll, auch im Eigenschaften-Fenster anzuzeigen und dort auch von Hand den Namen des gewünschten Steuerelements eingeben zu können. Aufgrund der dafür notwendigen "Dualität" der Eigenschaft (wie das genau aussieht, werde ich Ihnen gleich zeigen) sollte es dann auch möglich sein, zur kompilierten Laufzeit der Container-Anwendung ein Steuerelement nicht nur als Objekt zuzuweisen, sondern nur dessen Namen als String zu übergeben.

Die Lösung hierfür bietet die tatsächliche "Dualität" einer Eigenschaft, wenn es sich um eine Objekt-Eigenschaft handelt. Wie Sie sicher festgestellt haben werden, müssen sich die Get-Prozedur und die Let-Prozedur immer auf den gleichen Datentyp beziehen. Dies gilt jedoch nicht für die Set-Eigenschaft. Ihr Datentyp kann ein anderer sein, allerdings mit der naheliegenden Beschränkung, dass es sich um einen Objekt-Datentyp handeln muss. Dafür kann sich jedoch die Get-Prozedur als auch die Let-Prozedur auf einen beliebigen Datentyp beziehen. Soll aber über die Get-Prozedur ein über die Set-Prozedur zugewiesenes Objekt auch wieder ausgelesen werden können, muss hier natürlich auch ein für dieses Objekt gültiger Objekt-Datentyp verwendet werden. Doch nein, das stimmt nicht ganz: Sie können hier auch den Variant-Datentyp verwenden! Das Dreigespann Get/Let/Set kann also über das Datentyp-Muster Variant/Variant/Steuerelement-Typ verfügen. Und damit hätten wir, was wir benötigen.

Im UserControl brauchen wir nun also zwei Variablen zur Verwaltung des Steuerelements: eine String-Variable und eine Objekt-Variable des Steuerelement-Typs:

Private mImageListName As String

und

Private pImageList As ImageList

Die Get-Prozedur sieht noch einigermaßen einfach aus (erschrecke ich Sie etwa?):

Public Property Get ImageList() As Variant
  If Ambient.UserMode Then
    Set ImageList = pImageList
  Else
    ImageList = mImageListName
  End If
End Property

Je nach Laufzeit-Zustand wird somit entweder ein Steuerelement als Objekt oder sein Name zurückgegeben.

Die Set-Prozedur weist schon einige Zeilen mehr auf. In erster Linie rührt das von einigen Sicherheitsmaßnahmen her - schließlich soll ja kein beliebiges Objekt, sondern ein Steuerelement eines ganz bestimmten Typs übernommen werden. Und natürlich muss auch das Löschen per Übergabe von Nothing möglich sein.

Public Property Set ImageList(New_ImageList As Object)
  If TypeOf New_ImageList Is ImageList Then
    If Ambient.UserMode Then
      Set pImageList = New_ImageList
    Else
      mImageListName = New_ImageList.Name
    End If
  ElseIf New_ImageList Is Nothing Then
    If Ambient.UserMode Then
      Set pImageList = Nothing
    Else
      mImageListName = "[keine]"
    End If
  Else
    Err.Raise 380
  End If
  PropertyChanged "ImageList"
End Property

Sie fragen sich, warum die Übergabe eines falschen Steuerelement-Typs nicht einfach durch die entsprechende Deklaration des Übergabeparameters gewährleistet wird? Grundsätzlich wäre das schon möglich, allerdings ausschließlich dann, wenn das UserControl privat in einem Projekt verwendet wird. Bei einem öffentlichen UserControl in einem OCX-Projekt dürfen zumindest VB-interne Steuerelement-Typen nicht übergeben werden. Auch wenn es sich hier um ein ImageList-Steuerelement handelt - VB wird trotzdem unter Ausgabe einer Fehlermeldung streiken (ach so, ja, Sie werden es doch sicher längst gemerkt haben, dass es sich die ganze Zeit um die Auswahl eines ImageList-Steuerelements dreht, gemäß den Vorbildern des ListView- und TreeView-Steuerelements, oder?). Daher die Deklaration der Übergabe "As Object" und die interne Prüfung.

Nun wird es tatsächlich etwas komplizierter - wir kommen zur Let-Prozedur:

Public Property Let ImageList(New_ImageList As Variant)
  Dim nObj As Object
  Dim nNewImageListName As String
  Dim nIsCtlArray As Boolean
  Dim nIndex As Integer
  Dim nPos As Integer
  
  If Not Ambient.UserMode Then
    If VarType(New_ImageList) <> vbString Then
      Err.Raise 380
    End If
  End If
  If IsObject(New_ImageList) Then
    If TypeOf New_ImageList Is ImageList Then
      Set pImageList = New_ImageList
      PropertyChanged "ImageList"
      Exit Property
    End If
  ElseIf VarType(New_ImageList) = vbString Then
    nNewImageListName = Trim$(New_ImageList)
    nPos = InStr(nNewImageListName, "(")
    If nPos Then
      nIsCtlArray = True
      nIndex = Val(Mid$(nNewImageListName, nPos + 1))
      nNewImageListName = Left$(nNewImageListName, nPos - 1)
    End If
    Select Case LCase$(nNewImageListName)
      Case "", "[keine]"
        If Ambient.UserMode Then
          Set pImageList = Nothing
        Else
          mImageListName = kNoImageList
          PropertyChanged "ImageList"
        End If
        Exit Property
      Case Else
        For Each nObj In UserControl.ParentControls
          If TypeOf nObj Is ImageList Then
            If StrComp(nObj.Name, nNewImageListName, vbTextCompare) _
             = 0 Then
              If nIsCtlArray Then
                If nObj.Index <> nIndex Then
                  Set nObj = Nothing
                End If
              End If
              If Not (nObj Is Nothing) Then
                If Ambient.UserMode Then
                  Set pImageList = nObj
                  Exit Property
                Else
                  If nIsCtlArray Then
                    mImageListName = nObj.Name & "(" & nIndex & ")"
                  Else
                    mImageListName = nObj.Name
                  End If
                  PropertyChanged "ImageList"
                  Exit Property
                End If
              End If
            End If
          End If
        Next
    End Select
  End If
  Err.Raise 380
End Property

Auch hier sind wieder verschiedene Prüfungen notwendig. Denn da wir es hier, passend zur Get-Prozedur, mit der Übergabe eines Variant-Wertes zu tun haben, könnte ja alles mögliche aufkreuzen. Wir wollen es aber zur Entwicklungslaufzeit nur mit Strings, und zur Container-Laufzeit nur mit Strings oder mit Objekt-Referenzen des betreffenden Steuerelement-Typs zu tun haben. Der Aufwand zur Container-Laufzeit ist ähnlich gering wie in der Get-Prozedur, wenn ein Steuerelement-Objekt übergeben wird. Wird dagegen ein String übergeben, müssen wir uns auch darum kümmern, dass ein Steuerelement-Name am Ende eine Index-Kennung tragen kann. Oder dass ein leerer String oder ein Default-Name wie beispielsweise "[keine]" als Löschung übergeben wird. Grundsätzlich müssen wir natürlich auch prüfen, in beiden Laufzeitzuständen gleichermaßen, ob es das mit dem übergebenen Namen bezeichnete Steuerelement (und dann gegebenenfalls auch noch mit dem richtigen Index) tatsächlich gibt. Und zur Container-Laufzeit müssen wir schließlich das betreffende Steuerelement aus der ParentControls-Collection der im UserControl vorgesehenen Objekt-Variablen für das Steuerelement zuweisen.

Das Schwierigste ist nun eigentlich geschafft. Bleibt nur noch die "Kleinigkeit" der Ablage im PropertyBag. Der kleinere Teil dieser "Kleinigkeit" wiederum betrifft das WriteProperties-Ereignis. Hier brauchen wir nur den Namen ins PropertyBag hineinzuschieben...:

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  PropBag.WriteProperty "ImageList", mImageListName, "[keine]"
End Sub

...und auch wieder auszulesen:

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  mImageListName = PropBag.ReadProperty("ImageList", "[keine]")
End Sub

Das ist doch einfach, oder nicht? Klar. Nur, zur Container-Laufzeit können Sie bzw. Ihr UserControl mit dem Namen allein ja nicht viel anfangen. Also einfach den Namen sogleich an unsere raffinierte Let-Prozedur übergeben?

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  mImageListName = PropBag.ReadProperty("ImageList", "[keine]")
  If Ambient.UserMode Then
    Me.ImageList = mImageListName
  End If
End Sub

Sie werden pures Glück haben, wenn das funktioniert - rein zufällig funktioniert. Denn zu dem Zeitpunkt, zu dem das ReadProperties-Ereignis eintrifft, ist keineswegs sichergestellt, dass der übergeordnete Container das gewünschte Steuerelement dieses Namens bereits geladen hat und kennt. Es hängt einfach von der Ladereihenfolge ab, auf die Sie keinerlei Einfluss haben und nehmen können. Sie brauchen also eine Verzögerung, bis der Ladevorgang aller Steuerelemente im Container abgeschlossen ist, bevor das gesuchte Steuerelement sicher gefunden werden kann. Diese Verzögerung beschafft uns ein Timer mit einem extrem kurzen Intervall (= 1), der standardmäßig deaktiviert ist und nur zur Container-Laufzeit aktiviert wird:

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  mImageListName = PropBag.ReadProperty("ImageList", "[keine]")
  tmr.Enabled = Ambient.UserMode
End Sub

Private Sub tmr_Timer()
  tmr.Enabled = False
  Me.ImageList = mImageListName
End Sub

Im Timer-Ereignis wird der Timer sofort wieder deaktiviert - wir benötigen seinen Dienst ja nur ein einziges Mal. Erst hier und jetzt wird der aus dem PropertyBag ausgelesene Steuerelement-Name der Let-Prozedur zugewiesen. Dieses Timer-Ereignis wird erst ausgelöst, wenn die ganzen Initialisierungsvorgänge des Containers als auch der darauf befindlichen Steuerelemente erledigt sind - das heißt, dass das beispielsweise das Form_Load-Ereignis vollständig abgearbeitet ist. Bis dies jedoch der Fall ist, kann uns noch etwas anderes in die Quere kommen. Nämlich ein Aufruf der Get-Prozedur, also ein Auslesen der Eigenschaft im Form_Load-Ereignis - er würde Nothing zurück geben, da die Objekt-Variable für das Steuerelement noch nicht belegt worden ist. Natürlich könnten Sie eine solche Aktion per Hinweis in der Dokumentation verbieten. Aber erstens ist das nicht die feine Art, und zweitens bedarf es nur geringfügiger Modifikationen, auch diesen Stolperstein aus dem Weg zu räumen.

Auch wenn das Timer-Ereignis erst nach Abschluss des Form_Load-Ereignisses eintrifft, steht das gesuchte Steuerelement ja bereits während der ganzen Form_Load-Ereignisprozedur zur Verfügung. Wir haben nur deswegen den Timer als Hilfsmittel ausgesucht, weil es keine Möglichkeit gibt, mit vertretbarem Aufwand den Zeitpunkt zwischen vollständiger Initialisierung der Steuerelemente auf dem Form (bzw. im Container) und dem Beginn des Form_Load-Ereignisses zu bestimmen Zwar könnten Sie sich auf COM-Ebene in die Geschehnisse einklinken. Doch das ist mit Visual Basic-Bordmitteln erstens gar nicht möglich, und zweitens stünde der Aufwand in keinem Verhältnis mehr zum Effekt. Denn die Timer-Hilfe funktioniert zuverlässig, wenn das UserControl bzw. das kompilierte OCX in einem VB(A)-Projekt verwendet wird.

Die wesentlichste Modifikation betrifft die Get-Prozedur. Hier müssen wir sicherstellen, dass ein vorzeitiger Zugriff (ein Zugriff vor dem Auslösen des Timer-Ereignisses) trotzdem zum Aufruf der Let-Prozedur mit dem bereits aus dem PropertyBag ausgelesenen Steuerelement-Namen führt. Dazu benötigen wir eine weitere Hilfsvariable, mFirst, die im ReadProperties-Ereignis auf True gesetzt wird.

Private mFirst As Boolean

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  mImageListName = PropBag.ReadProperty("ImageList", "[keine]")
  mFirst = Ambient.UserMode
  tmr.Enabled = mFirst
End Sub

In der Get-Prozedur erfolgt zur Container-Laufzeit ausdrücklich dann erst einmal die Selbstzuweisung des Steuerelement-Namens an die Eigenschaft ImageList, so dass danach der korrekte Inhalt der Objekt-Variablen pImageList gewährleistet ist. Da ja auch tatsächlich kein Steuerelement gewählt worden sein kann, kann sie natürlich auch nach wie vor Nothing enthalten und zurückgeben.

Public Property Get ImageList() As Variant
  If Ambient.UserMode Then
    If mFirst And pImageList Is Nothing Then
      mFirst = False
      Me.ImageList = mImageListName
    End If
    Set ImageList = pImageList
  Else
    ImageList = mImageListName
  End If
End Property

Für den Fall, dass doch das Timer-Ereignis früher eintreten sollte, wird dort die Hilfsvariable mFirst auch zurückgesetzt, so dass sich die Get-Prozedur danach "völlig normal" verhält.

Private Sub tmr_Timer()
  tmr.Enabled = False
  If mFirst Then
    mFirst = False
    Me.ImageList = mImageListName
  End If
End Sub

Die Innereien des UserControls hätten wir damit nun komplett erledigt. Kommen wir nun noch einmal zur Eigenschaftenseite zurück. Dort hatten wir ja zuvor lediglich das Einlesen der Steuerelement-Namen in die Auswahl-ComboBox erledigt. Es fehlt noch die konkrete Zuweisung der Auswahl an die Eigenschaft des UserControls.

Zuvor schieben wir aber noch das nette Feature dazwischen, dass die ComboBox beim Öffnen der Eigenschaftenseite gleich den Namen des eventuell früher schon ausgewählten Steuerelements anzeigt.

Private mSelectedName As String

Private Sub PropertyPage_SelectionChanged()
  Dim nUC As ucWithImageList
  Dim nObj As Object
  Dim nName As String
  
  mSelectedName = ""
  Set nUC = SelectedControls(0)
  With cboImageLists
    .Clear
    .AddItem "[keine]"
    For Each nObj In nUC.FormControls
      If TypeOf nObj Is ImageList Then
        If nObj.Index > -1 Then
          nName = nObj.Name & "(" & nObj.Index & ")"
        Else
          nName = nObj.Name
        End If
        .AddItem nName
        If nName = nUC.ImageList Then
          mSelectedName = nName
        End If
      End If
    Next
  End With
  If mSelectedName = "" Then
    zComboFindText cboImageLists, "[keine]", , True, True
  Else
    zComboFindText cboImageLists, mSelectedName, , True, True
  End If
  Changed = False
  tmr.Enabled = True 
End Sub

Wir fügen hier einfach den Vergleich des in der Schleife jeweils gerade eingelesenen Namens mit dem noch aktuellen Wert der Eigenschaft im UserControl ein - ist dieser gerade an der Reihe, wird er in der Variablen mSelectedName festgehalten. Im Anschluss an die Schleife wird der Name, so denn einer gefunden wurde, in der ComboBox gesucht und der ListIndex entsprechend gesetzt. Wurde kein (gültiger) Name gefunden, wird die Default-Anzeige "[keine]" gewählt. Auf die Suche des Namens in der ComboBox gehe ich hier nicht weiter ein - eine Beschreibung der Hilfsfunktion zComboFindText finden Sie unter: "Wer suchet, der findet". (Wundern Sie sich bitte nicht über die Zeile "tmr.Enabled = True" - was es mit diesem Timer auf sich hat, werde ich später noch erklären.)

Da wir die Variable mSelectedName zur Aufnahme den gefundenen Namens nicht prozedurlokal deklariert haben, sondern modulweit für die Eigenschaftenseite, können wir ihn dazu verwenden, im Click-Ereignis der ComboBox nur dann das Changed-Flag der Eigenschaftenseite zu setzen, wenn ein anderer Name gewählt worden ist.

Private Sub cboImageLists_Click()
  Changed = Not (mSelectedName = cboImageLists.Text)
End Sub

Nun folgt noch eine allerletzte Kleinigkeit. Wenn wir schon mit dem Get/Let/Set-Dreigespann im UserControl dafür gesorgt haben, dass die Eigenschaft im Eigenschaftenfenster aufgelistet wird, könnten wir ja auch noch dafür sorgen, dass die Eigenschaftenseite auch separat zu der Eigenschaft über eine "..."-Schaltfläche neben der Eigenschaft geöffnet werden kann. Dazu ordnen Sie einfach die Eigenschaftenseite in den Prozedureigenschaften der Eigenschaft des UserControls zu.

Allerdings sorgt irgendeine Unstimmigkeit (wenn es nicht gar ein Bug ist) in der Verwaltung oder Implementierung der Eigenschaftenseiten in VB dafür, dass nach dem Betätigen der "Übernehmen"-Schaltfläche die Eigenschaftenseite die Verbindung zum UserControl verliert. Ein ausdrücklicher, interner Aufruf der Ereignisprozedur SelectionChanged nach der Zuweisung an das UserControl im ApplyChanges-Ereignis behebt offensichtlich und interessanterweise den Fehler.

Private Sub PropertyPage_ApplyChanges()
  SelectedControls(0).ImageList = cboImageLists.Text
  PropertyPage_SelectionChanged
End Sub

Damit jedoch die ComboBox sowohl nach diesem Wiederanzeigen als auch nach dem erstmaligen Anzeigen beim Öffnen der Eigenschaftenseite zuverlässig den Fokus bekommen kann, benötigen wir hier ebenfalls einen (bereits weiter oben erwähnten) Timer zur Verzögerung. Er wird zum Abschluss der SelectionChanged-Prozedur aktiviert und setzt den Fokus auf die ComboBox, sobald diese sichtbar zur Verfügung steht.

Private Sub tmr_Timer()
  tmr.Enabled = False
  On Error Resume Next
  cboImageLists.SetFocus
End Sub

Beispiel-Projekt WithImageList (ctlsonproppage.zip - ca. 7,1 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche




Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer