ListView AutoSize-Probleme

  • VB.NET
  • .NET (FX) 4.0

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    ListView AutoSize-Probleme

    Hallo zusammen.

    Ich lasse mir in meiner Anwendung ListViews füllen und stelle unter anderem die Spaltenbreite über den Code ein.
    Jetzt hab' ich mich ein wenig belesen und weiß nun, dass mit -2 die Breite des Headertextes und mit -1 die breite des "breitesten Items" als Spaltenbreite
    übernommen wird.

    Auf dem einen ListView klappt das auch wie gewünscht, bei dem anderen schießt er mir eine Spalte dazwischen die ewig breit wird - obwohl es laut Code nicht so sein soll.
    Die ListView's sind in den Eigenschaften gleichermaßen eingestellt - was mach' ich denn hier falsch?

    Funktioniert:


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub PlanHeaderMonate(Monatsnummer As Integer, lvMonat As Windows.Forms.ListView)
    2. Dim sDate As Date = MonatsAnfang(Monatsnummer, My.Settings.JahrPlaner)
    3. Dim eDate As Date = MonatsEnde(Monatsnummer, My.Settings.JahrPlaner)
    4. With lvMonat
    5. .View = View.Details
    6. .GridLines = True
    7. .Scrollable = True
    8. .FullRowSelect = True
    9. .Items.Clear()
    10. .Columns.Clear()
    11. .Columns.Add("Mitarbeiter", -1) '170)
    12. .Columns.Add("Gesellschaft", -2) '170)
    13. .Columns.Add("Standort", -1) '120)
    14. .Columns.Add("Abteilung", -2) '120)
    15. .Columns.Add("Urlaub", -2) '100)
    16. .Columns.Add("Krank", -2) '100)
    17. End With
    18. Dim loopDate As Date = sDate
    19. Do While loopDate < eDate.AddDays(1)
    20. lvMonat.Columns.Add($"{loopDate.Day} {loopDate.ToString("ddd")}", -2, HorizontalAlignment.Center).Name = loopDate.ToShortDateString
    21. loopDate = loopDate.AddDays(1)
    22. Loop
    23. lvMonat.Columns.Add("", -2) 'Pseudo-Spalte, damit letzte Spalte nicht an Fensterbreite angepasst wird
    24. filteredMonate(lvMonat, Monatsnummer)
    25. End Sub


    Funktioniert nicht:


    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub PlanHeaderMitarbeiter()
    2. With lvMitarbeiter
    3. .View = View.Details
    4. .GridLines = True
    5. .Scrollable = True
    6. .FullRowSelect = True
    7. .Items.Clear()
    8. .Columns.Clear()
    9. .Columns.Add("Mitarbeiter", -1)
    10. .Columns.Add("Gesellschaft", -1)
    11. .Columns.Add("Standort", -1)
    12. .Columns.Add("Abteilung", -2)
    13. .Columns.Add("Urlaubsanspruch", -2) '130)
    14. .Columns.Add("Urlaub verplant", -2) '130)
    15. .Columns.Add("Urlaub unverplant", -2) '130)
    16. .Columns.Add("Krank", -2, HorizontalAlignment.Center) '100)
    17. .Columns.Add("Januar", -2, HorizontalAlignment.Center) '100)
    18. .Columns.Add("Februar", -2, HorizontalAlignment.Center) '100)
    19. .Columns.Add("März", -2, HorizontalAlignment.Center) '100)
    20. .Columns.Add("April", -2, HorizontalAlignment.Center) '100)
    21. .Columns.Add("Mai", -2, HorizontalAlignment.Center) '100)
    22. .Columns.Add("Juni", -2, HorizontalAlignment.Center) '100)
    23. .Columns.Add("Juli", -2, HorizontalAlignment.Center) '100)
    24. .Columns.Add("August", -2, HorizontalAlignment.Center) '100)
    25. .Columns.Add("September", -2, HorizontalAlignment.Center) '100)
    26. .Columns.Add("Oktober", -2, HorizontalAlignment.Center) '100)
    27. .Columns.Add("November", -2, HorizontalAlignment.Center) '100)
    28. .Columns.Add("Dezember", -2, HorizontalAlignment.Center) '100)
    29. .Columns.Add("", -2) 'Pseudo-Spalte, damit letzte Spalte nicht an Fensterbreite angepasst wird
    30. End With
    31. filteredMitarbeiter()
    32. End Sub
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    Fakiz schrieb:

    Ich würde nach dem befüllen der ListView die Methode ListView.AutoResizeColumns aufrufen.


    mist...
    mit der autoresizecolumns-methode muss ich mich aber festlegen, ob die Breite an den Header oder die Items angepasst wird - ich hätte ja gerne eine Mischung aus Beidem...

    Edit:
    Ich hab' in nem anderen älteren Thread noch was gefunden, was für mich auch passen würde. Allerdings flackert das Bild und der Aufbau dauert ewig, trotz dass das ganze innerhalb von
    LV.BeginUpdate und LV.EndUpdate stattfindet...
    ansonsten wäre das eine gute Lösung..

    VB.NET-Quellcode

    1. Private Sub SetColWidth(LV As ListView)
    2. For i As Integer = 0 To LV.Columns.Count - 1
    3. Dim Breite1, Breite2 As Integer
    4. LV.Columns(i).AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize)
    5. Breite1 = LV.Columns(i).Width
    6. LV.Columns(i).AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent)
    7. Breite2 = LV.Columns(i).Width
    8. LV.Columns(i).Width = Math.Max(Breite1, Breite2)
    9. Next
    10. End Sub

    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    Wenn du den Link für AutoresizeColumns öffnest und dir links den Treeview ansiehst findet sich dort auch die Methode AutoresizeColumn.
    Diese Methode ließe sich wie folgt umsetzen:


    VB.NET-Quellcode

    1. .Columns.Add("Mitarbeiter", -1) '170)
    2. .Columns.Add("Gesellschaft", -2) '170)
    3. '...


    VB.NET-Quellcode

    1. lvMonat.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent);
    2. lvMonat.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.HeaderSize);



    PS: Das die ListView stark flackert wenn die Methode SetColWidth aufgerufen wird ist klar, denn die ListView wird hier bei jedem Schleifen durchlauf 3x Neu gezeichnet. Von Dieser Methode kann ich dir nur abraten.
    Hi tragl

    bringt das eine Verbesserung

    VB.NET-Quellcode

    1. Public Sub ListviewOptimizeColumsWidth(ByRef Lvw As ListView)
    2. Lvw.SuspendLayout()
    3. For i As Integer = 0 To Lvw.Columns.Count - 1
    4. Lvw.Columns(i).Width = -2
    5. Dim w As Integer = Lvw.Columns(i).Width
    6. Lvw.Columns(i).Width = -1
    7. If w > Lvw.Columns(i).Width Then
    8. Lvw.Columns(i).Width = w
    9. End If
    10. Next
    11. Lvw.ResumeLayout()
    12. End Sub


    gruss
    kasi

    Kasi schrieb:

    bringt das eine Verbesserung

    Leider nein, das Gleiche Geflacker

    Fakiz schrieb:

    PS: Das die ListView stark flackert wenn die Methode SetColWidth aufgerufen wird ist klar, denn die ListView wird hier bei jedem Schleifen durchlauf 3x Neu gezeichnet. Von Dieser Methode kann ich dir nur abraten.

    Danke für den Tipp - mit folgendem geht's halbwegs, allerdings ist die Spalte die nach der MIT Tags kommt auf die komplette restliche Bildschirmbreite gezogen, danach kommen die restlichen via Bildlauf...

    VB.NET-Quellcode

    1. Private Sub SetColumnWidth(lv As ListView)
    2. lv.SuspendLayout()
    3. For i = 0 To lv.Columns.Count - 1
    4. If Not lv.Columns(i).Tag Is Nothing Then
    5. Select Case lv.Columns(i).Tag.ToString
    6. Case "col" : lv.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.ColumnContent)
    7. Case "head" : lv.AutoResizeColumn(i, ColumnHeaderAutoResizeStyle.HeaderSize)
    8. End Select
    9. End If
    10. Next
    11. lv.ResumeLayout()
    12. End Sub




    es muss doch irgendwie machbar sein die Breiten sinnvoll einzustellen, sodass das auch funzt.
    Die Spaltenbreiten persistieren und beim Öffnen laden ist auch nicht so das Gelbe vom Ei - denn wenn die ListView zwischendurch neu geladen werden muss, wird die persistierung überschrieben
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Wie in dem MSDN Artikel zu lesen ist muss AutoResizeColumn/s nach jeder änderung der Auflistung aufgerufen werden und erst nach befüllung der ListView. U.U. Könnte auch der Aufruf von SuspendLayout zu Problemen führen sicher bin ich aber nicht. Ich nutze, um das neuzeichnen zur Laufzeit zu unterbinden, BeginUpdate() und EndUpdate().
    sorry, war 'ne Woche im Urlaub - daher kann ich jetzt erst antworten.

    Fakiz schrieb:

    nach jeder änderung der Auflistung aufgerufen werden und erst nach befüllung der ListView

    genau das mach' ich eigentlich (zumindest bei der Erstbefüllung)

    ErfinderDesRades schrieb:

    Warum verwendest du nicht einfach ein Datagridview?

    Darauf wird's wohl hinaus laufen. Wollte das ListView-Control verwenden weil das DGV für das zu mächtig ist. Des Weiteren kommen die Daten aus verschiedenen Tabellen, weshalb ich nicht einfach eine BindingSource
    drankleben kann.

    Ich setz' mich die Tage mal mit der manuellen Befüllung eines DGV und der damit verbundenen Zellmarkierung und den Berechnungen auseinander. :thumbup:
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Hallo zusammen.

    Bin grad' dabei das ganze von der ListView auf DGV umzutüdeln - das mit den Spaltenbreiten klappt da nämlich genau so wie es sein soll.
    Allerdings stehe ich vor folgendem Problem:

    Ich kann mit meinem aktuellen Wissensstand nur eine komplette DGV-Row hinzufügen aber nicht einzelne "Items" nachträglich, so wie es beim
    ListView der Fall war.

    Konkret ziehe ich mir in dem Beispiel meine festen Daten (Mitarbeiter, Gesellschaft, Standort, gesamtUrlaub Monat, Krank Monat).
    Jetzt möchte ich wie im ListView aber dahinter noch die einzelnen Tage (Header werden sauber erstellt) und wenn ein Urlaub an dem Tag ansteht soll er mir das entsprechend anzeigen.
    Am Beispiel der ListView:


    Mein DGV sieht bisher wie folgt aus:


    Codeaufbau für die Daten: (Das Auskommentierte war mein Versuch - aktuelle Row holen und den ColText mit Datum abgleichen und Zelle entsprechend beschreiben, geht aber nicht)
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub dataMonate(dgvMonat As DataGridView, monatNr As Integer)
    2. For Each rwMitarbeiter In Dts.Mitarbeiter
    3. If Not rwMitarbeiter.Name = "<keine Zuordnung>" Then 'Mitarbeiter ohne Zuordnugn weglassen
    4. Dim urlaubMonat = 0#
    5. Dim krankMonat = 0
    6. Dim monatsDaten = Dts.Plan.Where(Function(x) x.MitarbeiterID = rwMitarbeiter.ID AndAlso x.Datum.Year = _setYear AndAlso x.Datum.Month = monatNr)
    7. For Each rwMonatsDaten In monatsDaten
    8. Select Case rwMonatsDaten.UrlaubStatus
    9. Case "1" : urlaubMonat += 1
    10. Case "0,5" : urlaubMonat += 0.5
    11. Case "K" : krankMonat += 1
    12. End Select
    13. Next
    14. dgvMonat.Rows.Add(rwMitarbeiter.Name,
    15. rwMitarbeiter.expGesellschaft,
    16. rwMitarbeiter.Standort,
    17. urlaubMonat,
    18. krankMonat)
    19. 'Dim getRow = dgvMonat.Rows.Count
    20. 'For iCol = 6 To dgvMonat.Columns.Count
    21. ' For Each rwMonatsDaten In monatsDaten
    22. ' If rwMonatsDaten.Datum.ToShortDateString = dgvMonat.Columns(iCol).Name Then
    23. ' dgvMonat.Rows(getRow).Cells(iCol).Value = rwMonatsDaten.UrlaubStatus
    24. ' End If
    25. ' Next
    26. 'Next
    27. End If
    28. Next
    29. End Sub


    Ich stehe also irgendwo auf'm Schlauch... :( Hat wer einen Tipp für mich?

    LG
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

    VB.NET-Quellcode

    1. DeinDGV.Rows(x).Cells(y).Value = "Foo"
    2. 'oder
    3. DeinDGV.Item(y, x).Value = "Bar"

    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.
    @VaporiZed:
    Danke, dann lag ich ja garnicht mal falsch - funzt aber trotzdem nicht:


    liegt das vielleicht daran, dass ich die Row weiter oben mit 5 Items "angelegt" hab - danach aber noch einige dazu kommen?
    Das Problem ist, dass ich nicht weiß wieviele Einträge es werden (also max. 31 Tage - das is klar, aber es können ja auch mal 28/29/30 sein)
    sonst könnte man das ggf. vorher abhandeln und in eine Variable packen...

    Zum Codefehler:
    Ich weiß nicht, wo das Indexproblem sein soll...
    Column 6 ist richtig, das ist die 1. die mit Datum angelegt ist (nach Mitarbeiter, Gesellschaft, Standort, Urlaub, Krank)
    und Row 1 ist richtig, weil es die erste Row ist (wird ja mit getRow ausgelesen)

    EDIT: Hab's - ich hab nicht mehr dran gedacht, dass Columns und Rows ja bei 0 anfangen und nicht bei 1 :S
    Also so funzt es nun:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub dataMonate(dgvMonat As DataGridView, monatNr As Integer)
    2. For Each rwMitarbeiter In Dts.Mitarbeiter
    3. If Not rwMitarbeiter.Name = "<keine Zuordnung>" Then 'Mitarbeiter ohne Zuordnugn weglassen
    4. Dim urlaubMonat = 0#
    5. Dim krankMonat = 0
    6. Dim monatsDaten = Dts.Plan.Where(Function(x) x.MitarbeiterID = rwMitarbeiter.ID AndAlso x.Datum.Year = _setYear AndAlso x.Datum.Month = monatNr)
    7. For Each rwMonatsDaten In monatsDaten
    8. Select Case rwMonatsDaten.UrlaubStatus
    9. Case "1" : urlaubMonat += 1
    10. Case "0,5" : urlaubMonat += 0.5
    11. Case "K" : krankMonat += 1
    12. End Select
    13. Next
    14. dgvMonat.Rows.Add(rwMitarbeiter.Name,
    15. rwMitarbeiter.expGesellschaft,
    16. rwMitarbeiter.Standort,
    17. urlaubMonat,
    18. krankMonat)
    19. Dim getRow = dgvMonat.Rows.Count - 1
    20. For iCol = 5 To dgvMonat.Columns.Count - 1
    21. For Each rwMonatsDaten In monatsDaten
    22. If rwMonatsDaten.Datum.ToShortDateString = dgvMonat.Columns(iCol).Name Then
    23. dgvMonat.Item(iCol, getRow).Value = $"{rwMonatsDaten.UrlaubStatus}"
    24. End If
    25. Next
    26. Next
    27. End If
    28. Next
    29. End Sub
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: