Steuerelement zur Laufzeit erzeugen und managen

  • .NET (FX) 4.5–4.8
  • VB.NET

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Steuerelement zur Laufzeit erzeugen und managen

    Hallo zusammen,

    ich möchte in Visual Basic 2022 nicht über 60 Mal das gleiche Control »PictureBox« im Designer erstellen und mit der Maus »zurecht zittern«. Daher habe ich mich entschieden, das benötigte Steuerelement »PictureBox« mehrmals zur Laufzeit in einer Form zu erzeugen. Das funktioniert soweit auch super. Alle Controls werden der Form hinzugefügt, dort angezeigt, sind mit der Maus ansprechbar und funktioneren sozusagen tadelos. Allerdings hat jedes Control einen eigenen Namen!
    Das Problem liegt nun beim Aktualisieren dieser Steuerelemente: Ich möchte das Bild (Eigenschaft ».image«) bei einem Teil der Steuerelemente auch zur Laufzeit ändern. Während ich früher Mal Steuerelemente problemlos mit

    Me.Controls.Item(<ObjektName>).Image = <Resources>

    ändern konnte, meckert die IDE im Code mit den Worten, Image wäre kein Member von Control und schlägt mir die o. g. Eigenschaft auch nicht vor. Was habe ich vergessen?

    Verschoben. ~Thunderbolt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thunderbolt“ ()

    Willkommen im Forum. Nutze einen Array oder ein Dictionary(of String, PictureBox). Soll das mit Strings anstatt Zahlen für einen Index im Array sein, ist das Dictionary zu bevorzugen.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private PictureBoxes As New Dictionary(Of String, PictureBox)
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Dim pb As New PictureBox
    5. pb.Location = New Point(100, 100)
    6. pb.BackColor = Color.Green
    7. Controls.Add(pb)
    8. PictureBoxes.Add("PB1", pb)
    9. End Sub
    10. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    11. Dim pb As New PictureBox
    12. If PictureBoxes.TryGetValue("PB1", pb) Then
    13. pb.BackColor = Color.Red
    14. End If
    15. End Sub
    16. End Class

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    sw032024 schrieb:

    Allerdings hat jedes Control einen eigenen Namen!
    Das ist nur im Designer einigermassen verlässlich.
    Wenn du zur Laufzeit Controls erstellst, bekommen sie den Namen, den du ihnen zur Laufzeit gibst. Du kannst ihnen allen denselben Namen geben, oder die .Name-Property auch leer lassen.

    sw032024 schrieb:

    Das Problem liegt nun beim Aktualisieren dieser Steuerelemente...
    Na, da werden noch mehr Probleme kommen.
    Wer mit 60 Picboxen hantiert, verwendet offsichtlich Controls als Daten-Objekte - wofür sie sich nur sehr schlecht eignen.
    Daten will man zufügen, löschen, zugreifen, ändern, oft auch filtern und sortieren.
    Wenn man mit Datenobjekten arbeitet, gibts dafür zuverlässige Standard-Operationen.
    Wenn man das mit missbrauchten Controls alles selber hinbasteln will - so nach und nach - findet man sich schnell in Teufels Küche wieder.

    ByTheWay: hast du wirklich in deinen Resourcen 60 Images, um dein Picboxes damit zu füttern?
    Erst mal Danke für eure Tipps. Ihr seid ja schnell. Ich habe mich am Beispiel von DTF orientiert und sehe bei »Dictionary« oder Arrays keinen nennenswerten Vorteil – auch wenn es in der Programmierung nicht »konventionell« sein sollte. Abgesehen von der Verwendung

    Dictionary(Of String, PictureBox) => PictureBoxes.Add("PB1", pb)

    ist mein ursprünglicher Ansatz auch nicht anders: 60 x neue PictureBox (mit eigenem Namen) erzeugen, gewünschte Eigenschaften setzen und

    Me.Controls.Add(<diese PictureBox>)

    Dazu noch zwei AddHandler, für MouseMove und Click. Also 60 Controls werden an diese beiden AddHandler verwiesen. Läuft.

    Allerdings ist das Problem der Aktualisierung dieser erzeugten Controls (aus einer anderen Prozedur in derselben Klasse) damit nicht behoben. Ich kann auch nicht auf das Array »Dictionary« zugreifen – .image ist auch kein Member von »Dictionary« oder der Form.
    Einerseits gibt es die »PictureBox« ja tatsächlich noch nicht im Entwurf. Andererseits frage ich mich, wieso es möglich ist Controls zur Laufzeit zu erzeugen, wenn ich im Code Methoden und Eigenschaften der noch zu erzeugenen Controls nicht anwenden und anpassen kann. Ich kann das Programm dann einfach nicht mehr starten und muss diese problematische Zeile als Kommentar stehen lassen.

    @ErfinderDesRades:
    Ich möchte bei einem Teil dieser PictureBox(en) die images austauschen. In My.Resources sind dafür 13 kleine Images (56 x 56 px), die ich bei Bedarf anwenden möchte. Nix Wildes, keine fette Datenbank oder sowas. Ganz harmlos.

    Im Internet finde ich überall in sämtlichen Versionen von MS Visual Basic, wie übliche Windows-Controls massenweise zur Laufzeit in einer Form erzeugt werden können und welch' unbegrenzte Möglichkeiten es doch gibt. Aber zum Thema ändern der Eigenschaften dieser erzeugten Controls schreibt niemand etwas. Geht wohl nicht und soll ein Geheimnis bleiben. ;)

    Muss ich vielleicht mit einem »Referenz-Control« in der Form arbeiten und die zur Laufzeit duplizieren, um im Code das obige Problem zu vermeiden? Ich meine mich ganz dunkel aus VB6-Zeiten an so etwas in der Art erinnern zu können ...



    Ich habe zum Aktualisieren nun eine andere Methode geschrieben, die etwas hoffnungsvoller sein könnte:

    VB.NET-Quellcode

    1. Dim nr As Integer
    2. Dim ObjektName, StrCache As String
    3. Debug.WriteLine(vbCrLf & "Reload_Form()")
    4. For Each Element As Control In Me.Controls
    5. Debug.Print(vbTab & "Element: " & Element.Name & " Text: " & Element.Text)
    6. If TypeOf Element Is PictureBox Then
    7. ObjektName = Element.Name
    8. If Strings.Len(ObjektName) > 12 Then
    9. If Strings.Left(ObjektName, 12) = "Mein Objekt_" Then
    10. Debug.Print(vbTab & vbTab & "Mein Objekt gefunden ...")
    11. StrCache = Strings.Replace(Element.Name, "Mein Objekt_", "")
    12. If StrCache <> "" Then
    13. nr = CInt(StrCache)
    14. Debug.Print(vbTab & vbTab & vbTab & "Mein Objekt-Nummer: " & nr)
    15. If MyArray(nr) = 1 Then
    16. Element.Image = My.Resources.Bild
    17. Else
    18. Element.Image = Nothing
    19. End If
    20. End If
    21. End If
    22. End If
    23. Else
    24. Debug.Print(vbTab & vbTab & "Ein anderes Objekt.")
    25. End If
    26. Next


    Das ist doch mal für meinen Zweck optimal, oder? Jemand aus dem Forum hat mich auf diese Idee gebracht. Aber: .Image ist halt immer noch kein Member der Form.

    Alles klar Microsoft: Ich sollte auf Assembler umsteigen.

    Beiträge zusammengefügt. ~Thunderbolt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thunderbolt“ ()

    sw032024 schrieb:

    Alles klar Microsoft: Ich sollte auf Assembler umsteigen.


    Ohhhh, da nimmste dir aber was vor :D . Kannste denn in C/C++ bereits via API Fenster, Buttons usw. erzeugen, auf Klicks usw. reagieren? Wenn nicht fang erstmal damit an. ;)


    Aber Falls du ein Grid hast, also X mal X Pictureboxen, könnte ein Mehr-Dimensionaler Array nützlich sein. Kannste dann wie mit koordinaten aus dem Array holen und die PictureBox nutzen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    Ich habe die Vermutung dein Hauptproblem ist, dass du den Unterschied zwischen Control, Form und Picturebox nicht kennst. Weder Form noch Control haben eine Eigenschaft Image. Daher kannst du auch nicht auf die Eigenschaft zugreifen. Stichwort Casten:

    VB.NET-Quellcode

    1. For Each pb As PictureBox In Controls.OfType(Of PictureBox)()
    2. pb.Image = Nothing
    3. Next
    4. For Each ctrl As Control In Controls
    5. If TypeOf ctrl Is PictureBox Then
    6. Dim pb As PictureBox = CType(ctrl, PictureBox)
    7. pb.Image = Nothing
    8. End If
    9. Next
    @sw032024 Willkommen im Forum.
    Vielleicht erläuterst Du mal kurz, was Du eigentlich vor hast.
    Vielleicht finden sich noch elegantere Lösungsansätze.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!