Leere Spalten im DataGridView ausblenden

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

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

    Leere Spalten im DataGridView ausblenden

    In meinem DataGridView sind momentan zwölf Spalten vorhanden und es ist an ein DataSet/DataTable gebunden. Je nachdem was ich anzeigen lassen möchte, gibt es immer leere Spalten, die doof aussehen und Platz wegnehmen. Die System.Windows.Forms.DataGridViewAutoSizeColumnMode habe ich alle ausprobiert, aber leere Spalten bleiben immer teilweise sichbar.
    Mit diesem Code habe ich mein Problem zufriedenstellend gelöst:

    VB.NET-Quellcode

    1. Friend Sub DGV_LeereSpaltenAusblendenUndSpaltenBreitenAnpassen(ByRef dgv As DataGridView, ByVal azMode As System.Windows.Forms.DataGridViewAutoSizeColumnMode)
    2. Dim c, r As Integer
    3. For c = 0 To dgv.ColumnCount - 1
    4. For r = 0 To dgv.RowCount - 1
    5. If dgv.Item(c, r).Value.ToString.Length > 0 Then
    6. dgv.Columns(c).Visible = True
    7. dgv.Columns(c).AutoSizeMode = azMode
    8. dgv.UpdateCellValue(c, r)
    9. Exit For
    10. End If
    11. dgv.Columns(c).Visible = False
    12. Next
    13. Next
    14. End Sub


    Aufruf so: DGV_LeereSpaltenAusblendenUndSpaltenBreitenAnpassen(myDataGridView, DataGridViewAutoSizeColumnMode.AllCells)

    Wo rufe ich das idealerweise auf? In .DataBindingComplete?
    --------
    Lieber inkompetent als inkontinent
    Zunächstmal: ByRef ist hier unangebracht, den dgv ist ein Refrerenz-Typ.
    Da fehlt wohl Verständnis an einem grundlegendem Konzept der Sprache. Recherchier das mal, oder versuche ByVal und ByRef - was macht jetzt genau was zu kapieren (ist nicht ganz einfach)

    Zur Frage: Kommt drauf an, wie du deine DGVs gestaltest. Wenn du mit einem typDataset arbeitest, und im Form-Designer die DGVs designest, mit je Tabelle eigenem DGV und Design, dann braucht man sowas garnet (oder man hat ein komisches Datenmodell, dass da Sichten entstehen mit komplett leeren Spalten).
    Soweit ich das verstanden habe, übergibt ByVal quasi eine Kopie und ByRef einen Verweis auf das Objekt. Mein Code würde so mit ByVal nicht funktionieren, bin ich überzeugt.

    Ich arbeite mit einem typisierten DataSet und das DGV habe ich im Form-Designer angepaßt. Die Tabelle, aus der Daten angezeigt werden, hat insgesamt ca. 25 Spalten, von denen werden jedoch nur zwölf Stück angezeigt. Die Daten kommen aus einer Schnittstelle, die ich nicht programmiert habe. Es gibt sehr viele Varianten welche Spalten Inhalte haben und welche nicht, wobei ich bei der Abfrage der Daten nicht vorhersehen kann, was genau zurückkommt.

    Beispiel:
    Ich frage, grob gesagt, (unvollständige) Adressdaten ab, die ich aber nicht erfaßt habe. Manche Datensätze beinhalten neben den ganz allgemein üblichen Angaben z.B. einen zweiten Vornamen, einen Adreßzusatz, Telefonnummern, Ausweisnummern. Wenn ich bei der Abfrage beispielsweise fünf Treffer habe, dann kann es sein, daß etliche Spalten komplett leer sind. Das möchte ich dem Anwender so nicht zumuten. Im DGV sollen daher nur die Spalten sichtbar sein, die auch Inhalte haben.

    Achso: Diese Tabelle im DataSet speichere ich auch nicht in meiner Datenbank! Es handelt sich bei dieser Tabelle nur um ein bequemes Hilfsmittel zur Datendarstellung/Sortierung.
    --------
    Lieber inkompetent als inkontinent

    100Volt schrieb:

    Mein Code würde so mit ByVal nicht funktionieren, bin ich überzeugt.
    Du irrst dich.
    Dass du so überzeugt bist, ist natürlich ein Problem.
    Ich würde empfehlen, du probierst es einfach aus mit ByVal - das dürfte deine Überzeugung ins Wanken bringen.
    Und befähigt dich somit, was zu lernen über ByVal, ByRef, ValueTypen (Structure), Referenztypen (Class).
    Ist wichtig.
    Du hast recht, das funktioniert wirklich mit ByVal.

    Ich hatte mir das so gemerkt, wie es z.B. in diesem Dokument von Microsoft steht:
    https://docs.microsoft.com/de-de/dotnet/visual-basic/programming-guide/language-features/procedures/passing-arguments-by-value-and-by-reference

    "In Visual Basic können Sie ein Argument als Wert oder als Verweis an eine Prozedur übergeben. Dies wird als Übergabe Mechanismus bezeichnet und bestimmt, ob die Prozedur das Programmier Element, das dem Argument zugrunde liegt, im aufrufenden Code ändern kann. Die Prozedur Deklaration bestimmt den Übergabe Mechanismus für jeden Parameter, indem das ByVal -oder ByRef -Schlüsselwort angegeben wird."

    Also kann eine Prozedur ein per ByVal übergebenes Steuerelement ändern, eine Variable aber nicht?


    --------
    Lieber inkompetent als inkontinent
    @100Volt Die Instanz selbst kannst Du nicht ändern (der überschriebene Parameter control = New CONTROL() ist control nur innerhalb der Prozedur verfügbar),
    wohl aber kannst Du Properties in dieser Instanz ändern.
    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!

    100Volt schrieb:

    Also kann eine Prozedur ein per ByVal übergebenes Steuerelement ändern, eine Variable aber nicht?
    Die Prozedur kann Properties des Steuerelements ändern - das Steuerelement selbst, als ganzes, austauschen kann sie nicht ("austauschen" statt "ändern" wäre vlt. das bessere Wort im MS-Doku-Text).
    Austauschen kann sie es nur, wenn sie es ByRef bekommt - und das wäre nicht gut.
    Siehe nochmal den zweiten Post des verlinkten Tuts - da steht, wofür ByRef in bestimmten Fällen auch gut sein kann.

    100Volt schrieb:

    Wo rufe ich das idealerweise auf? In .DataBindingComplete?
    Ja, warum nicht, sollte klappen. Sag Du es uns. Oder in BindingSource.DataSourceChanged. Probiere und berichte bitte.
    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.
    Wenn ich bei der Abfrage beispielsweise fünf Treffer habe, dann kann es sein, daß etliche Spalten komplett leer sind. Das möchte ich dem Anwender so nicht zumuten. Im DGV sollen daher nur die Spalten sichtbar sein, die auch Inhalte haben.


    und wenn jemand eine Adresse vervollständigen will ?
    dann sieht er die Spalte ja garnicht
    ok, vielen Dank für die Erklärungen bzgl. ByVal und ByRef. Ich werde meinen Code dahingehend überarbeiten, denn das wird an etlichen Stellen falsch sein.

    zu VaporiZed:
    Der Aufruf meines Codes in myDataGridView.DataBindingComplete und myDataGridView.DataSourceChanged funktioniert problemlos. In myBindingSource.DataSourceChanged hingegen funktioniert er nicht richtig, was aber wohl daran liegt, daß ich die Daten direkt in die Tabelle schreibe.

    Zu Kasi:
    Ich kann aus der Quelle nur Daten abrufen, keine hineinschreiben. Die abgerufenen Daten sind flüchtig und im wesentlichen zur visuellen Betrachtung vorgesehen. Daher sind leere Spalten wirklich völlig unnötig und nehmen nur Platz weg.
    --------
    Lieber inkompetent als inkontinent

    100Volt schrieb:


    ....leere Spalten wirklich völlig unnötig und nehmen nur Platz weg.


    da geb ich dir recht
    schaumal ob du damit was anfangen kannst

    VB.NET-Quellcode

    1. Public Class Form1
    2. WithEvents bsData As New BindingSource
    3. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    4. Dim dt As New DataTable With {.TableName = "Tabelle"}
    5. dt.Columns.Add(New DataColumn With {.ColumnName = "Nr",
    6. .DataType = GetType(Int32),
    7. .AutoIncrement = True,
    8. .AutoIncrementSeed = 1,
    9. .ColumnMapping = MappingType.Hidden
    10. }
    11. )
    12. dt.Columns.Add(New DataColumn With {.ColumnName = "Vorname",
    13. .DataType = GetType(String)})
    14. dt.Columns.Add(New DataColumn With {.ColumnName = "Nachname",
    15. .DataType = GetType(String)})
    16. dt.Columns.Add(New DataColumn With {.ColumnName = "Alter",
    17. .DataType = GetType(Integer)})
    18. dt.Columns.Add(New DataColumn With {.ColumnName = "Position",
    19. .DataType = GetType(String)})
    20. dt.Rows.Add(New Object() {Nothing, "", "Merkel", 66, "LockDown Spezialistin"})
    21. dt.Rows.Add(New Object() {Nothing, "", "Söder", 6, ""})
    22. bsData.DataSource = dt
    23. DataGridView1.DataSource = bsData
    24. Label1.DataBindings.Add("Text", bsData, "Nr")
    25. 'DGV_LeereSpaltenAusblendenUndSpaltenBreitenAnpassen(DataGridView1, bsData, DataGridViewAutoSizeColumnMode.AllCells)
    26. End Sub
    27. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    28. DGV_LeereSpaltenAusblendenUndSpaltenBreitenAnpassen(DataGridView1, bsData, DataGridViewAutoSizeColumnMode.AllCells)
    29. End Sub
    30. Public Function DGV_LeereSpaltenAusblendenUndSpaltenBreitenAnpassen(ByVal dgv As DataGridView, _
    31. ByVal bs As BindingSource, _
    32. ByVal azMode As System.Windows.Forms.DataGridViewAutoSizeColumnMode)
    33. 'Dim c, r As Integer
    34. 'For c = 0 To dgv.ColumnCount - 1
    35. 'For r = 0 To dgv.RowCount - 1
    36. For Each c As DataGridViewColumn In dgv.Columns
    37. Dim noValue As Boolean = True
    38. For Each r As DataGridViewRow In dgv.Rows
    39. 'If dgv.Item(c, r).Value.ToString > 0 Then
    40. If Not String.IsNullOrEmpty(r.Cells(c.Index).Value) Then
    41. 'dgv.Columns(c).Visible = True
    42. 'dgv.Columns(c).AutoSizeMode = azMode
    43. c.AutoSizeMode = azMode
    44. 'dgv.UpdateCellValue(c, r)
    45. 'Exit For
    46. noValue = False
    47. Exit For
    48. End If
    49. Next r
    50. If noValue Then
    51. dgv.Columns(c.Index).Visible = False
    52. End If
    53. Next c
    54. Return dgv
    55. End Function
    56. End Class