List(of String) an DatagridView binden

  • VB.NET

Es gibt 37 Antworten in diesem Thema. Der letzte Beitrag () ist von Takafusa.

    List(of String) an DatagridView binden

    Ich habe hier ein Anfängerproblem ...

    Ich habe eine List(of String), die ich an eine einspaltige DatagridView binden möchte.

    Wenn ich das richtig verstanden habe, dann geht das nicht einfach direkt, sondern ich muss eine Klasse bilden:

    VB.NET-Quellcode

    1. Public Class clTransponderList
    2. Public TransponderList As New List(Of String)
    3. Public Sub TransponderList_Add(ByRef myLine As String)
    4. TransponderList.Add(myLine)
    5. End Sub
    6. Public Sub TransponderList_Clear()
    7. TransponderList.Clear()
    8. End Sub
    9. End Class


    Soweit so gut.

    Die List(of String) befülle ich wie üblich:

    VB.NET-Quellcode

    1. Dim myTransponderList As New clTransponderList()
    2. myTransponderList.TransponderList_Add("....")
    3. myTransponderList.TransponderList_Add("....")
    4. myTransponderList.TransponderList_Add("....")


    Soweit immer noch so gut.

    Nun möchte ich die dgv mit der class verbinden.

    VB.NET-Quellcode

    1. dgvTransponder.DataSource = clTransponderList.TransponderList


    Das liefert mir die Fehlermeldung:

    Fehler BC30469 Der Verweis auf einen nicht freigegebenen Member erfordert einen Objektverweis.

    Ich weiß, dass ich einen ganz elementaren Fehler mache ... könnt ihr mir trotzdem nachsichtig helfen ?

    LG
    Peter
    Hier ist doch eindeutig keine Instanz der Klasse und somit der Zugriff auf die Liste so nicht drin.

    VB.NET-Quellcode

    1. dgvTransponder.DataSource = clTransponderList.TransponderList

    das würde gehen wenn die clTransponderList.TransponderList shared wäre.

    Ich denke du willst doch eher die Instanz nutzen. dgvTransponder.DataSource = myTransponderList.TransponderList

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

    @Peter329 Da hast Du ja ein lustiges Problem, das DGV zeigt ohne weiteres Zutun die Länge der Einträge an, das ist gewiss nicht das, was Du willst:

    Was soll denn angezeigt werden?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    ok ... natürlich will ich die Instanz nutzen. :)

    Danke !

    So, jetzt läuft die Sache ... alllein die dgv wird noch nicht richtig befüllt. Die Spalte "Tag" habe ich angelegt ... das ist die einzige Spalte in der dgv gemäß Designer.

    Der Bind fügt aber jetzt noch eine Spalte "Length" hinzu, die sogar richtig befüllt zu sein scheint ! Aber die Spalte "Tag", die den Text des List(of String) enthalten soll, enthält "nothing" !

    Na, vermutlich ist wieder etwas Elementares falsch ...

    LG
    Peter

    edit: Den Beitrag von RFG habe ich erst nach dem Senden gelesen. Der Effekt mit der Length scheint also bekannt zu sein. Ich will natürlich nur die Strings aus myTransponderList anzeigen. :)

    Bilder
    • s 2020-08-19 18-00-022.jpg

      8,82 kB, 559×252, 110 mal angesehen
    Das DataGridView sucht nach Properties. String hat Length.

    Brauchste eine Wrapperklasse und unterhälst eine List<T> davon.

    VB.NET-Quellcode

    1. Public Class ClTransponderList
    2. Public TransponderList As New List(Of Transponder)
    3. Public Sub TransponderList_Add(myLine As String)
    4. TransponderList.Add(New Transponder(myLine))
    5. End Sub
    6. Public Sub TransponderList_Clear()
    7. TransponderList.Clear()
    8. End Sub
    9. End Class
    10. Public Class Transponder
    11. Sub New(transponder As String)
    12. _value = transponder
    13. End Sub
    14. Private _value As String = ""
    15. Public Property Value As String
    16. Get
    17. Return _value
    18. End Get
    19. Set(value As String)
    20. _value = value
    21. End Set
    22. End Property
    23. End Class

    Das hast du sehr schön erklärt. Das verstehe ich jetzt. Danke.

    Jetzt wäre ich der Meinung, dass alles funktionieren müsste. Ich hoffe, ich bin nicht zu nervig ... aber leider ist das nicht so.

    Es wird jetzt eine Spalte "value" angehängt und die wird mit dem Inhalt der List(of String) korrekt befüllt. Die Spalte "Tag" bleibt nacht wie vor auf "nothing".

    Ich hab die Property "value" in "Tag" umbenannt ... dann wird eine zweite Spalte "Tag" angehängt und b befüllt. Die erste Spalte "Tag" enthält nach wie vor nothing. (s. Anhang) Muss ich vielleicht die Designer Spalte "Tag" entfernen ? Dann müsste ich die Properties (wie z.B. Text-Align etc. nachträglich im Programm setzen ?

    Das kann ich natürlich alles machen ... nur möchte ich halt sicher sein, dass dies dann so seine Richtigkeit hat. :)

    LG
    Peter


    edit: Ich sehe gerade, dass die Sache mit dem dynamischen Setzen der column-properties nicht ganz so einfach ist. Wenn ich etwa AutosizeMode=Fill einstellen will, muss ich ja wissen, wie die Spalte heißt ! Und wo bekomme ich den Namen her ?

    LG
    d.O.
    Bilder
    • s 2020-08-19 18-27-065.jpg

      12,36 kB, 555×254, 98 mal angesehen

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

    Du meinst den Style der ColumnHeader?
    Das kannst du auch zur Designtime festlegen.

    Um das Ergebnis zur Designtime zu sehen, kannst du temporär eine Column anlegen und wenn du fertig bist wieder löschen. Siehe die ganzen Sache im markierten Bereich. Wobei der DefaultCellStyle nicht relevant ist für den Header, auch wenn markiert.
    Bilder
    • Unbenannt.png

      14,74 kB, 651×475, 96 mal angesehen
    Ne, da hast du mich jetzt leider missverstanden.

    Ich habe einfach mal meine (Designer) Spalte "Tag" auf invisible gesetzt. Dann erhalte ich ein Display, wo die (neue) Spalte "Tag" eine feste Länge hat. Und das Display ist natürlich nicht das was ich haben will.

    Wie kann ich jetzt erreichen, dass diese Spalte Autosize=Fill zugewiesen bekommt ?

    LG
    Peter


    edit: Ok, ich hab das jetzt herausgefunden. Ich addressiere einfach über die relative column number:

    VB.NET-Quellcode

    1. dgvTransponder.Columns(1).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill


    Und schon schnackelt die Sache ! :)

    Ich bin begeistert ! Herzlichen Dank an aller Ratgeber ... Daumen hoch .... und einen schönen Abend !

    LG
    Peter

    Bilder
    • s 2020-08-19 18-48-103.jpg

      7,27 kB, 573×252, 89 mal angesehen

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

    Peter329 schrieb:


    edit: Ich sehe gerade, dass die Sache mit dem dynamischen Setzen der column-properties nicht ganz so einfach ist. Wenn ich etwa AutosizeMode=Fill einstellen will, muss ich ja wissen, wie die Spalte heißt ! Und wo bekomme ich den Namen her ?


    Der Name ist gleich wie dein PropertyName in der Transponderklasse.

    VB.NET-Quellcode

    1. For Each col As DataGridViewColumn In DataGridView1.Columns
    2. MessageBox.Show(col.DataPropertyName & Environment.NewLine & col.Name)
    3. 'hier eine passende Bedingung hin und z.B. col.EineProperty = EinKorrekterWert
    4. Next


    Wenn dir dir ColumnIndex bekannt ist kannst du auch einfach mit DataGridView1.Columns[index] darauf zugreifen.

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

    @Peter329 Was soll die Spalte Tag? Die DataSource bringt alles mit.
    Separate Spalten, die nicht gebunden sind, machen da nur Spunk.
    Denk mal darüber nach, eine DataTable zu befüllen un die dem DGV zuzuweisen.
    Wenn da an Spalten nix weiter hast, kannst Du ja glatt eine ListBox nehmen.
    Muss es ein DGV sein?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Alternativ gäbe es noch die Verwendung einer BindingSource (BS).

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Property TransponderList As New List(Of Transponder)
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. BindingSource1.DataSource = TransponderList
    5. End Sub
    6. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    7. BindingSource1.Add(New Transponder With {.Name = "Foo", .Tag = "Bar"})
    8. End Sub
    9. End Class
    10. Public Class Transponder
    11. Property Name As String
    12. Property Tag As String
    13. End Class

    Du haust Dir ne BS auf's Form, bindest sie an den Typ Transponder und das DGV an die BS. Dann kannst Du im Designer einstellen, wie das DGV aussehen soll, ohne dass Du während der Laufzeit irgendwas designtechnisch einstellen musst. Und dann arbeitest Du erstmal untypisiert mit dem o.g. Code. Will heißen, Du bindest Deine echte TransponderList an die BS an und alles ist gut.
    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.
    Mit der Listbox komme ich nicht klar, weil ich noch zwei weitere Spalten aufzunehmen muss. Ich hab meine Frage für das Forum halt möglichst einfach gehalten. Aber trotzdem vielen Dank für deine Anregung, die ich wie immer sehr zu schätzen weiß !

    So sieht die DGV jetzt aus:

    Seq - eine Folgenummer (Integer) - neu
    Lvl - eine Levelnummer (Integer) - neu
    Tag - ein Textstring

    Damit habe ich folgendes Display. (s. Anhang)

    Da habe ich dann gleich noch eine Frage:

    Die Spalte "Lvl" ist die Stufennummer der XML Einträge. Jetzt würde ich beispielsweise alle Einträge mit Stufennummern > 2 von der Anzeige ausblenden ... und später wieder einblenden - natürlich ohne die Datenbasis zu verändern.

    Soweit ich weiß ist das gerade ein Highlight des Databinding, dass man solche Auswahlen treffen kann ... nur wie macht man das ?

    LG
    Peter

    edit: Habe den Beitrag von Vaporizel erst nach dem Abschicken meines Beitrags entdeckt. Dann schließt sich die Frage an: wenn man das mit der BindingSource macht, wie sähe das dann aus, mit dem temporären ein- und ausblenden von Zeilen ?

    LG
    d.O.

    Bilder
    • s 2020-08-19 20-52-352.jpg

      43,48 kB, 777×380, 81 mal angesehen

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

    Aha. So langsam kommen die wichtigen Infos daher ;)
    Jetzt solltest Du wirklich mit DataTables und Datenmodellierung anfangen. Denn jetzt geht's schon um verschachtelte Informationsklassen, da brauchst Du ja mehr Klassen als bisher genannt wurden. Dann wird's dann m.E. auch sinnvoll mit den oben von mir erwähnten BindingSources zu arbeiten.

    @Peter329: Allerdings frag ich mich gerade, ob Seq und Lvl relevante Daten für Dein Projekt sind. Willst Du einfach nur ne XML-Datei auslesen und mit deren Daten arbeiten oder brauchst Du Seq und Lvl wirklich?
    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.
    Also ... dann lege ich mal die Karten offen.

    Die Datei, die ich hier verarbeite ist eine .TLL Datei, das ist eine Senderliste, die ich von meine LG Fernseher ausgelesen habe. Ich habe eine Sateliten-Schüssel mit einem Twin-LNB und außerdem eine DVB-T Antenne ... da habe ich rund 3.000 Programme ... von denen die allermeisten aber Schrott sind. Nach einem Sendersuchlauf muss ich jedesmal per Fernbedienung die Favoriten neu einstellen. Das ist ein abendfüllendes Programm.

    Ich würde gern auf Knopfdruck alle verschlüsselten Programme entfernen ... und außerdem bestimmte Programme, wie ARD, ZDF ... immer an den Anfang der Liste sortieren. Das sind Funktionen, die ich mit CHANSORT und ähnlichen Programmen nur sehr mühsam hinbekomme.

    Leider ist mein Vorhaben nicht ganz so einfach, weil das Format der Senderliste für jeden Hersteller und manchmal sogar für jedes Modell verschieden ist. Ich muss mir also erst mal einen Überblick über den Aufbau der Datei verschaffen. Und weil das fast 125.000 Zeilen sind, würde ich gern Stufenlevel ausblenden. Aber ich will die originale Zeilenummer des Source immer noch anzeigen, damit ich weiß, wo ich mich befinde.

    Ich werde jetzt mal sehen, ob ich das mit der Binding Source und der Filter Property hinbekomme. Aber das mache ich dann morgen .... :)

    LG
    Peter
    Wir haben auch eine Satellitenschüssel und haben Ähnliches Problem. Ich habe da einfach eine eigene Senderliste angelegt und dort nur die Sender reingepackt die uns interessieren. Diese wird beim anktualisieren nicht angerührt. Schau mal ob das bei dir auch möglich ist. Sparst dir das Programm evtl.
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    Ich habe jetzt versucht, die Technik von Vaporized umzusetzen.

    VB.NET-Quellcode

    1. Public Class Transponder2
    2. Property Seq As Integer
    3. Property Lvl As Integer
    4. Property Tag As String
    5. End Class
    6. Public Class frmTransponderEdit
    7. Public Property TransponderList As New List(Of Transponder2)
    8. Dim BindingSource1 As New BindingSource
    9. Private Sub frmTransponderEdit_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    10. BindingSource1.DataSource = TransponderList
    11. BindingSource1.Add(New Transponder2 With {.Seq = cnt, .Lvl = lvl, .Tag = line})
    12. dgvTransponder.DataSource = BindingSource1


    Im Designer habe ich die Spalten Seq, Lvl und Tag angelegt.

    Das Programm läuft fehlerfrei durch .... allein die Spalten werden immer noch dynamisch generiert ! (s. Anhang)

    Was mache ich denn falsch ?

    LG
    Peter
    Bilder
    • s 2020-08-20 07-01-432.jpg

      20,25 kB, 913×349, 97 mal angesehen

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

    @Peter329 Das Binding interessiert sich nicht für Spalten, die im Designer angelegt werden.
    Nimm die wieder raus und dann sollten die vom Binding übrig bleiben.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Sobald Du ein leeres DGV an eine BS bindest, wird das DGV automatisch Spalten anzeigen. Diese werden automatisch an die Properties der Datenquelle gebunden, die als BS-DataSource hinterlegt ist. Und diese Spalten solltest Du nach Herzenslust modifizieren. Selber welche anzulegen ist der umständliche Weg und wird auch zu Problemen führen.
    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.
    Da du die "Liste" die gebunden wird im Code erstellst und zur Laufzeit bindest, kann zur Designtime ja nichts angezeigt werden, da ist ja nichts bekannt. Anders verhält es sich, wenn du ein Dataset benutzt(Im Designer erstellt) und dieses schon zur Designtime bindest.

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