Eigenschaften von zur Laufzeit erstellten Objekten ändern

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Eigenschaften von zur Laufzeit erstellten Objekten ändern

    Hallo zusammen,

    ich habe folgendes Problem:

    In meinem kleinen Lernprojekt erstelle ich gerade zur Laufzeit mehrere Objekte:

    VB.NET-Quellcode

    1. Dim nud_menge As New NumericUpDown
    2. Dim bt_add As New Button
    3. With nud_menge
    4. .Location = New Point(395, y)
    5. .Width = 50
    6. .Name = "nud_menge_" & i
    7. .Visible = True
    8. .Enabled = True
    9. .Value = 1
    10. .Parent = Me
    11. End With
    12. With bt_add
    13. .Location = New Point(455, y)
    14. .Width = 50
    15. .Name = "bt_add_" & i
    16. .Visible = True.Enabled = True
    17. .Text = "Fertig"
    18. .Parent = MeAddHandler bt_add
    19. .Click, AddressOf bt_add_Click
    20. End With
    21. i = i + 1
    22. y = y + 26



    Bei klick auf den Button soll die Eigenschaft Enabled bei dem Button UND dem NumericUpDown auf FALSE gesetzt werden.

    Beim Button klappt das ganz gut hiermit:

    VB.NET-Quellcode

    1. Private Sub bt_add_Click(ByVal sender As Object, ByVal e As EventArgs)
    2. Dim Btn As Button = DirectCast(sender, Button)
    3. Btn.Enabled = False
    4. End Sub




    Aber wie schaffe ich es, dass beim Klick auf den Button auch Eigenschaften des NumericUpDown geändert werden können?

    Vielen dank schonmal für eure Hilfe!
    Willkommen im Forum. :thumbup:
    Die Controls müssen in die Klasse verschoben werden.

    VB.NET-Quellcode

    1. Private nud_menge As New NumericUpDown
    2. Private bt_add As New Button
    3. Private Sub Bla()
    4. ' Dein Code
    5. End Sub
    6. Private Sub bt_add_Click(ByVal sender As Object, ByVal e As EventArgs)
    7. bt_add.Enabled = False
    8. nud_menge.Value = 20
    9. End Sub
    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!
    Hallo Rod,

    danke für die Begrüßung und die schnelle Hilfe!

    Das Verschieben der Controls in die Klasse hat funktioniert!

    Allerdings tritt jetzt folgender Effekt auf:

    Wenn neue Controls erstellt werden (DataGridView1_CellDoubleClick), verschwinden die bereits erstellten auf der Form.
    Die MsgBox in Private Sub bt_add_Click hingegen "meldet" alle bisher erstellen Buttons.


    VB.NET-Quellcode

    1. Private Sub DataGridView1_CellDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    2. With nud_menge
    3. .Location = New Point(15 + 70 + 260 + 50, y)
    4. .Width = 50
    5. .Name = "nud_menge_" & i
    6. .Visible = True
    7. .Enabled = True
    8. .Value = 1
    9. .Parent = Me
    10. End With
    11. With bt_add
    12. .Location = New Point(15 + 70 + 260 + 50 + 60, y)
    13. .Width = 50
    14. .Name = "bt_add_" & i
    15. .Visible = True
    16. .Enabled = True
    17. .Text = "Fertig"
    18. .Parent = Me
    19. AddHandler bt_add.Click, AddressOf bt_add_Click
    20. End With
    21. i = i + 1
    22. y = y + 26
    23. End Sub
    24. Private Sub bt_add_Click(ByVal sender As Object, ByVal e As EventArgs)
    25. Dim Btn As Button = DirectCast(sender, Button)
    26. Btn.Enabled = False
    27. nud_menge.Enabled = False
    28. MsgBox _
    29. ("Es wurde auf '" & Btn.Name & "' geklickt.", _
    30. MsgBoxStyle.Information)
    31. End Sub
    Das ist ein neuer Sachverhalt, der in Deinem Eröffnungspost nicht dargestellt wurde.
    Klar, wenn Du ein neues Control erstellst und es der Klassenvariable zuweist, wird das alte zerstört, das macht .NET.
    Überleg Dir nun, was Du genau willst, alles, vollständig und möglichst präzise, poste das, dann werden wir sehen.
    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!
    Sorry, manchmal ist man einfach zu vorschnell :S

    Also, hier der "Plan":

    Im DataGridView1 befinden sich Artikeldaten.
    Bei Doppelklick auf eine Zeile werden unter dem DataGridView dynamisch zur Laufzeit eine TextBox, ein NumericUpDown und ein Button generiert:

    VB.NET-Quellcode

    1. Public Class Neue_Bestellung
    2. Dim y As Integer = 343
    3. Dim i As Integer
    4. Dim tb_artnr As New TextBox
    5. Dim nud_menge As New NumericUpDown
    6. Dim bt_add As New Button
    7. Private Sub DataGridView1_CellDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    8. With tb_artnr
    9. .Location = New Point(15, y)
    10. .Width = 60
    11. .Name = "tb_artnr_" & i
    12. .Visible = True
    13. .Enabled = False
    14. .Text = DataGridView1.CurrentRow.Cells(1).Value
    15. .Parent = Me
    16. End With
    17. With nud_menge
    18. .Location = New Point(15 + 70 + 260 + 50, y)
    19. .Width = 50
    20. .Name = "nud_menge_" & i
    21. .Visible = True
    22. .Enabled = True
    23. .Value = 1
    24. .Parent = Me
    25. End With
    26. With bt_add
    27. .Location = New Point(15 + 70 + 260 + 50 + 60, y)
    28. .Width = 50
    29. .Name = "bt_add_" & i
    30. .Visible = True
    31. .Enabled = True
    32. .Text = "Fertig"
    33. .Parent = Me
    34. AddHandler bt_add.Click, AddressOf bt_add_Click
    35. End With
    36. i = i + 1
    37. y = y + 26
    38. End Sub
    39. Private Sub bt_add_Click(ByVal sender As Object, ByVal e As EventArgs)
    40. Dim Btn As Button = DirectCast(sender, Button)
    41. Btn.Enabled = False
    42. nud_menge.Enabled = False
    43. MsgBox _
    44. ("Es wurde auf '" & Btn.Name & "' geklickt.", _
    45. MsgBoxStyle.Information)
    46. End Sub
    47. End Class


    Jetzt soll der Benutzer eine Bestellmenge mit dem NumericUpDown eingeben können.

    Nach Klick auf den Button sollen alle Controls, die bei DataGridView1_CellDoubleClick generiert wurden auf Enabled=False gesetzt werden.
    Außerdem soll der Wert des NumericUpDown verfügbar sein um ihn z.B. in ListBox1 einzufügen.

    Bei einem weiteren DataGridView1_CellDoubleClick soll das Ganze dann wieder von vorne losgehen.
    Das würde ich doch lieber in einen Dialog packen, den Du bei einem Doppelklick aufrufst:

    VB.NET-Quellcode

    1. Using dlg As New Form2
    2. 'dlg.XXX = xxx ' Eigenschaften setzen
    3. 'dlg.YYY = yyy
    4. dlg.Show(Me)
    5. 'xxx = dlg.XXX ' geänderte Werte zurückholen
    6. 'yyy = dlg.YYY
    7. End Using
    Form2 ist dann der Dialog, der die entsprechenden Controls enthält.
    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!
    Oder, wenn du keinen Dialog möchtest, dann nicht deine Control-Variable überschreiben, sondern eine weitere anlegen, oder eine List(Of IControl) (wenn es sowas gibt, das Interface mein ich), wenn es das gibt, kannst du da die einzelnen Controls reinschaufeln.

    Aber warum zur Laufzeit erzeugen? Mache sie doch als Unvisible Member der Form, also per Designer, und wenn sie gebraucht werden, dann Sichtbar machen. Warum nicht so?
    @RodFromGermany:
    Kannst du mir hier nähere Info's oder ein etwas ausführlicheres Beispiel zu geben?

    @Kagurame:
    Das ist mir (noch) zu komplex...
    Ich nutze das Projekt um Grundlagen zu lernen. Den Ansatz mit den "Unvisible"-Controls hatte ich auch schon im Kopf, hab ihn aber verworfen, weil ich das Ganze möglichst flexibel lassen wollte (Es wäre zu überdenken, ob ein solches Maß an Flexibilität überhaupt Sinn macht :S )
    Füge Deinem Projekt eine Form2 hinzu, schreibe da rein, mach Du brauchst: Button, NumericUpDown, ...
    und gib ihr die erforderlichen Properties, z.B.

    VB.NET-Quellcode

    1. Public Property xxx() As Decimal
    2. Get
    3. Return nud_menge.Value
    4. End Get
    5. Set(ByVal value As Decimal)
    6. nud_menge.Value = value
    7. End Set
    8. End Property
    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!
    OK, vielen Dank.

    Allerdings verstehe ich nicht recht, wofür ich dann noch die Property benötige.

    Die Werte aus den Controls kann ich mir doch dann auch einfach so zurückholen:

    VB.NET-Quellcode

    1. Private Sub DataGridView1_CellDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    2. Using dlg As New frm_bestellmenge
    3. dlg.TextBox1.Text = DataGridView1.CurrentRow.Cells(1).Value ' Eigenschaften setzen
    4. dlg.TextBox2.Text = DataGridView1.CurrentRow.Cells(4).Value
    5. dlg.TextBox3.Text = DataGridView1.CurrentRow.Cells(5).Value
    6. dlg.ShowDialog(Me)
    7. TextBox1.Text = dlg.nud_menge.Value ' geänderte Werte zurückholen
    8. End Using
    9. End Sub


    VB.NET-Quellcode

    1. Public Class frm_bestellmenge
    2. ' Public Property xxx() As Decimal
    3. ' Get
    4. ' Return nud_menge.Value
    5. ' End Get
    6. ' Set(ByVal value As Decimal)
    7. ' nud_menge.Value = value
    8. ' End Set
    9. 'End Property
    10. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    11. Me.Close()
    12. End Sub
    13. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    14. Neue_Bestellung.ListBox1.Items.Add(TextBox1.Text & ", " & TextBox2.Text & ", " & TextBox3.Text & ", " & nud_menge.Value)
    15. Me.Close()
    16. End Sub
    17. End Class
    Natürlich funktioniert es auch so.

    Jedoch sind deine textBoxen GUI, keine Logik. Du verwendest sie hier als Logik.

    Diese beiden Punkte sollte man immer getrennt halten, weil wenn jetzt mal der eine Wert generiert wird muss du die Abhängigkeit der TextBoxen lösen, mit einer Property nur die TextBox.

    Die eine GUI hat mit der anderen nichts zu tun, sie tauschen sich über Properties aus, nicht über GUI-Elemente.

    (Reine Design- und Wartbarkeits-Frage)
    Nun gut,

    ich werde mich dann also als nächstes mit Propertys auseinandersetzen. Es erscheint mir sinnvoll, gewisse "Standards" einzuhalten.

    Ich denke das eigentlich Thema ist erledigt.

    Vielen Dank an euch Zwei und bis zur nächsten Frage!
    /sign

    Auch nach meiner Erfahrung ist dynamisches Erstellen von Controls ausnahmslos Crap.
    Einzige Ausnahme: U.U. stellts eine Resourcen-Optimierung dar, wenn man komplexe UserControls erst zur Laufzeit erstellt. UserControls sind aber auch total einfach zu handeln, weil man jeweils nur ein einziges braucht: die komplexen Beziehungen der Unter-Controls sind ja bereits im Designer des UserControls strukturiert.

    Wie Kagurame sagt: Der Holzweg "dynamische Control-Erzeugung" wird üblicherweise beschritten, weil man denkerisch nicht zw. Oberfläche und Daten differenziert.