none
SteuerElement (zb.Button) zur Laufzeit erstellen und auch ansprechen mit WithEvents. Warum geht das nicht ???? RRS feed

  • Frage

  • Hallo ihrs
    Ich beschäftige mich gerade damit, Steuerelemente zur Laufzeit erstellen und möchte diese auch gerne ansprechen. Ich weiß mittlereweile das ich die erstellten Steuerelemente mit zb. "AddHandler.Click,AdressOf ......." ansprechen kann. Nun habe ich aber in einem Vb6 Beispielgesehen das das ganze auch mit  WithEvents ansprechen kann, und dachte mir das muss doch auch in VB8 gehen. und habe folgendes probiert.
    Public Class Form1
    
        Private WithEvents MeinButton As Button
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
            Dim MeinButton As New Button
    
            With MeinButton
    
                .Text = " OK "
    
                .BringToFront()
    
                .Left = 100
    
                .Top = 100
    
                Me.Controls.Add(MeinButton)
    
            End With
    
        End Sub
    
    
    
        Private Sub MeinButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MeinButton.Click
    
            MsgBox("Der Button wurde geklickt")
    
        End Sub
    
    End Class
    
    
    Wenn ihr diesen Code in der Codansicht einfügt dürfte kein Fehler zu sehen sein, Beim Debugging kommt auch der gewünschte Button. In der Codansicht oben links wo Form1 bzw Allgemein  usw steht, kann ich auch auf  "Mein Button" zugreifen und links auch alle Eigenschaften zuweisen. (in meinem CodeBeispiel das Click_event)  Allerdings ist links, also bei "MeinButton" ein Schloss bzw Gesperrtzeichen davor und genau das ist das was ich nicht verstehe bzw beim Debugging nix passiert wenn ich den Button klicke. Eigentlich sollte ja sich die MsgBox melden.

    Sicherlich habe ich nur einen Denkfehler oder sollte das mit WithEvents unter VB8  wirklich nicht gehen.
    Kann mir das mal Jemand erklären bzw Zeigen wie es Richtig sein sollte???

    Lg Wild-Life78
    Sonntag, 1. November 2009 17:15

Antworten

  • Um auf einen bestimmten selbst erstellten Button zuzugreifen, kannst Du diesen bspw. einen Namen geben:

    Dim lButton As New Button()
    lButton.Name = "DynamicButton1"
    
    '...
    Me.Controls.Add(lButton)
    
    

    Später kannst Du dann über diesen Namen die Controlreferenz in der Controls-Auflistung ausfindig machen:

    Debug.Print(DirectCast(Me.Controls("DynamicButton1"), Button).Text)

    Es kann aber auch sinnvoll sein, eine eigene Auflistung aller zusammengehörenden Buttons bzw. dynamischen Controls zu verwalten:

    Private m_MyButtons As New List(Of Button)
    
    Private Sub Form_Load ...
       Dim lButton = New Button()
    
        lButton .Text = "My Button 1"
        lButton .Name = "MyButton1"
        lButton .Visible = True
    
        Me.Controls.Add(lButton)
        m_MyButtons.Add(lButton)
    End If
    
    ' ...
    Debug.Print(m_MyButtons(0).Text)


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    • Als Antwort markiert Wild-Life78 Dienstag, 3. November 2009 18:46
    Dienstag, 3. November 2009 18:16
    Moderator
  • Lass die erneute Deklaration von

        Dim MeinButton As New Button
    

    innerhalb von Form_Load weg. Damit weist Du die Referenz auf Deinen Button einer privaten Variable zu. Die Klassenvariable "MeinButton" bekommt davon nichts mit, somit empfängt sie auch keine Ereignisse Deines Button.

    Scope in Visual Basic
    http://msdn.microsoft.com/en-us/library/1t0wsc67.aspx

    Wenn Du wirklich dynamisch werden möchtest, stößt Du mit WithEvents schnell an die Grenzen. Über AddHandler kannst Du Ereignisse völlig dynamisch auf eigene Methoden aufsetzen, ohne zur Designzeit wissen zu müssen, wie viele Instanzen Du später einmal haben wirst:

    AddHandler Statement
    http://msdn.microsoft.com/en-us/library/7taxzxka.aspx


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Sonntag, 1. November 2009 17:32
    Moderator
  • Hallo Ronny,

    das hat nichts mit innerhalb oder außerhalb der Klasse zu tun, sondern rein mit Dynamik. Wenn Du zur Entwicklungszeit sagst:

    Private WithEvents MyButton As Button

    Kannst Du zur Laufzeit immer nur exakt eine Button Instanz über diese Variable "MyButton" referenzieren:

    Private Sub Form1_Load(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) Handles MyBase.Load
    
       MyButton = New Button()
    
       With MyButton
         .Text = " OK "
         .Left = 100
         .Top = 100
       End With
    
       Me.Controls.Add(MyButton)
    End Sub
    
    Private Sub MyButton_Click(ByVal sender As Object, _
                               ByVal e As System.EventArgs) Handles MeinButton.Click
    
       MsgBox("Der Button wurde geklickt")
    End Sub
    

    Jetzt stellst Du aber fest, dass Du zur Entwicklungszeit gar nicht wissen kannst, wie viele Buttons Du tatsächlich benötigst. Mal reicht einer, mal brauchst du 2, 3 oder sogar 5. Dann bist Du mit WithEvents am Ende, wenn Du nicht auf Verdacht 5 WithEvent Variablen deklarieren möchtest. Hier verwendest Du dann AddHandler. Zunächst brauchst Du weiterhin eine Methode, die als Ereignisempfänger fungiert:

    Private Sub AnyButton_Click(ByVal sender As Object, _
                                ByVal e As System.EventArgs)
       Dim lText As String = DirectCast(sender, Button).Text
    
       MsgBox(String.Format("Der Button '{0}' wurde geklickt", lText))
    End Sub
    


    Wie Du siehst, ist hier die Handles Anweisung nicht mehr notwendig.

    Private Sub Form1_Load(ByVal sender As System.Object, _
                           ByVal e As System.EventArgs) Handles MyBase.Load
    
      For i As Integer = 0 To 4
         Dim lButton = New Button()
    
         With lButton
           .Text = String.Format("Button {0}", i + 1)
           .Left = 100
           .Top = 100  + (25 * i)
         End With      
    
        AddHandler lButton.Click, AddressOf AnyButton_Click
    
        Me.Controls.Add(lButton)
      Next
    End Sub


    Hoffe das Beispiel veranschaulicht den Unterschied etwas besser. Wenn Du noch Fragen hast, scheue nicht sie zu stellen.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Montag, 2. November 2009 18:50
    Moderator

