ComboBox DataSource ist ein Array, soll sich ComboBox automatisch aktualisieren?

  • VB.NET

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von sonne75.

    ComboBox DataSource ist ein Array, soll sich ComboBox automatisch aktualisieren?

    Hallo,
    ich habe hier die Suche bemüht, habe aber nichts gefunden.
    Wenn man ComboBox über DataSource an ein Array von Strings bindet und dieses Array dann im Laufe des Programms aktualisiert, sollte sich die ComboBox nicht automatisch aktualisieren?

    Das passiert nämlich nicht. Beim Laden wird dieses Array mit Werten gefüllt, dann wird es der DataSource der ComboBox zugewiesen. Wenn aber in einem Event das Array neu gefüllt wird (und zwar wird ihm der Rückgabearray einer Funktion zugewiesen), dann aktualisiert sich zwar das Array aber nicht die Combobox:

    im Load:

    VB.NET-Quellcode

    1. _Keys=Ini.GetKeys(sec)
    2. cbKeys.DataSource=_Keys


    im Event

    VB.NET-Quellcode

    1. _Keys=Ini.GetKeys(sec)


    _Keys ist klassenweit deklariert.

    Muss man DataSource nochmal neu zuweisen?

    VB.NET-Quellcode

    1. cbKeys.DataSource=_Keys

    Aber was ist dann der Sinn der Datenbindung?

    Danke.

    LG
    Ich muss keinen Umweg über Nothing gehen, es funktioniert auch, wenn ich direkt nochmal das Array der DataSource zuweise (in einem Projekt von EDR ist es genau so). Die BindingList schaue ich mir gleich an.

    EDIT: wie aktualisiert man dann diese List? Wenn ich als Rückgabeparameter von der Funktion immer ein Stringarray bekomme? Löschen und Element einzeln zuweisen?
    Was wäre der Vorteil gegenüber

    VB.NET-Quellcode

    1. cbKeys.DataSource=Ini.GetKeys(sec)

    jedesmal?
    Controls und Components:
    - ListBox1
    - Button1
    - TextBox1
    - BindingSource1

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private _data As New List(Of String)
    3. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    4. Me.ListBox1.DataSource = Me.BindingSource1
    5. Me.BindingSource1.DataSource = _data
    6. End Sub
    7. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    8. Me.BindingSource1.Add(Me.TextBox1.Text)
    9. End Sub
    10. End Class
    Muss hier

    xtts02 schrieb:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    2. Me.BindingSource1.Add(Me.TextBox1.Text)
    3. End Sub


    nicht

    VB.NET-Quellcode

    1. _data.Add(Me.TextBox1.Text)

    stehen?

    Dann sollte sich die ListBox über Bindingssource aktualisieren. Oder geht es nicht?

    Aber bei solchem Aufwand bleibe ich lieber dabei, die cbKeys.DataSource neu zu setzen. Denn ich müsste erst mal in einer Schleife das Stringarray der List einzeln zuweisen...

    VB.NET-Quellcode

    1. _data.Add(Me.TextBox1.Text)
    wäre prinzipiell besser, denn das ist eine typisierte Zuweisung.
    Aber dazu müssteste die bereits von FreakJNS empfohlene Bindinglist(Of String) verwenden.

    Es scheint natürlich immer am einfachsten, sich an vorgekautem Code zu orientieren, aber ist nicht immer auch das beste.
    Aber wenn ich eine BindingList habe, brauche ich noch eine Bindingsource dazwischen? Kann ich sie nicht direkt dem DataSource der ComboBox zuweisen?

    Und ich habe immer noch nicht verstanden, was der Vorteil einer BindingList gegenüber direktem zuweisen des Array zu DataSource jedes Mal wäre.
    Nein, brauchst du nicht. Du kannst die BindingList direkt mit .DataSource an ein entsprechendes Control binden. Vorteil gegenüber Arrays/normaler List(of T): Die BindingList teilt dem Control automatisch mit, wenn du ein Item addest/entfernst, sodass es sich aktualisieren kann.
    In meinem Fall muss ich aber die Liste manuell befüllen, weil der Rückgabewert ein Stringarray ist.

    VB.NET-Quellcode

    1. Dim arr=Ini.GetKeys(sec)
    2. BindList.Clear()
    3. For i=0 To arr.Count-1
    4. BindList.Add(arr(i))
    5. Next


    sonst mache ich ja

    VB.NET-Quellcode

    1. cbKeys.DataSource=Ini.GetKeys(sec)


    EDIT: jetzt ist der Rückgabewert plötzlich List (Of String), obwohl ich nur

    VB.NET-Quellcode

    1. Function test() As String()
    schreibe. Seit wann ist es eine List statt dem Array? :?:
    Aber egal, ich kann trotzdem die List (Of String) leider nicht in eine BindingList (Of String) konvertieren...

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „sonne75“ ()

    Habe mir mal eine BindingList gemacht, die man wie die List(of T) sortieren kann. AddRange ist auch schnell hinzugefügt:

    VB.NET-Quellcode

    1. Public Class BetterBindingList(Of T)
    2. Inherits System.ComponentModel.BindingList(Of T)
    3. Private Const NO_ITEM_INDEX As Integer = -1
    4. Public Sub addRange(ByVal collection As IEnumerable(Of T))
    5. Dim tmp As List(Of T) = DirectCast(Me.Items, List(Of T))
    6. tmp.AddRange(collection)
    7. OnListChanged(New System.ComponentModel.ListChangedEventArgs(System.ComponentModel.ListChangedType.Reset, NO_ITEM_INDEX))
    8. End Sub
    9. Public Sub sort(ByVal sorter As System.Comparison(Of T))
    10. Dim tmp As List(Of T) = DirectCast(Me.Items, List(Of T))
    11. tmp.Sort(sorter)
    12. OnListChanged(New System.ComponentModel.ListChangedEventArgs(System.ComponentModel.ListChangedType.Reset, NO_ITEM_INDEX))
    13. End Sub
    14. Public Sub sort(ByVal comparer As System.Collections.Generic.IComparer(Of T))
    15. Dim tmp As List(Of T) = DirectCast(Me.Items, List(Of T))
    16. tmp.Sort(comparer)
    17. OnListChanged(New System.ComponentModel.ListChangedEventArgs(System.ComponentModel.ListChangedType.Reset, NO_ITEM_INDEX))
    18. End Sub
    19. Public Sub sort(ByVal index As Integer, ByVal count As Integer, ByVal comparer As System.Collections.Generic.IComparer(Of T))
    20. Dim tmp As List(Of T) = DirectCast(Me.Items, List(Of T))
    21. tmp.Sort(index, count, comparer)
    22. OnListChanged(New System.ComponentModel.ListChangedEventArgs(System.ComponentModel.ListChangedType.Reset, NO_ITEM_INDEX))
    23. End Sub
    24. End Class


    Da du aber eh ein .Clear aufrufst und dann wieder alles neu addest kannst du auch gleich die DataSource neu zuweisen. Es ist einfacher einer Person eine neue Adresse zu nennen als ein genanntes Haus komplett auszumisten und neu einzurichten.
    Danke schön. Verstehe ich es richtig, bei deiner List muss man trotzdem erst löschen und dann .addRange(list) machen?
    Ist es schlechter eine "addRange" über For-Schleife und direkte Elementzuweisung zu machen (wie bei mir weiter oben)?
    Warum erstellst du erst eine List, castest deine BindingList in sie, fügst die collection hinzu und dann noch Event auslösen (deren Inhalt ich leider nicht verstehe)? Gibt es da einen Vorteil gegenüber der For-Schleife?
    Das ist nur eine Erweiterung der BindingList. Intern verwendet die BindingList eine List(of T), darum ist das so möglich.

    Ob es schlechter ist oder ob es Vorteile gibt? Naja, bei jedem Element, das du der BindingList addest wird sie dem Control "ich habe mich geändert" sagen. Bei der .AddRange-Methode werden alle neuen Elemente auf einmal in die Liste geadded und dann meldet sich die BetterBindingList ans Control. Das 'ans Control wenden' macht dieses Event. Außerdem musst du keine For-Schleife mehr schreiben, wenn du .addRange verwendest.

    VB.NET-Quellcode

    1. Option Strict On
    2. Dim normaleBindingList As New System.ComponentModel.BindingList(Of Integer)
    3. Dim betterBindingList As New BetterBindingList(Of Integer)
    4. Dim vieleIntegers() As Integer = {3, 5, 63, 2, 34, 5, 644, 4, 3}
    5. 'MEHRERE ELEMENTE HINZUFÜGEN
    6. betterBindingList.addRange(vieleIntegers)
    7. 'normaleBindingList.addRange(vieleIntegers) 'die normale BL kann das nicht...
    8. 'SORTIEREN
    9. betterBindingList.sort(Function(x, y) x - y)
    10. 'normaleBindingList.sort(Function(x, y) x - y) 'die normale BL kann das nicht...
    11. 'WICHTIG: Die betterBL IST eine BindingList - Vererbung ist cool xD
    12. normaleBindingList = betterBindingList


    Ob du nun so eine 'Selbstgebastelte' Lösung verwendest oder einfach die DataSource neu setzt bleibt dir überlassen. Fakt ist, dass du da ein Haus komplett leerst und die Einrichtung des Nachbarn rüberträgst, anstatt dem Besucher zu sagen, er möge doch bitte ins Haus nebenan kommen^^

    FreakJNS schrieb:

    Bei der .AddRange-Methode werden alle neuen Elemente auf einmal in die Liste geadded und dann meldet sich die BetterBindingList ans Control.

    Das ist ein gutes Argument!

    FreakJNS schrieb:

    VB.NET-Quellcode

    1. betterBindingList.sort(Function(x, y) x - y)

    Kannst du mir bitte erklären, was dabei passiert?

    FreakJNS schrieb:

    anstatt dem Besucher zu sagen, er möge doch bitte ins Haus nebenan kommen


    Wie würde ich es sagen? Es geht nur darum, dass eine ComboBox sich aktualisiert (Daten kommen aus einer Ini).

    VB.NET-Quellcode

    1. betterBindingList.sort(Function(x, y) x - y)

    Das ist eine Art Minimalform zum vergleichen von zwei Elementen. Auf dessen Grundlage wird die Liste dann sortiert. Schau dir mal die CompareTo-Methoden von verschiedenen Datentypen an (z.B. Date), diese geben immer einen Integer zurück. Weil bei mir schon Integer drin waren und "x-y" einen zurückgibt habe ich das so geschrieben. Besser wäre natürlich so:

    VB.NET-Quellcode

    1. betterBindingList.sort(Function(x, y) x.CompareTo(y))

    denn das funktioniert auch bei vielen anderen Datentypen.

    Wie würdest du es ihm sagen? Wenn es nur ein Besucher ist (also eine Combobox, die an der Liste interessiert ist) würde ich einfach .DataSource neu setzen. Sind es mehrere, dann denke ich wäre die BindingSource das Richtige.

    FreakJNS schrieb:

    Schau dir mal die CompareTo-Methoden von verschiedenen Datentypen an (z.B. Date)

    Ich habe geschaut, es gibt eine positive Zahl, wenn x>y, 0, wenn gleich, negative Zahl, wenn x<y. Wie bei dir auch. Aber was passiert dann? Wie weiß die Sort-Funktion, was sie machen soll (ordnen)? Wo wird das erledigt?
    Habe gerade nochmal nachgeschaut, ist wohl eine eingebaute Funktion einer List (Of T) und du nutzt die Funktionalität wohl einfach mit.

    FreakJNS schrieb:

    Sind es mehrere, dann denke ich wäre die BindingSource das Richtige.


    Und in welchem Fall dann die BindingList? Oder ist es in dem Fall das Gleiche (BindingSource kombiniert mit List (Of T))?
    Mal eine Zusammenfassung:
    Spoiler anzeigen
    List(of T) und Arrays: Listen einfach nur Elemente auf
    BindingList: Listet Elemente auf UND ist so gebaut, dass sie Controls, an die es gebunden ist mitteilen kann, wenn sich was ändert

    Die List(of T) bietet Möglichkeiten zum sortieren - die BindingList nicht. (Aber darum geht es hier ja nicht). Ebenso bietet die List(of T) eine .AddRange Methode, die BindingList nicht. Um diese 'Schwachstellen' auszubessern habe ich die BetterBindingList geschrieben. Weil die BindingList intern eine List(of T) verwendet kann man die Methodenaufrufe einfach an diese weiterleiten - und muss dann sagen, dass sich was geändert hat.

    Wenn du nun nur ein einziges Control hast, welches eine Liste anzeigen soll, dann ist es am einfachsten .DataSource=neueListeOderArray zu setzen. Sind es aber nun mehrere Controls (Listboxen, Comboboxen, etc), dann müsstest du viele DataSources neu setzen - ODER: du lässt das ganze über die BindingSource laufen, sodass du nur dort die DataSource neu setzen musst.


    Das ist alles viel gerede rundrum. "Aber was ist dann der Sinn der Datenbindung?"
    Kommt was neues dazu, sollen Controls sich automatisch aktualisieren. Du hast da einen Extremfall, weil du nicht einzelne Elemente addest/removest, sondern ganz stumpf alles löschst und wieder neu addest. Weil du das von vornherein schon weißt, würde ich die DataSource einfach neu zuweisen. (somit ist alles andere, was hier geschrieben wurde NiceToKnow für die meisten anderen Probleme - aber hier nicht unbedingt angebracht, meine Meinung)