none
Combobox zeigt Inhalt doppelt an RRS feed

  • Frage

  • Hallo Zusammen,
    ich habe eine VB2008 Windowsanwendung, in der ich eine Combobox aus einer Abfrage auf eine Access 2010 Tabelle (A_Kategorie auf Tabelle Kategorie) anzeigen will.

    Nun zeigt mir diese Combobox jedesmal den gerade ausgewählten Text zweimal an. Dafür werden nicht alle Datensätze angezeigt. Das ist für den Anwender etwas verwirrend.

    Die Combobox hat folgende Eigenschaften:
    Text: A_KategorieBindingSource - Kategorie
    DataSource: A_KategorieBindingSource
    DisplayMember: Kategorie
    ValueMember: Kategorie

    Ich möchte anschließend die Combobox als Auswahlmöglichkeit nutzen, um über ein Textfeld ein Feld einer anderen Tabelle zu ändern. Das klappt, nachdem gespeichert wurde.

    SelectedValue: BuecherBindingSource - Kategorie

    Anzeige in der Combobox: 
    Historisch
    Unterhaltung
    Historisch
    Frauenroman
    Sachbuch
    Historisch
    Krimi

    Inhalt der Tabelle bzw. Abfrage:
    Thriller
    Krimi
    Frauenroman
    Sachbuch
    Unterhaltung
    Historisch

    Ich komme nicht drauf, was ich falsch mache :-(

    Wenn ihr vielleicht einen Tipp für mich habt?
    Vielen Dank und schöne Grüße
    Christina


    Donnerstag, 23. August 2012 14:03

Antworten

  • Hallo Michael,

    dann hat man euch leider zu wenig und auch falsches beigebracht.
    Insbesondere ist ein absolutes NO GO:

    If reader.HasRows = False Then
    Exit Sub
    End If

    Damit werden Reader und Connection nicht geschlossen, was auf Dauer Probleme nach sich ziehen kann. Eine überarbeitete Variante:

        Private Sub DatenLesen()
            Const constr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccess2007file.accdb;Persist Security Info=False;"
            Const strsql As String = "SELECT Vorname, Nachname FROM Beispieltabelle WHERE ..."
    
            ' Leert die Combobox
            ComboBox1.Items.Clear()
    
            Using conn As New OleDbConnection(constr)
                conn.Open()
                Using cmd As New OleDbCommand(strsql, conn)
                    Using reader = cmd.ExecuteReader()
                        While reader.Read()
                            ComboBox1.Items.Add(reader.GetString(0))
                            ComboBox1.Items.Add(reader.GetString(1))
                        End While
                    End Using
                End Using
            End Using
        End Sub
    

    die zudem kürzer - die Kommentare sind eh überflüssig bei solchem Trivial-Code
    (ausgenommen ihr werdet dafür bezahlt ;-))

    Was hier fehlt: Datenzugriffscode sollte nicht direkt im Formularcode "versenkt" werden, denn langfristig führt das zu einem Wartungschaos:
    Wo bitte greifen wir auf "Beispieltabelle" zu? (und alle fangen an zu suchen).

    Und letztendlich macht die BindingSource-Komponente keine "bösen" oder "unheimlichen" Dinge und man sollte sich damit vertraut machen.

    Für den Fall, dass man Dir die using Anweisung nicht beigebracht hat, solltest Du Dich damit ebenso beschäftigen.

    Und bitte nicht falsch verstehen: Diese Ratschläge sind gut gemeint - von einem Entwickler mit gut zwei Jahrzehnten auf dem Buckel.

    Gruß Elmar

    Mittwoch, 29. August 2012 16:50
    Beantworter

