Verständnisproblem Bindingsource Verhalten der Combobox

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

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Schoofi.

    Verständnisproblem Bindingsource Verhalten der Combobox

    Ich habe ein Hauptformular mit diversen Comboboxen nach deren Inhalt gesucht werden kann.Aufgrund des Suchergebnisses werden dann die betroffenen Formulare geöffnet.
    Wenn ich im Unterformular im dtrowNutzer Änderungen vornehme wird sofort selectedindexchanged ausgelöst. Dabei reicht die Zuweisung, ich muß noch nicht mal ein bsNutzer.endedit ausgelöst haben.
    In der Combobox selber bleibt interessanterweise der vorher eingestellte Wert erhalten, in der Bindingsource des Nutzerformulars wechselt die Bindingsourceposition, wobei es so aussieht als ob er den aktuellen Datensatz nicht findet.
    Setze ich die Werte im Formular (wovon ja im Forum abgeraten wird) tritt dieser Effekt nicht auf.
    bsNutzer.Position gibt 0 zurück.

    Beim speichern könnte ich ja das Vehalten der Combobox noch nachvollziehen, deswegen schalte ich da vorher den Handler von Selectedindex_changed aus.
    Wie kann ich das Problem lösen ?

    Hauptformular:

    Quellcode

    1. sub new
    2. Me.Rechnerliste = dsRechnerliste_be.GetInstance
    3. Rechnerliste.FuelleAlleTabellenRechnerliste(clsServerini.Anwendung("Rechnerliste_be"))
    4. Me.bsNutzer.DataSource = Me.Rechnerliste
    5. Me.cboSucheNutzer.SelectedIndex = -1
    6. end sub
    7. Public Sub HandlerAktivate()
    8. AddHandler Me.cboSucheNutzer.SelectedIndexChanged, AddressOf cboSucheNutzer_SelectedIndexChanged
    9. end sub
    10. Private Sub cboSucheNutzer_SelectedIndexChanged(sender As Object, e As EventArgs)
    11. With Me.cboSucheNutzer
    12. RemoveHandler .SelectedIndexChanged, AddressOf cboSucheNutzer_SelectedIndexChanged 'verhindert das AutoCompleteMode.Suggest TextChanged nochmal aufruft
    13. If .SelectedIndex > -1 Then
    14. AufrufNutzerformular(CInt(.SelectedValue))
    15. End If
    16. .AutoCompleteMode = AutoCompleteMode.SuggestAppend
    17. AddHandler .SelectedIndexChanged, AddressOf cboSucheNutzer_SelectedIndexChanged
    18. End With
    19. End Sub
    20. Private Sub AufrufNutzerformular(parintID_Nutzer As Integer)
    21. If frmDPNutzer Is Nothing Then
    22. Dim frmdpNutzer As New frmDPNutzer
    23. End If
    24. With frmDPNutzer
    25. .ID_Nutzer = parintID_Nutzer
    26. .Show()
    27. .BringToFront()
    28. .Left = Me.Location.X
    29. .Top = Me.Location.Y + Me.Size.Height
    30. .Width = Me.Width
    31. End With
    32. End Sub


    Formular Nutzer

    Quellcode

    1. Dim dtrowNutzer As dsRechnerliste_be.tbl_NutzerRow
    2. Sub New()
    3. InitializeComponent()
    4. Dim lstPflichtfeld As New List(Of Control)(New Control() {Me.txtNachname, Me.txtVorname, Me.cboKostenstelle, Me.cboApl})
    5. clsFormular.lstPflichtfelder = Me.lstPflichtfeld
    6. clsFormular.Formularstatus(False)
    7. Me.Rechnerliste = dsRechnerliste_be.GetInstance
    8. Me.bsAekzNutzer.DataSource = Rechnerliste
    9. Me.bsArbeitsplatz.DataSource = Rechnerliste
    10. Me.bsKostenstelle.DataSource = Rechnerliste
    11. Me.bsProtokolle_Nutzer.DataSource = Protokolle
    12. Me.bsNutzer.DataSource = Rechnerliste
    13. End Sub
    14. Private _ID_Nutzer As Integer
    15. public Property ID_Nutzer() As Integer
    16. Get
    17. Return _ID_Nutzer
    18. End Get
    19. Set(ByVal value As Integer)
    20. _ID_Nutzer = value
    21. Me.bsNutzer.Position = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, value)
    22. End Set
    23. End Property
    24. Private Sub bsNutzer_CurrentChanged(sender As Object, e As EventArgs) Handles bsNutzer.CurrentChanged
    25. If dtrowNutzer IsNot Nothing AndAlso Not dtrowNutzer.RowState = DataRowState.Deleted Then
    26. With dtrowNutzer
    27. If .RowState <> DataRowState.Unchanged Then
    28. Select Case MessageBox.Show("Sie haben den Nutzer " & dtrowNutzer.Nutzername & " geändert. Soll dieser gespeichert werden ?", "Speichern ?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
    29. Case DialogResult.Yes
    30. Speichern()
    31. Case DialogResult.Cancel
    32. Me.bsNutzer.Position = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, dtrowNutzer.ID_Nutzer)
    33. End Select
    34. End If
    35. End With
    36. End If
    37. Dim dv As DataRowView = DirectCast(Me.bsNutzer.Current, DataRowView)
    38. dtrowNutzer = DirectCast(dv.Row, dsRechnerliste_be.tbl_NutzerRow)
    39. End Sub
    40. Sub NamenBilden()
    41. With dtrowNutzer
    42. If .Nachname > String.Empty AndAlso .Vorname > String.Empty Then
    43. If .Mittelinitial > String.Empty Then
    44. .BKUAnmeldename = String.Concat(.Vorname.Umlauteersetzen, .Mittelinitial, .Nachname.Umlauteersetzen) 'Hier wird selectedindex_changed ausgelöst
    45. .Mailintern = String.Concat(.Vorname, " ", .Mittelinitial, " ", .Nachname)
    46. .Mailextern = String.Concat(.Vorname.Umlauteersetzen, ".", .Mittelinitial, ".", .Nachname.Umlauteersetzen)
    47. Else
    48. .BKUAnmeldename = String.Concat(.Vorname.Umlauteersetzen, .Nachname.Umlauteersetzen)
    49. .Mailintern = String.Concat(.Vorname, " ", .Nachname)
    50. .Mailextern = String.Concat(.Vorname.Umlauteersetzen, ".", .Nachname.Umlauteersetzen)
    51. End If
    52. .BKUAnmeldename = .BKUAnmeldename.Replace("-", "")
    53. Dim dtrowsAnwendungNutzer As dsRechnerliste_be.tbl_A_Anwendung_NutzerRow() = dtrowNutzer.Gettbl_A_Anwendung_NutzerRows
    54. End With
    55. End Sub
    Ich kam jetzt, um das Problem zu umgehen, auf die Idee einfach beim Initialisieren des Formulars die Bindingsource mit zu übergeben.
    Die Bindingsource zeigt auch im aufrufenden Formular 174 Datensätze an, allerdings bleibt das Formular leer.
    Weise ich vorher das Dataset zu ist das Formular zwar gefüllt, zeigt aber die falsche Zeile an.
    Woran liegt das ?
    Es wäre alles ein gutes Stück leichter, wenn Du:
    1. statt den allgemeinen Code-Tags die VB.Net-Tags verwenden würdest. Dann wäre ein gewissen Syntax-Highlighting da.
    2. weniger mit Variablennamen als mehr mit deren Typen erklären würdest.
    3. statt das Problem durch Anzeige des Gesamtcodes versuchst, das Problem für uns einzudampfen. Ich hab jetzt 3x versucht, mich durch Deinen Code zu wurtscheln, um zu antworten, aber es vergeht mir jedes mal wieder die Lust.

    Sieht vielleicht der ein oder andere hier anders und freut sich über soviel Info, aber ich gehör leider nicht dazu.

    Du hast 2 Formulare. Form1 ruft Form2 auf. Und wie geht's dann bitte weiter? Was hast Du für CEs auf Form2? Was machst Du auf Form2, was Dir komisch vorkommt?
    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.
    Sorry, da hatte die VB.net Tags übersehen.
    Ich habe mal versucht weiter einzustampfen und die richtigen Tags gesetzt

    Hauptformular:
    Im Hauptformular existiert eine Combobox cboNutzersuche die an die Bindingsource bsNutzer gebunden ist.
    Beim Auswählen eines Wertes über cboSucheNutzer_SelectedIndexChanged(sender As Object, e As EventArgs) wird ein weiteres Formular frmDpNutzer geöffnet und der im Hauptformular ausgewählte Datensatz angezeigt.

    VB.NET-Quellcode

    1. sub new
    2. Me.Rechnerliste = dsRechnerliste_be.GetInstance
    3. Rechnerliste.FuelleAlleTabellenRechnerliste(clsServerini.Anwendung("Rechnerliste_be"))
    4. Me.bsNutzer.DataSource = Me.Rechnerliste
    5. Me.cboSucheNutzer.SelectedIndex = -1
    6. end sub
    7. Public Sub HandlerAktivate()
    8. AddHandler Me.cboSucheNutzer.SelectedIndexChanged, AddressOf cboSucheNutzer_SelectedIndexChanged
    9. end sub
    10. Private Sub cboSucheNutzer_SelectedIndexChanged(sender As Object, e As EventArgs)
    11. With Me.cboSucheNutzer
    12. RemoveHandler .SelectedIndexChanged, AddressOf cboSucheNutzer_SelectedIndexChanged 'verhindert das AutoCompleteMode.Suggest TextChanged nochmal aufruft
    13. If .SelectedIndex > -1 Then
    14. AufrufNutzerformular(CInt(.SelectedValue))
    15. End If
    16. .AutoCompleteMode = AutoCompleteMode.SuggestAppend
    17. AddHandler .SelectedIndexChanged, AddressOf cboSucheNutzer_SelectedIndexChanged
    18. End With
    19. End Sub
    20. Private Sub AufrufNutzerformular(parintID_Nutzer As Integer)
    21. If frmDPNutzer Is Nothing Then
    22. Dim frmdpNutzer As New frmDPNutzer
    23. End If
    24. With frmDPNutzer
    25. .ID_Nutzer = parintID_Nutzer
    26. .Show()
    27. End With
    28. End Sub


    Formular frmDPNutzer

    Dieses Formular bekommt aus dem Hauptformular die ID_Nutzer als Integer übergeben und sucht die Bindingsourceposition auf Grund dieser ID.
    Danach wird die gefundene Bindingsource.current in die Datarow dtrowNutzer gecastet.
    Beim Ändern der Namensbestandteile Vorname, Nachname und Mittelinitial (alles gebundene Textboxen) werden der BKUAnmeldename und die Mailadressen gebildet und in das datarow dtrowNutzer übernommen.
    Bei dieser Zuweisung wird im Hauptformular Selectedindexchanged ausgelöst. Hier stellt sich die Frage warum, zumal hier nur die Zuweisungen erfolgen und noch nicht gespeichert wird. ?
    Er übergibt an das Formular frmDPNutzer die richtige ID_Nutzer, dort ist sie aber scheinbar nicht mehr in der Bindingsource enthalten.Als Position wird -1 ermittelt.

    VB.NET-Quellcode

    1. Dim dtrowNutzer As dsRechnerliste_be.tbl_NutzerRow
    2. Sub New()
    3. InitializeComponent()
    4. Me.Rechnerliste = dsRechnerliste_be.GetInstance
    5. Me.bsNutzer.DataSource = Rechnerliste
    6. End Sub
    7. Private _ID_Nutzer As Integer
    8. public Property ID_Nutzer() As Integer
    9. Get
    10. Return _ID_Nutzer
    11. End Get
    12. Set(ByVal value As Integer)
    13. _ID_Nutzer = value
    14. dim intPos as integer
    15. intpos= = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, value)
    16. Me.bsNutzer.Position=intpos
    17. End Set
    18. End Property
    19. Private Sub bsNutzer_CurrentChanged(sender As Object, e As EventArgs) Handles bsNutzer.CurrentChanged
    20. If dtrowNutzer IsNot Nothing AndAlso Not dtrowNutzer.RowState = DataRowState.Deleted Then
    21. With dtrowNutzer
    22. If .RowState <> DataRowState.Unchanged Then
    23. Select Case MessageBox.Show("Sie haben den Nutzer " & dtrowNutzer.Nutzername & " geändert. Soll dieser gespeichert werden ?", "Speichern ?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
    24. Case DialogResult.Yes
    25. Speichern()
    26. Case DialogResult.Cancel
    27. Me.bsNutzer.Position = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, dtrowNutzer.ID_Nutzer)
    28. End Select
    29. End If
    30. End With
    31. End If
    32. Dim dv As DataRowView = DirectCast(Me.bsNutzer.Current, DataRowView)
    33. dtrowNutzer = DirectCast(dv.Row, dsRechnerliste_be.tbl_NutzerRow)
    34. End Sub
    35. Sub NamenBilden()
    36. With dtrowNutzer
    37. .BKUAnmeldename = String.Concat(.Vorname.Umlauteersetzen, .Mittelinitial, .Nachname.Umlauteersetzen) 'Hier wird selectedindex_changed ausgelöst
    38. End With
    39. End Sub
    3 Punkte, bevor ich tiefer in den Kaninchenbau reingehe:

    VB.NET-Quellcode

    1. If frmDPNutzer Is Nothing Then
    2. Dim frmdpNutzer As New frmDPNutzer
    3. End If
    4. With frmDPNutzer
    5. .ID_Nutzer = parintID_Nutzer
    6. .Show()
    7. End With

    Zeile#2 ist Quark. Du legst eine lokale Variable an, die nicht weiter verwendet wird. Was Du wohl meinst, ist frmdpNutzer = New frmDPNutzer, damit Du jene neuinstanziierte Variable dann in Z#4 weiternutzen kannst.
    2. Z#15 in CodeBlock#2: inpos= = ?(
    3. Was ist dsRechnerliste_be? Wahrscheinlich Dein typ. DataSet. Nur ist die Frage, ob es immer dasselbe tDS (was richtig wäre) ist oder nur das gleiche (wäre falsch, da dann falsche Daten drin sind). Wie ist dsRechnerliste_be genau definiert? Ist GetInstance eine Methode von Dir?
    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.
    Danke für Deine Antwort.
    Bei Zeile 2 hast Du Recht, im Quellcode hatte ich es schon korrigiert, steht so drin wie Du vorgeschlagen hast.
    Zeile 15 im Codeblock dient zum Setzen der Bindingsourceposition. Mit der Zwischenvariable wollte ich nur austesten was wirklich zurückgegeben wird.
    Bei direkter Zuweisung stand die Position auf 0.

    VB.NET-Quellcode

    1. dim intPos as integer
    2. intpos= = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, value)
    3. Me.bsNutzer.Position=intpos


    dsRechnerliste ist das typisierte Dataset und Getinstance stellt sicher das immer auf die gleiche Instance zugreift.

    VB.NET-Quellcode

    1. 'Gobal verfügbar machen
    2. Private Shared instance As dsRechnerliste_be = Nothing
    3. ' Hilfsvariable für eine sichere Threadsynchronisierung.
    4. Private Shared ReadOnly mylock As New Object()
    5. ' Konstruktor ist privat, damit die Klasse nur aus sich selbst heraus instanziiert werden kann.
    6. ' Diese Shared-Methode liefert die einzige Instanz der Klasse zurück.
    7. Public Shared Function GetInstance() As dsRechnerliste_be
    8. SyncLock (mylock)
    9. If instance Is Nothing Then
    10. instance = New dsRechnerliste_be
    11. End If
    12. End SyncLock
    13. Return instance
    14. End Function
    eigentlich nicht, das ist ja das was ich nicht verstehe.Es werden keine Primärschlüssel geändert, kein Datensatz hinzugefügt und keiner entfernt.
    Eins ist allerdings noch auffällig. Bei selectedindexchanged wird in der Bindingsource des Unterformulars nach der ID_Nutzer gesucht

    VB.NET-Quellcode

    1. intpos= = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, value)

    intpos ergibt dann -1 obwohl der Datensatz im Datagridview, welches ich um den Sachverhalt nachzuvollziehen eingebaut habe, vorhanden ist.

    Das Verhalten beobachte ich erst seit ich das Dataset umprogramnmiert habe. Eventuell könnte auch hier ein Zusammenhang bestehen.
    Grund für die Änderung war, das ich im Hauptformular entscheide, von wo aus ich die Datenbank hole.
    Beim Anpassen des Connectionstrings wurde aus der einen Datenquelle gelesen und in die andere geschrieben.
    Die Originalzeile der Zuweisung im Tableadaptermanager sah so aus.

    VB.NET-Quellcode

    1. admRechnerliste.tbl_NutzerTableAdapter=New tbl_NutzerTableAdapter


    neu nutze ich dafür den vorhandenen Tableadapter mit dem ich auch die Tabelle fülle. siehe unten.
    Ich habe mal alle aus meiner Sicht für den Sachverhalt relevanten Codezeilen angehängt.

    Aktualisierung Primärschlüssel.
    Da ich mir den Datasetcode mit einer selbstgeschriebenen Routine generieren lasse, ist dieser universell einsetzbar.
    Deshalb auch die Prüfung ob der Typ Integer( für typische ID) ist, in anderen Fällen darf er nicht geholt werden.

    VB.NET-Quellcode

    1. Partial Class tbl_NutzerTableAdapter
    2. Private _IdentityCommand As New OleDbCommand("SELECT @@IDENTITY")
    3. Private Sub _RowUpdated(ByVal sender As Object, ByVal e As OleDbRowUpdatedEventArgs) Handles _adapter.RowUpdated
    4. If e.StatementType = StatementType.Insert Then
    5. _IdentityCommand.Connection = e.Command.Connection
    6. _IdentityCommand.Transaction = e.Command.Transaction
    7. If _IdentityCommand.ExecuteScalar().GetType.Equals(GetType(Integer)) Then
    8. e.Row(e.Row.Table.PrimaryKey(0)) = CInt(_IdentityCommand.ExecuteScalar())
    9. End If
    10. End If
    11. End Sub
    12. End Class


    Zuweisung zur entsprechenden Datenbank, füllen der Tabelle und Eintrag in den Tabledaptermanager

    VB.NET-Quellcode

    1. Dim admRechnerliste As New TableAdapterManager
    2. Const conProvider = "Provider=Microsoft.Jet.OLEDB.4.0;"
    3. Private _strDBRechnerliste As String
    4. Public Property DBRechnerliste() As String
    5. Get
    6. Return _strDBRechnerliste
    7. End Get
    8. Set(ByVal value As String)
    9. _strDBRechnerliste = value
    10. cnstrRechnerliste = String.Concat("", conProvider, "Data Source=", DBRechnerliste, "")
    11. End Set
    12. End Property
    13. Private _cnstrRechnerliste As String
    14. 'ConnectionString zurückgeben
    15. Public Property cnstrRechnerliste() As String
    16. Get
    17. Return _cnstrRechnerliste
    18. End Get
    19. Set(ByVal value As String)
    20. _cnstrRechnerliste = value
    21. End Set
    22. End Property
    23. 'tbl_Nutzer
    24. Private daNutzer As New tbl_NutzerTableAdapter
    25. Public Sub FuelleTabelleNutzer()
    26. daNutzer.Connection.ConnectionString = cnstrRechnerliste
    27. daNutzer.Fill(tbl_Nutzer)
    28. admRechnerliste.tbl_NutzerTableAdapter = Me.daNutzer
    29. End Sub
    30. Public Sub daNutzerUpdate()
    31. daNutzer.Update(tbl_Nutzer)
    32. End Sub

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

    Auch wenn es nix mit dem Problem zu tun hat. Da Du zum 3. Mal

    VB.NET-Quellcode

    1. intpos= = Me.bsNutzer.Find(Rechnerliste.tbl_Nutzer.ID_NutzerColumn.ColumnName, value)
    erwähnst und ich das schon in Post#5 anmarkerte: Dass da zum Anfang ein doppeltes = drin ist, was syntaktisch falsch ist, ist Dir schon aufgefallen, oder?

    Schoofi schrieb:

    dsRechnerliste ist das typisierte Dataset und Getinstance stellt sicher das immer auf die gleiche Instance zugreift.
    die selbe. Es ist die selbe. Das ist wichtig. Aber sei's drum. Ok, dann ist das schon mal klar.
    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.
    Danke, das doppelte Gleichheitszeichen war mir gar nicht aufgefallen, hatte mich schon gewundert, was Du bei der Frage nach der Zeile meintest. Da war ich betriebsblind.
    Das war aber auch nur ein Tippfehler im Forum, der beim Kürzen des Codes reingeraten war.
    Ich mußte mein Projekt dank eines "unknown harderrors" erstmal wieder zurücksichern, das ich nachsehen konnte.
    Ich hatte schon Hoffnung, das das Fehlen der Datarow im Bindingsource nur auf den Schreibfehler zurückzuführen war, aber im Projekt ist es richtig geschrieben.