DataGridView und BindingList verbinden

  • VB.NET

Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von YEE.

    DataGridView und BindingList verbinden

    Beim suchen nach Lösungen, meine Datagridview an eine BindingList(of T) zu binden, welche sich auch selbstständig updaten sollte, bin ich auf diesen Thread gestoßen.
    Soweit funktioniert das ganze auch, allerdings nur solange wie nicht all zu viele PropertyChanged Events gleichzeitig reinflattern.
    Testweise habe ich eine Klasse erstellt, die über einen eigenen Timer, einmal pro Sekunde einen Wert erhöht und dann das Event auslöst.
    Bereits bei 5 Elementen, geschmissen zur gleichen Zeit in die BindingList(of T), verhaspelt sich die UI.
    Sporadisch wird mal hier, mal da aktualisiert.
    Bei Auswahl der Zellen / srollen werden alle sofort aktualisiert.


    Hin und wieder kommt auch ein Fehler:


    Benutze ich vlt die falsche Technik für meinen Anwendungsfall?
    Gibt es bereits bessere Methoden?


    VB.NET-Quellcode

    1. 'User Class
    2. Public Class Class_User : Implements INotifyPropertyChanged
    3. Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    4. Private m_UserName As String
    5. Private m_count As Integer = 0
    6. Private m_timer1 As New System.Timers.Timer
    7. Public Property UserName As String
    8. Get
    9. Return m_UserName
    10. End Get
    11. Set(value As String)
    12. m_UserName = value
    13. End Set
    14. End Property
    15. Public Property Count As Integer
    16. Get
    17. Return m_count
    18. End Get
    19. Private Set(value As Integer)
    20. m_count = value
    21. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Count"))
    22. End Set
    23. End Property
    24. Public Sub New(p_UserName As String, p_interval As Double)
    25. m_UserName = p_UserName
    26. m_timer1.Interval = p_interval
    27. m_timer1.Enabled = True
    28. AddHandler m_timer1.Elapsed, AddressOf m_timer1Tick
    29. End Sub
    30. Private Sub m_timer1Tick(sender As Object, e As EventArgs)
    31. Count += 1
    32. End Sub
    33. Private Sub NotifyPropertyChanged(ByVal Info As String)
    34. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Info))
    35. End Sub
    36. 'Form Class
    37. Public Class Form1
    38. WithEvents users As New System.ComponentModel.BindingList(Of Class_User)
    39. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    40. Bs1.DataSource = users
    41. Bs1.RaiseListChangedEvents = True
    42. DataGridView1.DataSource = Bs1
    43. End Sub
    44. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    45. For index As Integer = 0 To 5
    46. 'fügt der BindingList neue User hinzu mit Username und Timer Interval in ms
    47. users.Add(New Class_User("User " & index.ToString, 1000))
    48. Next
    49. End Sub
    50. End Class


    Ausgelagert aus List(of T) an DataGridView binden. ~Thunderbolt

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

    ErfinderDesRades schrieb:

    der Timer den du verwendest, läuft im NebenThread.
    wurde schon gesagt: Sowas verhält sich unvorhersehbar.


    Und wie regelt man dass dann, wenn mehrere Threads auf ein Control zugreifen wollen?
    Nehme wir an ich bastel einen Downloadmanager der es erlaubt gleichzeitig mehrere Datein runterzuladen.
    Da dürfte es auch pro Sekunde zu dutzenden PropertyChanged Events kommen.

    Ich habe heute Nacht noch mal das Internet ausgiebig abgesucht nach einer Lösung für mein Problem. Man findet aber nur Beispiele mit jeweils einem eigenen Control pro Thread.
    Mir schwebte eine art Warteschlange für PropertyChanges vor.
    Ich habe meinen Code dann wie folgt angepasst.

    Die ​Class_User bekommt eine List(Of String), worin alle PropertyChanges gespeichert werden.


    VB.NET-Quellcode

    1. Private m_ListOfPropertyChanges As New List(Of String)
    2. Public ReadOnly Property GetListOfPropertyChanges As List(Of String)
    3. Get
    4. Return m_ListOfPropertyChanges
    5. End Get
    6. End Property
    7. Private WriteOnly Property AddListOfPropertyChange As String
    8. Set(value As String)
    9. m_ListOfPropertyChanges.Add(value)
    10. End Set
    11. End Property
    12. Public Sub ClearListOfChanges()
    13. m_ListOfPropertyChanges.Clear()
    14. End Sub


    Propertys feuern nicht mehr selbst das PropertyChanged Event, sondern fügen Ihren Property Namen der privaten ​ListOfPropertyChanges hinzu:

    VB.NET-Quellcode

    1. Public Property Count As Integer
    2. Get
    3. Return m_count
    4. End Get
    5. Private Set(value As Integer)
    6. m_count = value
    7. If Not GetListOfPropertyChanges.Contains("Count") Then
    8. AddListOfPropertyChange = "Count"
    9. End If
    10. End Set
    11. End Property


    Kommen wir zur ​Form1 Klasse.
    Dort habe ich einen Timer hinzugefügt. Dieser geht alle paar Sekunden durch die List(Of Class_User) und prüft ob es Einträge in der ListOfPropertyChanges gibt.
    Wenn ja werden von der Form1 Klasse aus die einzelnen PropertyChanged Events​ gefeuert. Anschließend wird die Liste geleert.
    Getestet mit 10.000 Einträgen. Dauert wohl ne halbe Sekunde, allerdings Fehlerfrei.

    VB.NET-Quellcode

    1. Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    2. 'während der Schleife darf nichts hinzugefügt werden, sonst Fehler
    3. Button1.Enabled = False
    4. 'alle User in der BindingList(Of Class_User) durchgehen
    5. For Each a In users
    6. If Not IsNothing(a.GetListOfPropertyChanges) Then
    7. 'die Liste durchgehen, die die Namen der geänderten Propertys enthält
    8. For Each b In a.GetListOfPropertyChanges
    9. a.NotifyPropertyChanged(b)
    10. Next
    11. End If
    12. a.ClearListOfChanges()
    13. Next
    14. Button1.Enabled = True
    15. End Sub