Datagridview Datenaktualisierung im Hintergrund (ähnlich wie in Access)

  • VB.NET

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

    Datagridview Datenaktualisierung im Hintergrund (ähnlich wie in Access)

    Moin,

    nachdem ich hier schon jahrelang immer wieder Lösungen für meine Problemchen finde musste ich mch jetzt doch mal anmelden. Also erstmal Hallo und sorry wenn es im falschen Bereich gelandet ist.

    Ich bin die letzten Jahre eher in PHP unterwegs gewesen, deswegen entschuldigt wenn die Frage zu simpel ist.

    Aber nun zu meiner Aufgabenstellung. Ich habe ein funktionierendes Windows Form, das mir für 18 Techniker jeweils die offenen Aufträge anzeigt. Das habe ich atm über ein Usercontrolelement gelöst, welches ein Datagridview, die MYSQL Verbidung incl. Abfrage und Layout- und Stylingfunktionen für das DGV enthält. Dieses Usercontrollelement ruf ich aus dem Formular dann 18 mal auf, mit Parametern für die einzelen Techniker. Das ganze Rendering dauert aber ein par Sekunden, was zu einem unschönen Bildaufbau führt. Letzteres wäre noch vertretbar, wenn es nur bei Programmstart auftreten würde, da aber auch Datensätze aus anderen Quellen (mobile App, Website, Access) in die Datenbank gelangen, lade ich die Datatable, die als Datasource für das DGV dient, regelmäsig neu, was alle par Minuten diesen hässlichen Effekt verursacht.
    Gibt es eine Möglichkeit / Methode, dass die Daten für das DGV so aktualisiert werden, wie es z.B. Access macht, also einerseits automatisch wenn neue/geänderte Datensätze aus anderen Quellen in die Datenbank gelangen und andererseits, ohne immer das ganze DGV neu zu rendern.

    Ich hoffe ihr könnt mir da weiterhelfen, kann ja nicht sein, dass ich was versuche, das noch nie wer gemacht hat ;)
    Willkommen im Forum :)

    DianonForce schrieb:

    Das ganze Rendering dauert aber ein par Sekunden, was zu einem unschönen Bildaufbau führt
    Versuche einmal die Bindung zu den Controls während der Aktualisierung der Daten zu deaktivieren und danach wieder zu aktivieren...
    Bindingsource.EnableListChangedEvents=False und BindingSource.SuspendBindings
    Danke für die Antwort, aber ich hab kein Bindingsource Objekt, wenn ich das richtig sehe dürfte dein Ansatz deswegen nicht fuktionieren.

    Ich hau mal den Code für die Aktualisierung hier mit dran, bitte nicht hauen, wenn er Mist ist, ich versuche hier grade die Programmierung meines Kollegen soweit zu überarbeiten. Ursprünglich hatte er für jedes DGV einen eigenen Sub, was dafür sorgte das durch copy & paste ca. 1/3 aller DGVs nicht funktionierten, ich hab den Code jetzt auch nur 'übernommen' und in eine eigene Klasse 'geschmissen' das er wenn dann überall gleich funktioniert oder nicht.


    VB.NET-Quellcode

    1. Sub New(techkz As String)
    2. InitializeComponent()
    3. Me.Name = "tv" & techkz
    4. 'daten.technikerviews.add(Me)
    5. kuerzel = techkz
    6. fillTickets()
    7. End Sub
    8. Sub fillTickets()
    9. Try
    10. Dim techniker() As DataRow = daten.dt_user.Select("user ='" & kuerzel & "'")
    11. If techniker.Count = 1 Then
    12. LblTechniker.Text = techniker(0)("name")
    13. End If
    14. Catch ex As Exception
    15. End Try
    16. Try
    17. Dim con As MySqlConnection = Nothing
    18. con = New MySqlConnection(My.Settings.MySqlWebConString)
    19. con.Open()
    20. dt = Nothing
    21. DgvTickets.DataSource = Nothing
    22. DgvTickets.Update()
    23. Dim SQLString = "SELECT
    24. id,
    25. status,
    26. Firma,
    27. ort as Ort,
    28. Modell,
    29. datum as Datum,
    30. stoerung as Stoerung,
    31. termintag as TerminVon,
    32. terminende as TerminBis,
    33. termintyp,
    34. Standort,
    35. Techniker,
    36. KDNR
    37. FROM
    38. tbl_serviceticket
    39. WHERE
    40. status <> 14
    41. AND
    42. status <> 39
    43. AND
    44. status <> 102
    45. AND
    46. techniker = '" & kuerzel & "'"
    47. '### Ausnahme für Unverteilt -> Ware benötigt ###
    48. If kuerzel = "%" Then
    49. SQLString = SQLString & "
    50. OR
    51. status = 19"
    52. End If
    53. '### Ausnahme für mt -> Eskalation ###
    54. If kuerzel = "mt" Then
    55. SQLString = SQLString & "
    56. OR
    57. status > 98
    58. AND
    59. status < 102"
    60. End If
    61. '### Sortierung ###
    62. SQLString = SQLString & "
    63. ORDER BY
    64. Datum DESC;"
    65. rs = New MySqlDataAdapter(SQLString, My.Settings.MySqlWebConString)
    66. Dim commandBuilder As New MySqlCommandBuilder(rs)
    67. dt = New DataTable()
    68. dt.Locale = System.Globalization.CultureInfo.InvariantCulture
    69. rs.Fill(dt)
    70. DgvTickets.DataSource = dt
    71. dt.Columns.Add("TKD")
    72. For Each row As DataRow In dt.Rows
    73. Dim result() As DataRow = daten.dt_tkd.Select("auaersatzger ='" & row("id") & "'")
    74. For Each rows In result
    75. row("TKD") = result(0)("auanr")
    76. Next
    77. Next
    78. LblTicketcount.Text = "mit " & dt.Rows.Count & " Tickets"
    79. con.Close()
    80. Dim cbStatus As New DataGridViewComboBoxColumn
    81. cbStatus.Name = "cbStatus"
    82. cbStatus.DataPropertyName = "status"
    83. cbStatus.HeaderText = "Status"
    84. cbStatus.DataSource = daten.dt_ticketstatus
    85. cbStatus.ValueMember = "id"
    86. cbStatus.DisplayMember = "serviceticket_status"
    87. cbStatus.FlatStyle = FlatStyle.Flat
    88. DgvTickets.Columns.Insert(0, cbStatus)
    89. Dim cbTechniker As New DataGridViewComboBoxColumn
    90. cbTechniker.Name = "cbTechniker"
    91. cbTechniker.DataPropertyName = "techniker"
    92. cbTechniker.HeaderText = "Techniker"
    93. cbTechniker.DataSource = daten.dt_user
    94. cbTechniker.ValueMember = "user"
    95. cbTechniker.DisplayMember = "user"
    96. cbTechniker.FlatStyle = FlatStyle.Flat
    97. DgvTickets.Columns.Insert(13, cbTechniker)
    98. DgvTickets.AllowUserToAddRows = False
    99. DgvTickets.RowTemplate.Height = 18
    100. DgvTickets.Columns("id").Visible = False
    101. DgvTickets.Columns("status").Visible = False
    102. DgvTickets.Columns("techniker").Visible = False
    103. DgvTickets.Columns("termintyp").Visible = False
    104. DgvTickets.Columns("cbTechniker").Width = 45
    105. DgvTickets.Columns("Ort").Width = 60
    106. DgvTickets.Columns("Firma").Width = 60
    107. DgvTickets.Columns("Modell").Width = 60
    108. DgvTickets.Columns("Datum").Width = 75
    109. DgvTickets.Columns("Stoerung").Width = 210
    110. DgvTickets.Columns("Standort").Width = 60
    111. DgvTickets.Columns("cbStatus").Width = 80
    112. DgvTickets.Columns("TerminVon").Width = 90
    113. DgvTickets.Columns("TerminBis").Width = 90
    114. DgvTickets.Columns("TKD").Width = 40
    115. DgvTickets.Columns("TKD").DisplayIndex = 12
    116. DgvTickets.RowHeadersVisible = True
    117. DgvTickets.RowHeadersWidth = 20
    118. DgvTickets.Columns("KDNR").Width = 1
    119. Catch
    120. 'todo: Cath routine
    121. End Try
    122. End Sub
    123. Private Sub dgvTickets_CellPainting(ByVal sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DgvTickets.CellPainting
    124. Try
    125. For i As Integer = 0 To DgvTickets.Rows.Count - 1
    126. DgvTickets.Rows(i).Height = 17
    127. Select Case DgvTickets.Rows(i).Cells("status").Value
    128. Case "10"
    129. DgvTickets.Rows(i).Cells("cbStatus").Style.BackColor = Color.Orange
    130. Case "20"
    131. DgvTickets.Rows(i).Cells("cbStatus").Style.BackColor = Color.LightBlue
    132. Case "99"
    133. DgvTickets.Rows(i).Cells("cbStatus").Style.BackColor = Color.Red
    134. Case "15"
    135. DgvTickets.Rows(i).Cells("cbStatus").Style.BackColor = Color.LightGray
    136. Case "12"
    137. DgvTickets.Rows(i).Cells("cbStatus").Style.BackColor = Color.LightGreen
    138. End Select
    139. Select Case DgvTickets.Rows(i).Cells("termintyp").Value
    140. Case "0"
    141. DgvTickets.Rows(i).Cells("TerminVon").Style.BackColor = Color.LightBlue
    142. DgvTickets.Rows(i).Cells("TerminBis").Style.BackColor = Color.LightBlue
    143. Case "1"
    144. DgvTickets.Rows(i).Cells("TerminVon").Style.BackColor = Color.LightGreen
    145. DgvTickets.Rows(i).Cells("TerminBis").Style.BackColor = Color.LightGreen
    146. Case "2"
    147. DgvTickets.Rows(i).Cells("TerminVon").Style.BackColor = Color.LightYellow
    148. DgvTickets.Rows(i).Cells("TerminBis").Style.BackColor = Color.LightYellow
    149. Case "3"
    150. DgvTickets.Rows(i).Cells("TerminVon").Style.BackColor = Color.Red
    151. DgvTickets.Rows(i).Cells("TerminBis").Style.BackColor = Color.Red
    152. End Select
    153. Next
    154. Catch
    155. End Try
    156. End Sub


    Und ja, ich weiß, nen Try Catch ohne Catchroutine ist völliger Schwachsinn, so hat / tut mein Kollege leider programmieren. Ich weiß nicht wieviel Nerfen mich das schon gekostet hat, nicht funktionierenden Code zu suchen der allerdings keinen Fehler wegen diesem Mist schmeißt.

    VB1963 schrieb:

    DianonForce schrieb:

    Ich weiß nicht wieviel Nerfen mich das schon gekostet hat, nicht funktionierenden Code zu suchen der allerdings keinen Fehler wegen diesem Mist schmeißt.
    Dann sofort raus mit dem Try/Catch und sämtlicher Fehler auf den Grund gehen...


    Na, das lass ich noch absichtlich drin, da ich da noch für User verständliche Fehlermeldungen reinmachen will, damit ich nicht Rückmeldunungen wie "Da geht was nicht" bekomme, aber das ist noch relativ weit hinten bei meinem todo. Wie gesagt atm läuft es ja, nur der Bildaufbau nerft mich.

    DianonForce schrieb:

    Ich kann den Try Catch auch rausnehmen, dass ändert nichts an der Programmfunktion
    dann ist's ja gut und du brauchst die Try/Catches ja dann gar nicht...
    Sollte wirklich einmal ein Fehler auftreten, dann kannst du diesem gleich nachgehen!
    Zur Bindingsource: du brauchst nur die BS zwischen Daten und DGV zwischenschalten

    VB.NET-Quellcode

    1. rs.Fill(dt)
    2. Dim bs As New BindingSource()
    3. bs.DataSource = dt
    4. DgvTickets.DataSource = bs
    und dann kannst du das von Post#2 einmal testen...
    Ich grab den Thread mal wieder aus,
    ich habe zwischenzeitlich mal ein wenig mit den Bindingsources rumexperimentiert und alleine diese haben die Effekte schon dramatisch reduziert. Bis zum Vorschlag aus #2 habe ich es leider nicht mehr geschafft. Zwischenzeitlich war ich über die DBExtensions von EDR gestolpert und dachte "cool, das würde gleich noch 2-3 andere Sachen charmant lösen" leider habe ich mich damit in eine Ecke entwickelt bei der ich mich Frage wie ich wieder rauskomme.
    Ich habe immernoch mein Formular, welches zur Laufzeit 18 gleiche Usercontrols erstellt, diese Unterscheiden sich eigendlich nur durch die gefilterten Daten (heißt jedes Usercontrol zeigt die Aufträge eines Technikers an, manche zusätzlich noch einige 'besondere Aufträge'). Momentan lasse ich in jedem Usercontrol mit hilfe der DBExtensions die Tabelle Servicetickets füllen,

    VB.NET-Quellcode

    1. Sub New(techkz As String)
    2. InitializeComponent()
    3. Me.Name = "tv" & techkz
    4. kuerzel = techkz
    5. Dim techniker() As DataRow = daten.dt_user.Select("user ='" & kuerzel & "'")
    6. If techniker.Count = 1 Then
    7. LblTechniker.Text = techniker(0)("name")
    8. End If
    9. Dim adp = New DatasetAdapter(
    10. MySql.Data.MySqlClient.MySqlClientFactory.Instance,
    11. My.Settings.db_dispatchingConnectionString,
    12. ConflictOption.OverwriteChanges)
    13. Db_serviceticket_test.Adapter(adp).Register(Me)
    14. fillTickets()
    15. End Sub
    16. Sub fillTickets()
    17. With Db_serviceticket_test
    18. .Fill(.tbl_service_ticket_status)
    19. .tbl_serviceticket.Fill("WHERE status <> 14 AND status <> 39 AND status <> 102 AND techniker = ?", kuerzel)
    20. End With
    21. End Sub


    dies führt dazu das zum Schluß alle 18 Usercontolls die selben Datensätze anzeigen, nämlich die vom letzten 'techkz'. Ich vermute das Verhalten ist durch DBExtensions so erwünscht.
    Ich überlege nun nur, wie ich in den 18 Usercontrolls jeweils nur die Aufträge vom jeweiligen 'techkz' anzeigen kann ohne 18 Datasets zu machen.

    Idee 1: die Tabelle Servicetickets nur einmal mit den Aufträgen aller Techniker zu füllen und über die Filtereigenschft der Datagridviews nur die jeweiligen Aufträge anzeigen. Leider hat der Ansatz das Problem das viele unnötige Daten abgefragt werden, worunter schon bei der vorhandenen Lösung die Performance leidet.

    Idee 2: in jedem Usercontrol nur für das jeweilige 'techkz' die Tabelle befüllen. Würde zwar die zu verarbeitende Datenmenge drastisch reduzieren, allerdings habe ich keine Idee wie ich mit der DBExtensions 18 unterschiedliche Tabellen befülle die uf dem selben Dataset beruhen. 18 Datasets zu erstellen ist denke ich kontraproduktiv und nicht Sinn der Sache.

    Ich hoffe irgendjemand kann mir folgen und hat einen guten Ansatz für mich :)
    also wenn jedes usercontrol für einen Techniker steht, und du willst alle userControls befüllen, dann wirst du wohl alle Techniker-Datensätze laden müssen.
    Aber da kommste doch so oder so nicht drumrum, ob nun DbExtensions oder nicht.

    Also mit DbExtensions geht vlt. sowas:

    VB.NET-Quellcode

    1. .tbl_serviceticket.Fill("WHERE (not status in (14 ,39 ,102)) AND techniker in (?,?,?,?,?)", _
    2. kuerzel1,kuerzel2,kuerzel3,kuerzel4,kuerzel5)

    Sehe ich es richtig, dass wenn ich das so machen würde, dass es sinniger wäre die Tabelle aus dem Formular herraus zu befüllen, anstatt aus den Usercontrols? Die UCs würden ja alle den selben DataSet benutzen und der würde ja egal von wo befüllt immer die gleichen Daten enthalten. Klappt das dann auch mit der Aktualisierung ( also insert,update und delete?). Sorry für die doofe Frage, aber in PHP ich habe mich bisher immer selbst um das Rückschreiben der Daten gekümmert, und so sehr hab ich hier noch nicht das Verständniss, dass sich ein Gefühl von 'das macht das schon selbst' einstellen würde.

    DianonForce schrieb:

    Sehe ich es richtig, dass wenn ich das so machen würde, dass es sinniger wäre die Tabelle aus dem Formular herraus zu befüllen, anstatt aus den Usercontrols?
    ja, natürlich.

    Ich würde auch von den 18 Ucls abraten - wenn die alle dieselbe Datenstruktur anzeigen, dann reicht eines.
    Die Daten-Präsentation wird nicht gewechselt, indem man ein anneres Ucl anzeigt, sondern einfach indem man einen Filter anders setzt.

    Guck dir mal Parent-Child-View an, auf vier Views-Videos
    Danke für den Tip mit der Parent-Child-View, aber ich glaube das ist für mein Ziel nicht das was ich will. Ich glaube auch das wir atm verschiedene Vorstellung haben wie das Ergebnis aussehen soll.

    Ich Versuche eine Gesamtübersicht zu erzeugen, bei der ein Anwedner alle oder bestimmte Techniker auswählt und dann eine Übersicht erhällt, in der pro Techniker ein, ich sag hier mal bewust ein optischer Container existiert (programmtechnisch muß er nicht existieren), der wiederumm alle Aufträge für diesen Techniker enthällt, so dass man eine Gesammtübersicht enthällt, wie viel zu tun ist und wie die Aufträge verteilt sind.

    Bilder
    • Dispatching.jpg

      161,63 kB, 1.000×548, 96 mal angesehen

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DianonForce“ ()