none
DataBinding an Array in Windows Forms unter Visual Basic 2013 RRS feed

  • Frage

  • Guten Morgen alle miteinander,

    ich erstelle mit VB.NET unter Visual Studio 2013 ein Formular, das in einer Groupbox eine variable Anzahl von Checkboxen enthält, deren Inhalt ich an ein Boolean-Array binden möchte.

    Die Datenbindung stelle ich mir in folgender Form vor:

    MyGroupBox.Controls("MyCheckbox0").DataBindings.Add(New Binding("Checked", Me, "MyBooleanArray(0)"))

    wobei die 0 im Namen "MyCheckbox0" und im Adressierungsausdruck  "MyBooleanArray(0)" mit der tatsächlichen Checkbox von 0 bis Anzahl der Checkboxen -1 variiert. Ich hoffe, mich einigermaßen verständlich ausgedrückt zu haben.

    Die Zuweisung mit "MyBooleanArray(0)" klappt so natürlich nicht.

    Kann mir jemand helfen, wie der DataBindings-Ausdruck richtig erstellt werden muss? Ganz sicher gibt es auch eine elegantere Möglichkeit. Wichtig für mich ist lediglich, dass ich nach dem Schließen des Formulars ein Abbild der angeklickten Checkboxen in einem Array oder einer Liste oder wo auch immer haben werde, die ich mit einem Index von 0 bis Anzahl der Checkboxen -1 auslesen kann.

    Gruß, Werner


    WM

    Montag, 15. Januar 2018 06:24

Antworten

  • Hi Werner,
    eine Datenquelle an die GroupBox zu binden und zu erwarten, dass dann eine passende Anzahl Steuerelemente innerhalb der GroupBox generiert wird, ist falsch. Auf Basis des Arrays musst Du die CheckBoxes incl. Bindung und Position erzeugen und der GrupBox zuweisen.

    Public Class Form30
      Private gb As New GroupBox With {.Dock = DockStyle.Fill, .Text = "GroupBox mit ChexBoxes"}
      Private rnd As New Random
      Private Sub Form30_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' GropBox anzeigen
        Me.Controls.Add(gb)
        ' Daten laden
        For i = 0 To Me._arr.GetUpperBound(0)
          Arr(i) = rnd.NextDouble < 0.5
        Next
        ' GroupBox füllen ind jede CheckBos binden
        For i = 0 To Me._arr.GetUpperBound(0)
          Dim cb As New CheckBox With {.Text = $"Box {i + 1}", .Top = i * 20}
          cb.DataBindings.Add("Checked", Arr(i), "")
          gb.Controls.Add(cb)
        Next
      End Sub
    
      Private _arr(9) As Boolean ' Boolean-Array
      Friend Property Arr(index As Integer) As Boolean
        Get
          Return Me._arr(index)
        End Get
        Set(value As Boolean)
          Me._arr(index) = value
        End Set
      End Property
    End Class


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks


    Montag, 15. Januar 2018 09:19
  • Hi Werner,
    wenn Du mit dem Designer eine Datenquelle zuweisen willst, dann muss diese auch als instanziierbare Komponente bereitstehen. Meist ist das aber nicht notwendig, da eine Zuweisung zur Ausführungszeit völlig ausreichend sein kann.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    • Als Antwort markiert WerMil Dienstag, 30. Januar 2018 09:05
    Montag, 15. Januar 2018 15:34

