BindingSource-Objekt auf "Nichts" setzen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von VB2021Aug.

    BindingSource-Objekt auf "Nichts" setzen

    Zwei DataGridViews sind je an ein BindingSource gebunden. (DataSet + Tabelle) (und ein paar Textfelder ebenfalls)
    Wenn ich im DGV1 (Mitarbeiter) einen Eintrag wähle, kann ich im BindingSource-CurrentChanged nach einem bestimmten Feldwert fragen und diesen in der BindingSource der DGV2 suchen und selectieren.
    Funktioniert! DGV2 und Textfelder werden aktualisiert.

    Jetzt hat der Feldwert in einigen Fällen noch keinen Inhalt (DBNull) und hier möchte ich über das BindingSource-Objekt ein "ClearSelection" auslösen.
    Ich könnte das für das DGV2 (Dienststellen) machen, aber es gibt da einige Textfelder, welche Detaildaten zeigen und die bekommen vom ClearSelection des DGV2 nichts mit.

    VB.NET-Quellcode

    1. Private Sub BSMitarbeiter_CurrentChanged(sender As Object, e As EventArgs) Handles BSMitarbeiter.CurrentChanged
    2. Dim index As Integer
    3. index = Me.BSDienststelle.Find("ID", BSMitarbeiter.Current("DienststellenNr").ToString)
    4. If index > -1 Then
    5. Me.BSDienststelle.Position = index
    6. Else
    7. Me.Dienststellen.ClearSelection() ' Hier würde ich gern mit der BindingSource (BSDienststellen) arbeiten?
    8. End If
    9. End Sub


    Kleine Besonderheit: Eine Auswahl im DGV1-Mitarbeiter soll einen Standardwert aus der DGV2-Dienststellen auswählen, trotzdem soll es möglich sein,
    ad hoc eine andere Dienststelle zu wählen, ohne dabei den Standardwert des Mitarbeiters zu ändern. Also A -> B aber nicht B -> A
    Es soll also keine "ComboBox-join-Beziehung" hergestellt werden.
    Genau genommen sollten auch alle TextBoxen so funktionieren. (In WPF gibt es solche "Einmal einlesen" oder "Nur lesen" bzw. "Nur schreiben" Bindungen, in WinForms auch?)

    Danke für alles Mitdenken!
    ClearSelection hat keinen Einfluss auf die BindingSource. Daher werden auch DGV2 und die TextBoxen (oder welche Controls Du auch immer verwendest bzw. mit »Textfelder« meinst) nicht beeinflusst. Die Änderung bei DGV2/Textfeld-Inhalten funktioniert nur deshalb, weil indirekt durch die DGV1-Selektionsänderung die BS-Position beeinflusst wird. Um jetzt den gewünschten Effekt zu erzielen, müsstest Du z.B. schreiben:
    BSDienststellen.DataSource = New List(Of DerTypDerMitDerBsEigentlichGekoppeltIst).

    Zum 2. Problem: Wenn Du bei DGV2 in den Properties bei DataBinding auf Erweitert […] klickst, kannst Du Dein DataBinding raussuchen und rechts einstellen, wann Daten in der Datenquelle aktualisiert werden sollen: OnPropertyChanged, OnValidation, Never
    Bilder
    • ExtendedDataBinding.png

      62,02 kB, 1.184×532, 125 mal angesehen
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo und Vielen Dank!

    Ich vermute, du bist in deiner Antwort auf die TextFeld-Aktualisierung eingegangen. (2.Problem)

    Meine erste Frage:

    VB.NET-Quellcode

    1. Me.BSDienststelle.Position = Nix


    Kann ich sowas machen? Habe das mal mit -1 probiert, hat aber nichts gebracht.
    Nein, ich bin auf beide Probleme eingegangen.
    Das Setzen der BS-Position führt nicht zum Ziel.
    Um mit einer BS auf ein Nichts zu zeigen, musst Du dieser ein passendes Nichts als Datenquelle geben. Aber nicht Nothing, sondern eben BSDienststellen.DataSource = New List(Of DerTypDerMitDerBsEigentlichGekoppeltIst)
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    OK,
    soweit verstanden!
    Die Zuweisung als New List(Of...) ist etwas schwierig (für mich) da ich die DataTable aus einem typisierten DataSet hole, also eigentlich keinen Typ Dienststellentabelle habe.
    (konnte keinen im Quellcode finden) Das DataSet fummelt sich das aus einer .xsd-Datei zusammen.
    (sorry, aber ich nutze die "Klick-Funktionen" von Visual-Studio, da ist der Code nicht immer optimal, aber als Anfänger erhalte ich zunächst ein Ergebnis)

    Würde die Zuweisung einer leeren Bindingsource dann nicht auch die komplette DGV2 löschen? Ich will ja nur, dass "Nix" ausgewählt wird.

    Ich werde wohl etwas "Tricksen" und ans Ende einen "Dummy-Eintrag", mit leeren Feldern anfügen. Das entspricht zwar nicht dem DGV2.ClearSelection,
    ich habe dafür ein echtes "Nichts", welches ich aktiv zuweisen kann.

    PS: Genau genommen bin ich vom Konzept DataSet ziemlich enttäuscht.
    Es ist nur eine Exceldatei mit zwei Tabellen und 20 / 10 Datensätzen. Fülle ich direkt ein ListView (auch DataGridView ohne Bindung) öffnet sich das Fenster praktisch verzögerungsfrei.
    Mit DataSet -> BindingSource -> DataGridView dauert es 4 bis 6 Sekunden, bevor sich überhaupt etwas zeigt.
    Natürlich ist die Synchronisation der einzelnen Controls mit Bindung viel einfacher, aber so eine Wartezeit wegen 30 Datensätzen - das kann ich niemandem zumuten.
    (Ich habe auch vor dem Befüllen die Bindingsource-Aktualisierung Suspended, hat aber auch keinen bedeutenden Unterschied gebracht.)
    Vermutlich dauert nicht das Laden der Daten so lange, sondern die Erzeugung der Tabellen und Abhängigkeiten.
    Aha, so ist's also. Ein tDS. Das ändert die Sache etwas. Dann kannst Du es so probieren:
    BSDienststellen.DataSource = New List(Of DeinTds.DienststellentabelleRow)

    Das mit der Verzögerung ist eine Frage der korrekten Codeverwendung, nicht der Sache an sich. Wenn man es richtig macht, ist das alles sehr schnell erledigt. 4-6 Sekunden ist vollkommen indiskutabel langsam und nicht normal. Sind Dgv-Spaltenbreitenmodi auf AllCells gestellt? Was in Code ist Bindingsource-Aktualisierung Suspended?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed

    Danke! Das mit dem List(Of ...) habe ich jetzt verstanden.
    Das ist aber nicht ganz meine Lösung: Wenn ich dem BindingSource-Objekt eine leere DataSource zuweise, dann verschwindet der Inhalt des DGV2 (was eigentlich logisch ist).

    Ich versuch's mal in Worten mit einem kleinen Beispiel:
    Ein Person (Tabelle (DGV1) hat ein Datenfeld "Lieblingsschuhe" z.B. "Filzpantoffel", wählt man die Person aus, dann springt der Cursor / Selection in Tabelle2 DGV2 entsprechend zu "Filzpantoffel".
    Die Beziehung ist aber nur einseitig, d.h. es sind eben nur die Lieblingsschuhe, wenn es regnet möchte die Person heute mal Gummistiefel anziehen. (Auswahl in Tabelle 2 schreibt keine Daten in die Person)
    Mein Problem von oben: Manche Personen haben zu ihren Lieblingsschuhen keine Angaben gemacht, also soll in Tabelle 2 nichts ausgewählt werden,
    umgekehrt sollen sie nicht dazu "verdammt sein" barfuß bleiben zu müssen :D

    Geschwindikeit inakzeptabel: Ja, das sehe ich auch so!
    Tatsächlich haben meine DataGridView jeweils nur eine einzige Spalte, deren Collumn With auf Fill steht. Die übrigen Datenfelder werden über das BindingSource-Objekt verwaltet. (Spart mir die Suche nach "ID={Nummer}")

    Zum Füllen des / der DataSet habe ich den Code übernommen, mit dem ich in "Null Komma Nix" meine ListView's gefüllt hatte.

    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. Me.BSMitarbeiter.SuspendBinding() ' Damit sollen alle Objekte (TextBox, DataGridView... von der Aktualisierung abgehängt werden (später "in einem Rutsch")
    3. dim conn = New ADODB.Connection
    4. dim rs = New ADODB.Recordset
    5. Dim sql As String
    6. Dim Row As DataRow ' Statt allgemein As DataRow habe ich auch probiert As dsMitarbeiterDaten.dtMitarbeiterRow - hat keinen Unterschied in der Geschwindigkeit gemacht.
    7. Dim Feld
    8. Dim FeldName As String
    9. DBPath = "C:\Projekt\Daten.xlsx"
    10. connectionString = "Provider=MSDASQL.1;DSN=Excel Files;DBQ=" & DBPath & ";HDR=Yes';"
    11. conn.Open(connectionString)
    12. sql = "SELECT * From [Mitarbeiter$]"
    13. rs.Open(sql, conn, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockReadOnly)
    14. With Me.DsMitarbeiterdaten.dtMitarbeiter
    15. Do While Not rs.EOF
    16. Row = .NewRow()
    17. For Each Feld In rs.Fields
    18. Try ' Auf diese Weise könnte meine Excel-Tabelle Felder enthalten, die nicht zu meinem DataSet passen, die werden einfach in einem leeren Catch übersprungen
    19. FeldName = Feld.Name
    20. Row(FeldName) = Feld.value
    21. Catch
    22. End Try
    23. Next
    24. .Rows.Add(Row)
    25. rs.MoveNext()
    26. Loop
    27. End With
    28. rs.Close()
    29. Me.BSMitarbeiterdaten.ResumeBinding() ' Und jetzt alle Objekte auf der Oberfläche aktualisieren
    30. End Sub


    Kein Unterschied Row As DataRow oder Row As dsMitarbeiterdaten.dtMitarbeiterRow
    Ist weiterhin "Inakzeptabel"!

    VB2021Aug schrieb:

    Mein Problem von oben: Manche Personen haben zu ihren Lieblingsschuhen keine Angaben gemacht, also soll in Tabelle 2 nichts ausgewählt werden
    Wie gesagt: "Nichts anwählen" geht nicht.
    Ich füge in solchen Fällen einen zusätzlichen Default-Datensatz ein, der "Keine Angabe" aussagt.
    Der wird dann angewählt.
    Zur Geschwindigkeit: Bau doch mal ne Performancemessung ein. Am Ende scheitert's vielleicht an dem Try-Catch. Exceptionthrowing ist heavy.

    Zum DGV2-Schuhbeispiel: Wenn jemand keine Lieblingsschuhe ausgewählt hat, ist dann eine Fortsetzung des Programms überhaupt zulässig?
    Ich weiß, ist kein DGV, aber vielleicht kommt ja die Benutzung meiner ClearableComboBox infrage.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    OK,
    dann lag ich mit meinem

    VB2021Aug schrieb:

    Ich werde wohl etwas "Tricksen" und ans Ende einen "Dummy-Eintrag", mit leeren Feldern anfügen.

    ja gar nicht so falsch.
    Das beruhigt ja auch schon mal :thumbsup:

    Das Geschwindigkeitsproblem lässt sich wohl nicht so leicht lösen.
    Außer dass ich ADODB statt OLEDBConnection nutze und im DataSet dann die Fill-Methode verwenden könnte.
    Aber 5 Sekunden bis 30 Datensätze geladen sind und das Programm startet - Ne, geht wirklich nicht!



    VaporiZed
    habe mir gerade dein Beispiel angeschaut. Nun offensichtlich hatten andere auch schon mal so ein Problem!
    Im DataGridView gibt es "ClearSelection()", das entspricht in etwa deinem Projekt.
    Wären da nicht die 10 Textfelder, die mit dem DGV in Beziehung stehen. DataBinding macht das sehr einfach.
    Ich habe probiert, das alles zu Fuß zu erledidgen - ein furchtbarer Spaghetti-Code. Und jedes SelectedItemsChanged kommt immer zuerst mit einem Nothing (alter Eintrag löschen)
    bevor ein zweites Event das neuen Item liefert.
    DataBinding hätte so schön sein können :/

    Auf Try Catch verzichten? OK, das ist eine Idee, Ich wede das DataSet überarbeiten und die vorgabe <DBNull> etwa auf <String.empty> setzen, so kann ich evtl. Fehler beim Einlesen vermeiden.
    Es hatte ja einen Grund, warum ich das Try Catch geschrieben hatte ;)

    Liebe Grüße an meine fleißigen "Mitdenker"!

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

    An alle, die dieses Thema lesen und an der Lösung interessiert sind.

    Das mit dem DataSet auf "Nix" setzen haben wir ja geklärt. Geht nicht!
    Mit einem Dummy-Datensatz kann man sich behelfen.
    (Solange der Anwender nur lesen und auswählen kann, ist alles OK. Wenn der Anwender auch eigene Werte eintragen darf, dann muss man an dem Konzept noch etwas feilen.
    z.B. - Dummy als erster Datensatz, damit der Anwender ans Ende der Tabelle schreiben kann.
    - Schreibschutz für den Dummy
    - evtl. die Zeilenhöhe für den Dummy auf 0 setzen - OwnerDraw?)

    Geschwindigkeit beim Laden:
    Meine Excel-Datei hat zwei Tabellen (9 Spalten x 19 Datensätze) (11 Spalten x 11 Datensätze). Als gewaltige Datenmenge kann man das wirklich nicht bezeichnen!
    Beim Einlesen der Daten habe ich jedes Feld in einen Try Catch Block gekapselt (s.o.), macht im Beispiel 292 Try Catch'es und offensichtlich mein Zeitproblem.
    Ohne diese bekomme ich zwar jedesmal eine Fehlermeldung (was ich noch beheben muss). dafür startet das Programm so schnell wie erwartet. - Fehler gefunden!

    Ob das klassische "On Error goto" weniger Zeitprobleme verursacht?
    Oder ich muss im SQL-Befehl die Tabelle statt mit "SELECT * FROM Tabelle", mit "SELECT Spalte1, Spalte2, ...." einlesen, so kann ich auf meine Fehlerbehandlung auch verzichten.

    Seid gegrüßt und viel Erfolg bei euren Projekten!