Alle Antworten

  • Hallo Christina,

    Deine Kategorientabelle sollte besser einen Autowert als Primärschlüssel verwenden, -
    z. B. als KategorieId, und diesen für den Verweis in Bücher verwenden -
    ValueMember und SelectedValue wären dann eine KategorieID.

    Auch im DataSet solltest Du einen Fremdschlüssel mit Relation einrichten.

    Willst Du nur mit Texten arbeiten, prüfe ob die Werte identisch sind. Auf der Datenbankseite müsste eine Beziehung mit Änderungsweitergabe existieren, damit Änderungen an der Bezeichnung an alle Bücher weitergegeben werden.

    Gruß Elmar

    Donnerstag, 23. August 2012 15:26
    Beantworter
  • Hallo Elmar,
    ich habe in der Kategorie-Tabelle einen Autowert als Primärschlüssel. Ich wollte in der Tabelle Buecher den Text der Kategorie speichern. Die Beziehung muss ich einrichten, da hast du Recht.
    Aber egal, was ich in dieser Combobox mache, es wird immer nach der ersten Auswahl falsch angezeigt. Ich nehme das SelectedValue heraus, ich ändere es auf die KategorieID, ich ändere das ValueMember, es funktioniert nicht. Die Tabelle hat aber die richtigen Daten, und beim Laden in die Combobox stimmt alles. Nur nach dem Auswählen eines Eintrags tritt der Fehler auf.
    • Bearbeitet sphinxx Montag, 27. August 2012 13:00
    Montag, 27. August 2012 12:47
  • Hallo,

    da kann ich mir direkt keinen Reim drauf machen.
    Reine Vermutung: Irgendwo findet da im Code noch etwas statt.
    Am besten entferne die ComboBox und BindingSource komplett,
    kompiliere einmal und fange danach von vorne an.

    Speichern solltest Du besser nur die KategorieID.
    Wenn Du den Text der Kategorie direkt sehen willst, füge sie als berechnetes Feld (über die Relation) ein. Ansonsten müsstest Du den Kategorietext eindeutig machen und für die Relation verwenden.

    Gruß Elmar

    Montag, 27. August 2012 16:19
    Beantworter
  • Um solchen Probleme zu umgehen fülle ich meine Comboboxen meistens manuell:

    Public Sub DatenLesen()
    
    'Leert die Combobox
    combobox1.items.clear()
    
    'Variablen deklarieren
    Dim constr As String 'Beinhaltet den Connectionstring zur Datenbank
    Dim conn As OleDBConnection 'Ist die Datenleitung zur Datenbank
    Dim strsql As String 'Beinhaltet den Befehl an die Datenbank
    Dim reader As OleDBDataReader 'Ist das ReaderObjekt
    'Verbindung zur Datenbank festlegen
    'Variert leicht, je nachdem welcher Datenbanktyp
    'Weitere Hilfe unter www.connectionstrings.com
    constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccess2007file.accdb;Persist Security Info=False;"
    'Datenleitung wird definiert
    conn = New OleDBConnection(constr)
    'Datenleitung wird geöffnet
    conn.Open()
    'Datenbankbefehl wird definiert
    strsql = "SELECT Vorname, Nachname FROM Beispieltabelle WHERE ..."
    'Befehlsobjekt wird vorbereitet
    Dim cmd As New OleDBCommand(strsql, conn)
    'Befehlsobjekt wird ausgeführt und Ergebnis in das Readerobjekt zurückgegeben
    reader = cmd.ExecuteReader
    'Prüfen, ob Datensätze gefunden wurden
    If reader.HasRows = False Then
    Exit Sub
    End If
    'Readerobjekt durchlaufen und Daten ausgeben
    While reader.Read()
    combobox1.Items.Add(reader!Vorname)
    combobox1.Items.Add(reader!Nachname)
    End While
    'Readerobjekt schliessen
    reader.Close()
    'Verbindung zur Datenbank schliessen
    conn.Close()
    
    End Sub
    Gruß Michael

    • Bearbeitet mgross93 Mittwoch, 29. August 2012 13:24
    Mittwoch, 29. August 2012 13:22
  • Hallo Michael,

    vielen Dank für deinen Tipp. Hattest du das gleiche Problem schon mal? Dann handelt es sich vielleicht um einen MS Bug?

    Mittwoch, 29. August 2012 14:29
  • Hallo Michael,

    vielen Dank für deinen Tipp. Hattest du das gleiche Problem schon mal? Dann handelt es sich vielleicht um einen MS Bug?

    Nunja... nicht direkt.

    Habe es in der Ausbildung so beigebracht bekommen. Und da Abreiten wir eigentlich überhaupt nicht mit BindingSources. Wir ziehen uns die Datensätze direkt aus der DB oder dem gefülltem DataSet mit dem oben genanntem Code-Besipiel.

    Gruß

    Mittwoch, 29. August 2012 15:19
  • Hallo Michael,

    dann hat man euch leider zu wenig und auch falsches beigebracht.
    Insbesondere ist ein absolutes NO GO:

    If reader.HasRows = False Then
    Exit Sub
    End If

    Damit werden Reader und Connection nicht geschlossen, was auf Dauer Probleme nach sich ziehen kann. Eine überarbeitete Variante:

        Private Sub DatenLesen()
            Const constr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccess2007file.accdb;Persist Security Info=False;"
            Const strsql As String = "SELECT Vorname, Nachname FROM Beispieltabelle WHERE ..."
    
            ' Leert die Combobox
            ComboBox1.Items.Clear()
    
            Using conn As New OleDbConnection(constr)
                conn.Open()
                Using cmd As New OleDbCommand(strsql, conn)
                    Using reader = cmd.ExecuteReader()
                        While reader.Read()
                            ComboBox1.Items.Add(reader.GetString(0))
                            ComboBox1.Items.Add(reader.GetString(1))
                        End While
                    End Using
                End Using
            End Using
        End Sub
    

    die zudem kürzer - die Kommentare sind eh überflüssig bei solchem Trivial-Code
    (ausgenommen ihr werdet dafür bezahlt ;-))

    Was hier fehlt: Datenzugriffscode sollte nicht direkt im Formularcode "versenkt" werden, denn langfristig führt das zu einem Wartungschaos:
    Wo bitte greifen wir auf "Beispieltabelle" zu? (und alle fangen an zu suchen).

    Und letztendlich macht die BindingSource-Komponente keine "bösen" oder "unheimlichen" Dinge und man sollte sich damit vertraut machen.

    Für den Fall, dass man Dir die using Anweisung nicht beigebracht hat, solltest Du Dich damit ebenso beschäftigen.

    Und bitte nicht falsch verstehen: Diese Ratschläge sind gut gemeint - von einem Entwickler mit gut zwei Jahrzehnten auf dem Buckel.

    Gruß Elmar

    Mittwoch, 29. August 2012 16:50
    Beantworter
  • Hallo Christina,

    ein Bug eher nicht.
    Nur ohne weitere Zusatzinfos kann ich leider mangels Kristallkugel nicht mehr als raten ;-)

    Kannst Du das Projekt auf den Teil zusammenstauchen und als Download bereit stellen?

    Gruß Elmar

    Mittwoch, 29. August 2012 16:53
    Beantworter
  • Hi Elmar,

    danke für die Korrektur meines Beispielcodes :) .

    If reader.HasRows = False Then
    Exit Sub
    End If

    Das schließen des Readers und der Connection hab ich aus zeitlichen Gründen vergessen zu erwähnen aber das mit den Using-Blocks ist eine Super Idee um den Code übersichtlicher und kleiner zu halten Vielen Dank :)

    Mittwoch, 29. August 2012 17:17
  • Ich kann da Elmar nur bestätigen. Beim Einsatz der ComboBox pur oder gekapselt, z.B. in einer Gridspalte, hatte ich noch nie Probleme, außer bei eigenen Fehlern, z.B. beim Laden per Code (ungebunden) im falschen Ereignis (z.B. Activate). Durch den mehrmaligen Aufruf kann zum mehrmaligen Laden gleicher Daten kommen. Das ist aber ein Problem nicht im Computer, sondern vor dem Computer.
     
    --
    Viele Gruesse
    Peter
    Mittwoch, 29. August 2012 19:17
  • Hallo Elmar, hallo Michael, hallo Peter,

    ich habe jetzt mal beide Versionen getestet, und da tritt mein Fehler nicht mehr auf. Da Elmar's Version kürzer ist, werde ich wohl mit dieser arbeiten.

    Trotz Allem will ich auch nochmal das Binden an die Combobox im Formulardesigner versuchen.

    Vielen Dank nochmals an Euch Alle.

    Viele Grüsse
    Christina

    Montag, 17. September 2012 10:13
  • Hallo sphinxx,

    Ich gehe davon aus, dass die Antworten Dir weitergeholfen haben.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT   Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Montag, 1. Oktober 2012 16:04
    Moderator