Filterproblem im DataGridView mit DataGridViewCheckBoxColumn

  • VB.NET

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Kasi.

    Filterproblem im DataGridView mit DataGridViewCheckBoxColumn

    Hallo Zusammen,

    ich habe in einem Dataset eine DataTable "tbl_invoice", wo Rechnungsinformationen wie Rg.-Nr., Datum, Betrag, bezahlt, bezahlt wann, etc. gespeichert werden.

    Die Daten sind in einer MariaDB gespeichert bw. werden dort zur Verfügung gestellt.

    Dem Anwender wird für die bereits erstellten Rechnungen ein Form mit einem Datagridview (dgv_invoice_overview) bereit gestellt, wo ihm jede "noch nicht bezahlte Rechnung" angezeigt wird. Für das "noch nicht bezahlt" habe ich in der Datenbank eine Column "tbl_invoice_paid" (Typ: tinyint(1)) - 0 oder 1.
    Im DGV wird diese Column als DataGridViewCheckBoxColumn dargestellt.

    Das Filtern der DataTable "tbl_invoice" habe ich

    Versuch a) Mit einer BindingSource (über den Designer aufs Form gepackt und gefüllt)

    VB.NET-Quellcode

    1. Private Sub frm_invoice_overview_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. bsInvoice.DataSource = DS_Global.Tables("tbl_invoice")
    3. bsInvoice.Filter = " AND tbl_invoice_paid = 0 AND tbl_invoice_should_pay <'" & Format(Date.Now, "yyyy-MM-dd") & "'"
    4. bsInvoice.Sort = "tbl_invoice_number, tbl_invoice_date"
    5. dgv_invoice_overview.DataSource = bsInvoice
    6. End Sub


    Versuch b) Mit einer DataView realisiert

    VB.NET-Quellcode

    1. Private Sub frm_invoice_overview_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. dvInvoiceDataView = DS_Global.Tables("tbl_invoice").DefaultView
    3. dvInvoiceDataView.RowFilter =" AND tbl_invoice_paid = 0 AND tbl_invoice_should_pay <'" & Format(Date.Now, "yyyy-MM-dd") & "'"
    4. dvInvoiceDataView.Sort = "tbl_invoice_number, tbl_invoice_date"
    5. dgv_invoice_overview.DataSource = dvInvoiceDataView
    6. End Sub

    Angenommen, der Anwender hat nun in der DGV fünf "offene" - noch nicht bezahlte Rechnungen vor sich...

    Wenn er nun in Row 2 (oder 0, 1, 3, 4) die Checkbox der Column "tbl_invoice_paid" klickt und diese damit auf "True" setzt, er jetzt die Row 2 verlässt (wenn er in der Row bleibt, bleibt auch die Row), schlägt der Filter zu und die Row ist aus dem DGV - also nicht mehr sichtbar.
    Das möchte ich aber nicht! Die Row 2 soll angezeigt werden, bis der Anwender mit einem Button ALLE Änderungen akzeptiert (da liegt mein Problem nicht).

    Wenn ich für das DGV noch weitere (außer Checkboxes) Filter erstelle, kann ich in dem DGV alle sonstige DataGridViewTextBoxColumn ändern, ohne das die Row verschwindet, wenn ich eine andere Row anwähle.
    Im o. g. Filter kann ich z.B. im DGV das Datum in der Column "tbl_invoice_should_pay" außerhalb des Filters ändern und die Row bleibt im DGV, wenn ich den Focus der Row ändere

    Grundsätzlich klappt die Definition des Filters auch mit

    VB.NET-Quellcode

    1. BSInvoice.Filter = " AND tbl_invoice_paid = True AND tbl_invoice_should_pay <'" & Format(Date.Now, "yyyy-MM-dd") & "'"

    bzw.

    VB.NET-Quellcode

    1. DGVInvoiceDataView.RowFilter =" AND tbl_invoice_paid = True AND tbl_invoice_should_pay <'" & Format(Date.Now, "yyyy-MM-dd") & "'"


    Eine Google-Recherche hatte mir u. a. ein Ergebnis gebracht, worauf ich mir die Doku durchgelesen hatte, aber nichts fand (was evtl. an dem vorm Bildschirm lag): vbforums.com/showthread.php?65…18&viewfull=1#post4038718

    Ich denke, dass es an der DataGridViewCheckBoxColumn und dessen Verhalten beim Verlassen der aktuellen Row liegt, habe aber keinen Plan, wie ich das realisieren soll :(

    Ich würde mich sehr über Hilfe bei meinem Problem freuen.

    Viele Grüße,
    Laret

    P.S. Natürlich könnte ich die Source (DataTable) mit SQL vorfiltern. Ich möchte das aber wenn es geht vermeiden, da ich die Table nunmal bereits geladen habe (für neue Rechnungen, Statistik, etc).
    hier ein Bsp. mit der Tabelle Artikel aus der Nordwind Datenbank Access
    musste du etwas umstellen da dieses Bsp. nach dem Feld(Ja/Nein) Auslaufartikel
    sucht.
    Filter setzen kannst du mit der Textbox oder mit Checkbox

    VB.NET-Quellcode

    1. Imports System.Data.OleDb
    2. Public Class Form8
    3. Private objConnection As OleDbConnection
    4. Private objCommand As OleDbCommand
    5. Private objDataAdapter As OleDbDataAdapter
    6. Private objDataTable As DataTable
    7. Private objDataSet As DataSet
    8. '//Access Database::
    9. Private strConnectionString As String = _
    10. "Provider=Microsoft.Jet.OLEDB.4.0;" & _
    11. "Data Source=E:\Nordwind.mdb;"
    12. '--------------------------------------------------------
    13. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    14. objConnection = New OleDbConnection(strConnectionString)
    15. Dim sSQL As String = "Select ArtikelNr, Artikelname, Auslaufartikel From Artikel"
    16. Dim sWhere As String = Nothing
    17. 'mit Buchstabe nach Artikelname filtern
    18. If TextBox1.Text <> Nothing Then
    19. sWhere &= "And (Artikelname Like '" & TextBox1.Text & "%') "
    20. End If
    21. 'alle Auslaufartikel filtern = True
    22. If CheckBox1.CheckState = CheckState.Checked Then
    23. sWhere &= "AND Auslaufartikel = True"
    24. End If
    25. If sWhere <> Nothing Then
    26. sWhere = " Where " & sWhere.Substring(4)
    27. End If
    28. sSQL &= sWhere & " Order by Artikelname"
    29. MsgBox(sSQL)
    30. objDataAdapter = New OleDbDataAdapter(sSQL, objConnection)
    31. Dim builder As OleDbCommandBuilder = New OleDbCommandBuilder(objDataAdapter)
    32. objDataSet = New DataSet()
    33. objDataAdapter.Fill(objDataSet, "MyTable")
    34. DataGridView1.DataSource = objDataSet.Tables("MyTable").DefaultView
    35. objConnection.Close()
    36. objConnection = Nothing
    37. End Sub
    38. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    39. Me.Validate()
    40. Me.objDataAdapter.Update(Me.objDataSet.Tables("MyTable"))
    41. Me.objDataSet.AcceptChanges()
    42. End Sub


    mit Button2 werden dann alle änderungen übernommen

    prinzip ist gleich für alle DB's, nur die SQL kann unterschiedlich sein

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

    Hallo Kasi,
    zunächst vielen Dank für Deine Antwort!
    Du hast natürlich recht, dass ich mein Problem damit lösen kann, indem ich mir die Daten immer wieder aus der Datenbank hole.

    Ich hatte nur gedacht, ich könnte mir die Abfrage(n) Richtung Datenbank sparen, da ich ja bereits eine DataTable geladen habe :(

    Mich wundert es, dass ich in meinem Beispiel alle Inhalte in den Zellen ändern kann (mit Werten außerhalb eines Filters) und diese nach einem Verlassen der editierten Row noch im DGV bleiben - es bei einer Änderung in einer DataGridViewCheckBoxColumn dazu führt, dass die Spalte nach dem Verlassen (der Row - nicht der Cell) verschwindet. Hätte ich keinen Filter für eineDataGridViewCheckBoxColumn, würde mein Beispiel funktionieren und ich könnte nur mit der vorhandene (bereits geladende) DataTable arbeiten....hmm

    Ich werde noch ein bissl warten, ob mir evtl. noch jemand einen Tipp geben kann. Anonsten werde ich das gemäß Deinem Vorschlag realisieren (müssen).

    Nochmals Danke!
    VG, Laret
    wenn werte nicht geändert werden sollen dann stelle diese Columns auf ReadOnly = True

    gemäss...

    VB.NET-Quellcode

    1. '.......
    2. objDataAdapter = New OleDbDataAdapter(sSQL, objConnection)
    3. Dim builder As OleDbCommandBuilder = New OleDbCommandBuilder(objDataAdapter)
    4. objDataSet = New DataSet()
    5. objDataAdapter.Fill(objDataSet, "MyTable")
    6. DataGridView1.DataSource = objDataSet.Tables("MyTable").DefaultView
    7. With DataGridView1
    8. .Columns(0).ReadOnly = True
    9. .Columns(1).ReadOnly = True
    10. End With
    11. objConnection.Close()
    12. objConnection = Nothing



    EDIT:
    hast du dein Code mal so probiert

    VB.NET-Quellcode

    1. Dim dv As New DataView(DGVInvoiceDataView)
    2. DGVInvoiceDataView.RowFilter = " AND tbl_invoice_paid = True AND tbl_invoice_should_pay <'" & Format(Date.Now, "yyyy-MM-dd") & "'"
    3. DataGridView1.DataSource = dv

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

    Hallo Kasi,

    danke für Deine Antwort.

    Ich denke, dass Du mein Problem nicht verstanden hast (ich kann es wohl nicht richtig erklären)... Mein Problem ist nicht das Filtern, egal ob mit Bindingsource, DataView - das klappt alles. Mein Problem ist, das der Filter zuschlägt, wnn ich die gefilterten Daten verändere - und das NUR wenn die Änderung in einer DataGridViewCheckBoxColumn vorenommen wird.

    Wie ich ersten Post bereits schrieb, stelle man sich eine DGV mit gefilterten Daten (tbl_invoice_paid = False AND tbl_invoice_should_pay <'" & Format(Date.Now, "yyyy-MM-dd") & "'") vor:

    Column-Header: Rr.-Nr,, vom, Kunde, Betrag, Fälligkeit (Datum), ist bezahlt (mein Problem), wann bezahlt

    Das Ergebnis des Filters sind z. B. 5 "offene" Rechnungen
    Alle Spalten sind auf ReadOnly gesetzt, außer "ist bezahlt" und "wann bezahlt"

    Der Anwender guckt nun auf sein Konto und schaut nach, ob jemand eine Rechnung bezahlt hat. Wenn ja, markiert er die Checkbox der Spalte "ist bezahlt" und soll das Datum gemäß Zahlungseingang eingeben.

    Jetzt kommt mein Problem: Wenn der Anwender die Checkbox anklickt und sie auf True (bezahlt) setzt und dann mit der Maus eine neue Zeile anklickt, ist die Zeile, die er bearbeitet hat NICHT mehr im DGV zu sehen. Ich möchte aber, dass diese Zeile weiterhin im DGV bleibt, bis der Anwender fertig ist (er hat ja das Datum der Fälligkeit nch nicht eingegeben).

    Dieses Verhalten ist aber NUR bei einer DataGridViewCheckBoxColumn

    Wenn ich zum Testen (das soll nicht so bleiben, in diesem Beispiel habe ich ja nur die 2 Filterkriterien) die Column "Fälligkeit (Datum)" also "tbl_invoice_should_pay" auf ReadOnly = False setze und ändere dann im DGV das Datum, z.B. auf den 31.12.2030, dann bleibt diese Zeile auch im DGV, wenn ich eine andere Zeile anklicke. SO MÖCHTE ICH DAS AUCH MIT DER CHECKBOX HABEN!

    Viele Grüße, Laret
    jetzt kommt mein Problem: Wenn der Anwender die Checkbox anklickt und sie auf True (bezahlt) setzt und dann mit der Maus eine neue Zeile anklickt, ist die Zeile, die er bearbeitet hat NICHT mehr im DGV zu sehen.


    dann muss du dies abstellen ! du hast dann eine Anweisung das bei verlassen der CheckboxColumn eine Aktualisierung ausführt.

    erst Daten bearbeiten lassen dann die Aktualisierung
    Das Load-Ereignis ist das einigste in der Form. Was meinst Du denn mit "abstellen"?

    Naja, dennoch vielen Dank für Deine Bemühungen.

    Ich werde nun ein Filter schreiben, der die Daten immer wieder aus der DB liest - scheint wohl im Moment nicht anders zu gehen.

    VG, Laret
    "Abstellen" ist ja ein Wort, was Kasi eingeführt hat, und was in Bezug auf Filter nicht passend ist.
    Einen Filter kann man setzen, oder wegnehmen - also statt "abstellen" hätte ich besser "wegnehmen" gesagt.

    Aber was du brauchst, wäre ein "einfrieren" - also dass der Filter nicht sofort auf jede Datenänderung reagiert, sondern dass es eine Funktion geben müsste, die bewirkt, dass der Filter nur auf Aufforderung hin sich neu anwendet.



    Laret schrieb:

    Ich werde nun ein Filter schreiben, der die Daten immer wieder aus der DB liest
    Eine weniger invasive Alternative wäre, eine Ansicht zu coden, die die Daten statt aus der DB zu holen, einfach aus dem Dataset holt.

    ErfinderDesRades schrieb:

    "Abstellen" ist ja ein Wort, was Kasi eingeführt hat, und was in Bezug auf Filter nicht passend ist.
    Einen Filter kann man setzen, oder wegnehmen - also statt "abstellen" hätte ich besser "wegnehmen" gesagt.


    vielleicht wäre 'merken' das richtige wort.
    mann müsste eine Extension schreiben die 'gecheckte' Datensätze sich 'merkt', dann in einer
    zweiten Form mit Datagridview diese ausgewählten anzeigt.

    mit Bindingsource habe ich bisher wenig zutuen gehabt, wäre aber meiner Meinung nach
    eine Variante