Alle Antworten

  • Hi Werner,
    eine Datenquelle an die GroupBox zu binden und zu erwarten, dass dann eine passende Anzahl Steuerelemente innerhalb der GroupBox generiert wird, ist falsch. Auf Basis des Arrays musst Du die CheckBoxes incl. Bindung und Position erzeugen und der GrupBox zuweisen.

    Public Class Form30
      Private gb As New GroupBox With {.Dock = DockStyle.Fill, .Text = "GroupBox mit ChexBoxes"}
      Private rnd As New Random
      Private Sub Form30_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' GropBox anzeigen
        Me.Controls.Add(gb)
        ' Daten laden
        For i = 0 To Me._arr.GetUpperBound(0)
          Arr(i) = rnd.NextDouble < 0.5
        Next
        ' GroupBox füllen ind jede CheckBos binden
        For i = 0 To Me._arr.GetUpperBound(0)
          Dim cb As New CheckBox With {.Text = $"Box {i + 1}", .Top = i * 20}
          cb.DataBindings.Add("Checked", Arr(i), "")
          gb.Controls.Add(cb)
        Next
      End Sub
    
      Private _arr(9) As Boolean ' Boolean-Array
      Friend Property Arr(index As Integer) As Boolean
        Get
          Return Me._arr(index)
        End Get
        Set(value As Boolean)
          Me._arr(index) = value
        End Set
      End Property
    End Class


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks


    Montag, 15. Januar 2018 09:19
  • Hallo Peter,

    und vielen Dank für Deine schnelle Antwort.

    Dass die CheckBoxes generiert werden müssen ist klar und habe ich auch so gemacht. Mir kam es lediglich auf das Databinding an.

    Und das schein ja mit

     cb.DataBindings.Add("Checked", Arr(i), "")
    

    wesentlich einfacher zu sein, als ich erwartet hatte.

    Ich werde erst im Lauf der Woche dazu kommen es zu testen. Ich gehe aber schon mal davon aus, dass es genau so funktionieren wird. Ich melde mich nach dem Test zurück.

    Nochmals vielen Dank.

    Gruß, Werner


    WM

    Montag, 15. Januar 2018 10:04
  • Hi Werner,
    du kannst einfach den von mir geposteten Quelltext in eine leere Form kopieren und sehen, dass es funktioniert. Wichtig in der Demo ist, dass der Zugriff für die Bindung über eine indizierte Eigenschaft gemappt wird.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks


    Montag, 15. Januar 2018 10:16
  • Hallo Peter,

    ich konnte mir einen schnellen Test in meinem bereits erstellten Code nicht verkneifen. Das hat aber nicht funktioniert. Der Code wird fehlerfrei kompiliert. Aber weder zeigen mir die entsprechenden CheckBoxes voreingestellte Werte an noch enthält das Array nach Schließen des Formulars angeklickte Werte.

    Vielleicht liegt es daran, dass ich das Binding erst zuordne, nachdem ich die Checkbox bereits mit Add der GroupBox zugewiesen hatte. In Deinem Code passiert das vor dem Zuordnen.

    Zu mehr reicht mir im Moment nicht die Zeit. Ich muss es, wie gesagt, im Laufe der Woche in Ruhe analysieren. Sollte ich den Fehler nicht finden, melde ich mich noch einmal mit Codeauszug.

    Danke vorerst.

    Gruß, Werner


    WM

    Montag, 15. Januar 2018 10:33
  • Hallo Peter,

    ich nutze immer mal die Zeit zwischendurch, um zu testen und weiter zu kommen.

    Vom Code her sehe ich keinen Unterschied, bis auf die oben erwähnte Zuordnung des Binding, was bei Dir vor und bei mir nach dem Add der Checkboxen zur Groupbox erfolgt. Aber daran liegt es definitiv nicht. Das habe ich schon mal ausgeschlossen.

    Da ich einen Teil des Codes in Funktionen und Routinen habe, ist es mir gegenwärtig noch zu aufwändig, den ganzen Code hier einzufügen oder vorher entsprechend aufzuarbeiten.

    Was mir aber noch aufgefallen ist: Du hast den Code vollständig im Load-Event des Formulars stehen. Ich dagegen habe ein Formular mit Überschrift, Buttons, Groupbox usw. und einer Checkbox bereits vorbereitet und stelle das Formular vor seinem Aufruf mit ShowDialog durch externen Code fertig. Ansonsten müsste ich zu viele Parameter übergeben. Dabei übernehme ich Eigenschaften der vordefinierten Checkbox für die Definition weiterer Checkboxen. Das Binding allerdings füge ich, ebenfalls noch vor dem Formularaufruf, für alle Checkboxen, auch für die vordefinierte, ebenfalls durch externen Code zu. Für die vordefinierte Checkbox kann ich kein Binding zuweisen, da mir das Array nicht zur Auswahl gestellt wird (Alle anderen Eigenschaften kann ich auswählen).

    Vermutlich liegt der Fehler in der externen Binding-Zuordnung. Aber wie gesagt, das sieht bei mir auch nicht anders aus.

    Vielleicht fällt Dir noch etwas auf/ein, bevor ich meinen Code hierher zerpflücke.

    Gruß, Werner


    WM

    Montag, 15. Januar 2018 14:01
  • Hi Werner,
    ob vor dem Einfügen oder nach dem Einfügen der CheckBoxes in die GroupBox die Datenbindung hinzugefügt wird, ist egal:

        For i = 0 To Me._arr.GetUpperBound(0)
          Dim cb As New CheckBox With {.Text = $"Box {i + 1}", .Top = i * 20}
          gb.Controls.Add(cb)
          cb.DataBindings.Add("Checked", Arr(i), "")
        Next

    Ich habe nur alles im Form_Load eingefügt, damit das Beispiel auch voll funktionsfähig ist ohne weitere Designer-Aktivitäten. In einem realen Projekt ist das alles normalerweise viel komplexer. Bei dieser Komplexität kann man aber schneller Fehler machen, was bei Dir vermutlich vorliegt.

    Du kannst das auch alles auslagern:

    Public Class Form30
      Private gb As New GroupBox With {.Dock = DockStyle.Fill, .Text = "GroupBox mit ChexBoxes"}
      Private dl As New Form30DataLayer
      Private Sub Form30_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' GroupBox füllen
        gb.Controls.AddRange(dl.GetCheckBoxes.ToArray)
        ' GropBox anzeigen
        Me.Controls.Add(gb)
      End Sub
    End Class
    
    Friend Class Form30DataLayer
    
      Private rnd As New Random
    
      Friend Sub New()
        ' Daten laden
        For i = 0 To Me._arr.GetUpperBound(0)
          Arr(i) = rnd.NextDouble < 0.5
        Next
      End Sub
    
      Friend Iterator Function GetCheckBoxes() As IEnumerable(Of CheckBox)
        ' CheckBoxes erstellen und jede CheckBos binden
        For i = 0 To Me._arr.GetUpperBound(0)
          Dim cb As New CheckBox With {.Text = $"Box {i + 1}", .Top = i * 20}
          cb.DataBindings.Add("Checked", Arr(i), "")
          Yield cb
        Next
      End Function
    
      Private _arr(9) As Boolean ' Boolean-Array
    
      Private Property Arr(index As Integer) As Boolean
        Get
          Return Me._arr(index)
        End Get
        Set(value As Boolean)
          Me._arr(index) = value
        End Set
      End Property
    End Class


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    Montag, 15. Januar 2018 14:29
  • Danke Peter für Deine schnellen Antworten.

    Mir scheint, dass das externe Array Schuld ist. Denn es wird mir ja beim Formularentwurf auch nicht als Bindingsource angezeigt. Andererseits sollte es dann aber, nach der externen Zuweisung der Bindingsource, wohl zu Fehlern in der Laufzeit führen.

    Wie Du schon richtig bemerkt hast, ist alles ziemlich komplex und sicher wird der Fehler irgendwo darin liegen.

    Ich werde auf jeden Fall noch suchen und mich melden. Ich muss leider hauptsächlich einiges anderes fertigstellen.

    Gruß, Werner


    WM

    Montag, 15. Januar 2018 14:40
  • Hi Werner,
    wenn Du mit dem Designer eine Datenquelle zuweisen willst, dann muss diese auch als instanziierbare Komponente bereitstehen. Meist ist das aber nicht notwendig, da eine Zuweisung zur Ausführungszeit völlig ausreichend sein kann.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    • Als Antwort markiert WerMil Dienstag, 30. Januar 2018 09:05
    Montag, 15. Januar 2018 15:34
  • Hallo Peter,

    vielen Dank noch einmal für alle Deine Tipps. Wie befürchtet konnte ich leider in den letzten Tagen an der Angelegenheit nicht dran bleiben und vermutlich werde ich es auch eine ganze Weile zurückstellen müssen.

    Im Prinzip hattest Du aber meine Frage gleich am Anfang beantwortet, so dass jetzt eigentlich nur noch die Fehlersuche offen bleibt, die ich vermutlich alleine zum Ende bringen kann.

    Ich werde daher zunächst erst einmal den Thread als beantwortet markieren. Ggf. müsste ich mich erneut melden.

    Gruß, Werner


    WM

    Dienstag, 30. Januar 2018 09:04