Alle Antworten

  • Lass die erneute Deklaration von

        Dim MeinButton As New Button
    

    innerhalb von Form_Load weg. Damit weist Du die Referenz auf Deinen Button einer privaten Variable zu. Die Klassenvariable "MeinButton" bekommt davon nichts mit, somit empfängt sie auch keine Ereignisse Deines Button.

    Scope in Visual Basic
    http://msdn.microsoft.com/en-us/library/1t0wsc67.aspx

    Wenn Du wirklich dynamisch werden möchtest, stößt Du mit WithEvents schnell an die Grenzen. Über AddHandler kannst Du Ereignisse völlig dynamisch auf eigene Methoden aufsetzen, ohne zur Designzeit wissen zu müssen, wie viele Instanzen Du später einmal haben wirst:

    AddHandler Statement
    http://msdn.microsoft.com/en-us/library/7taxzxka.aspx


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Sonntag, 1. November 2009 17:32
    Moderator
  • Na das ist doch mal eine Ansage (-:

    Dann war ja das "AddHandler" garnicht so falsch, aber ich denke mal, das es nicht schadet beide Varianten zu kennen.


    Vielen Dank


    Lg Wild-Life78
    Sonntag, 1. November 2009 18:41
  • Nein, schaden kann das sicher nicht, wenn man beide Varianten kennt.

    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Sonntag, 1. November 2009 21:10
    Moderator
  • Hallo, Nun war ich etwas zu voreillig,
     also AddHandler ist die bessere Version, innerhalb der Klasse komme ich auch gut damit klar, aber wenn ich Dich richtig verstanden habe meinst Du mit dynamisch ausserhalb der Klasse? Das verstehe ich nicht ganz bzw bekomme es nicht hin. Ist Dir oder Jemanden der es weiß möglich, mal ein kleines Beisspiel zu zeigen, bzw mein Beispiel so  umzubauen, damit ich etwas besser verstehe wie Du das meinst???




    Ps selbstverständlich war Deine Antwort sicherlich richtig, aber ich habe es glaube noch nicht so ganz verstanden, ich werde Deinen Beitrag auch wieder als Antwort markieren, habe die Antwort nur zurück gezogen damit der Beitrag nochmal gelesen wird.


    Gruß Ronny
    Montag, 2. November 2009 14:42
  • Hallo Ronny,

    das hat nichts mit innerhalb oder außerhalb der Klasse zu tun, sondern rein mit Dynamik. Wenn Du zur Entwicklungszeit sagst:

    Private WithEvents MyButton As Button

    Kannst Du zur Laufzeit immer nur exakt eine Button Instanz über diese Variable "MyButton" referenzieren:

    Private Sub Form1_Load(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) Handles MyBase.Load
    
       MyButton = New Button()
    
       With MyButton
         .Text = " OK "
         .Left = 100
         .Top = 100
       End With
    
       Me.Controls.Add(MyButton)
    End Sub
    
    Private Sub MyButton_Click(ByVal sender As Object, _
                               ByVal e As System.EventArgs) Handles MeinButton.Click
    
       MsgBox("Der Button wurde geklickt")
    End Sub
    

    Jetzt stellst Du aber fest, dass Du zur Entwicklungszeit gar nicht wissen kannst, wie viele Buttons Du tatsächlich benötigst. Mal reicht einer, mal brauchst du 2, 3 oder sogar 5. Dann bist Du mit WithEvents am Ende, wenn Du nicht auf Verdacht 5 WithEvent Variablen deklarieren möchtest. Hier verwendest Du dann AddHandler. Zunächst brauchst Du weiterhin eine Methode, die als Ereignisempfänger fungiert:

    Private Sub AnyButton_Click(ByVal sender As Object, _
                                ByVal e As System.EventArgs)
       Dim lText As String = DirectCast(sender, Button).Text
    
       MsgBox(String.Format("Der Button '{0}' wurde geklickt", lText))
    End Sub
    


    Wie Du siehst, ist hier die Handles Anweisung nicht mehr notwendig.

    Private Sub Form1_Load(ByVal sender As System.Object, _
                           ByVal e As System.EventArgs) Handles MyBase.Load
    
      For i As Integer = 0 To 4
         Dim lButton = New Button()
    
         With lButton
           .Text = String.Format("Button {0}", i + 1)
           .Left = 100
           .Top = 100  + (25 * i)
         End With      
    
        AddHandler lButton.Click, AddressOf AnyButton_Click
    
        Me.Controls.Add(lButton)
      Next
    End Sub


    Hoffe das Beispiel veranschaulicht den Unterschied etwas besser. Wenn Du noch Fragen hast, scheue nicht sie zu stellen.


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Montag, 2. November 2009 18:50
    Moderator
  • Ja, das Beispiel ist gut und vorallem verständlich, ich wünschte solche Beispiele wären in Msdn Liybary zu finden, denn mal ganz ehrlich, manche Sachen dort, werden unwarscheinlich kompliziert dargestellt und erklärt, obwol sie eigentlich ganz einfach sind.

    Was die weiteren Fragen betrifft, da kommen bestimmt noch welche, aber dieses Problem hier, ist jetzt erstmal keins mehr. (-:
    obwohl vieleicht kannst mir noch sagen wie ich jetzt, zb nur Button3 von den 5 Button anspreche ?

    Vielen Dank


    Gruß Ronny
    Dienstag, 3. November 2009 14:43
  • Um auf einen bestimmten selbst erstellten Button zuzugreifen, kannst Du diesen bspw. einen Namen geben:

    Dim lButton As New Button()
    lButton.Name = "DynamicButton1"
    
    '...
    Me.Controls.Add(lButton)
    
    

    Später kannst Du dann über diesen Namen die Controlreferenz in der Controls-Auflistung ausfindig machen:

    Debug.Print(DirectCast(Me.Controls("DynamicButton1"), Button).Text)

    Es kann aber auch sinnvoll sein, eine eigene Auflistung aller zusammengehörenden Buttons bzw. dynamischen Controls zu verwalten:

    Private m_MyButtons As New List(Of Button)
    
    Private Sub Form_Load ...
       Dim lButton = New Button()
    
        lButton .Text = "My Button 1"
        lButton .Name = "MyButton1"
        lButton .Visible = True
    
        Me.Controls.Add(lButton)
        m_MyButtons.Add(lButton)
    End If
    
    ' ...
    Debug.Print(m_MyButtons(0).Text)


    Thorsten Dörfler
    Microsoft MVP Visual Basic
    • Als Antwort markiert Wild-Life78 Dienstag, 3. November 2009 18:46
    Dienstag, 3. November 2009 18:16
    Moderator
  • Danke dieser Code ist  wirklich gut.
    Das man dynamisch programmieren soll, weiß Ich ja, aber das es so dynamisch geht, habe ich noch nicht gesehen.

    vielen Dank

    Gruß Ronny
    Dienstag, 3. November 2009 18:44