Results 1 to 7 of 7

Thread: Auto resize ListView columns to fit either the header text or content

  1. #1

    Thread Starter
    Member
    Join Date
    Nov 2016
    Location
    UK
    Posts
    46

    Auto resize ListView columns to fit either the header text or content

    If the ListView has no items this will resize the columns to fit the header text but if it has items it will resize the columns to fit the content if the content is wider than the header text.

    Code:
        ''' <summary>
        ''' Automatically resizes a ListViews columns to fit either the column content or the column header text depending on which is the widest
        ''' </summary>
        ''' <param name="List_View"></param>
        Public Sub AutoColumnResize(List_View As ListView)
    
            Dim ColHeader As ColumnHeader
            Dim HeaderTextLength As Integer
            Dim MaxContentLength As Integer
            
            For i = 0 To List_View.Columns.Count - 1
    
                ColHeader = List_View.Columns(i)
                HeaderTextLength = List_View.Columns(i).Text.Length
    
                For inc = 0 To List_View.Items.Count - 1
                    MaxContentLength = Math.Max(MaxContentLength, List_View.Items(inc).SubItems(i).Text.Length)
                Next
    
                If MaxContentLength < HeaderTextLength Then
                    ColHeader.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize)
                End If
            Next
        End Sub
    Last edited by LucasCain; Jan 26th, 2021 at 08:50 PM.

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,302

    Re: Auto resize ListView columns to fit either the header text or content

    I haven't tested it specifically but wouldn't you just need to do this:
    vb.net Code:
    1. List_View.AutoResizeColumns(If(List_View.Items.Count = 0,
    2.                                ColumnHeaderAutoResizeStyle.HeaderSize,
    3.                                ColumnHeaderAutoResizeStyle.ColumnContent))
    EDIT: Actually, I see that, if ColumnContent ignores the header, that may cut off a header that is longer that all the subitems in that column. The problem with your code is that it accounts only for the number of characters and not the pixel width of the text. For instance "iiii" has more characters than "www" and so would be considered longer by your code, although the latter actually takes up more pixels.

  3. #3

    Thread Starter
    Member
    Join Date
    Nov 2016
    Location
    UK
    Posts
    46

    Re: Auto resize ListView columns to fit either the header text or content

    Yes that looks much more simple

    Oh well that was my first codebank post lol

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,302

    Re: Auto resize ListView columns to fit either the header text or content

    I just tested and the code I posted will indeed cut off a long column header if all subitems in that column are shorter. It seems an oversight that there isn't an option to consider both header and items automatically but that's the way it is. As such, your code is, in principle, better. It could do with a bit of improvement though. This should address all the issues:
    vb.net Code:
    1. Private Sub ResizeListViewColumns(listView As ListView)
    2.     Dim items = listView.Items.Cast(Of ListViewItem).ToArray()
    3.     Dim itemCount = items.Length
    4.     Dim g As Graphics
    5.  
    6.     'Create a single Graphics object with which to measure text if and only if it is needed..
    7.     If itemCount > 0 Then
    8.         g = listView.CreateGraphics()
    9.     End If
    10.  
    11.     For Each column As ColumnHeader In listView.Columns
    12.         'Assume that we're autosizing based on the header unless determined otherwise.
    13.         Dim style = ColumnHeaderAutoResizeStyle.HeaderSize
    14.  
    15.         If itemCount > 0 Then
    16.             'Get the pixel width of the header text.
    17.             Dim headerWidth = g.MeasureString(column.Text, listView.Font).Width
    18.  
    19.             'get the greatest pixel width of the subitems.
    20.             Dim maxSubItemWidth = items.Max(Function(item) g.MeasureString(item.SubItems(column.Index).Text, listView.Font).Width)
    21.  
    22.             If maxSubItemWidth > headerWidth Then
    23.                 style = ColumnHeaderAutoResizeStyle.ColumnContent
    24.             End If
    25.         End If
    26.  
    27.         column.AutoResize(style)
    28.     Next
    29.  
    30.     'Dispose the Graphics object if and only if we created one.
    31.     g?.Dispose()
    32. End Sub

  5. #5
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,302

    Re: Auto resize ListView columns to fit either the header text or content

    You could even implement that code as an extension method:
    vb.net Code:
    1. Imports System.Runtime.CompilerServices
    2.  
    3. Public Module ListViewExtensions
    4.  
    5.     <Extension>
    6.     Public Sub AutoResizeColumns(source As ListView)
    7.         Dim items = source.Items.Cast(Of ListViewItem).ToArray()
    8.         Dim itemCount = items.Length
    9.         Dim g As Graphics
    10.  
    11.         'Create a single Graphics object with which to measure text if and only if it is needed..
    12.         If itemCount > 0 Then
    13.             g = source.CreateGraphics()
    14.         End If
    15.  
    16.         For Each column As ColumnHeader In source.Columns
    17.             'Assume that we're autosizing based on the header unless determined otherwise.
    18.             Dim style = ColumnHeaderAutoResizeStyle.HeaderSize
    19.  
    20.             If itemCount > 0 Then
    21.                 'Get the pixel width of the header text.
    22.                 Dim headerWidth = g.MeasureString(column.Text, source.Font).Width
    23.  
    24.                 'get the greatest pixel width of the subitems.
    25.                 Dim maxSubItemWidth = items.Max(Function(item) g.MeasureString(item.SubItems(column.Index).Text, source.Font).Width)
    26.  
    27.                 If maxSubItemWidth > headerWidth Then
    28.                     style = ColumnHeaderAutoResizeStyle.ColumnContent
    29.                 End If
    30.             End If
    31.  
    32.             column.AutoResize(style)
    33.         Next
    34.  
    35.         'Dispose the Graphics object if and only if we created one.
    36.         g?.Dispose()
    37.     End Sub
    38.  
    39.  
    40. End Module
    That would allow you to call it on the ListView itself, just as you would call the existing instance method with the same name. If you pass an argument of type ColumnHeaderAutoResizeStyle then it will invoke the existing instance method and if you don't pass any parameters it will invoke this instance method.
    vb.net Code:
    1. 'Call the instance method of the ListView class.
    2. ListView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
    3.  
    4. 'Call our new extension method.
    5. ListView1.AutoResizeColumns()

  6. #6

    Thread Starter
    Member
    Join Date
    Nov 2016
    Location
    UK
    Posts
    46

    Re: Auto resize ListView columns to fit either the header text or content

    After reading your post i was seeing that was the way to go using MeasureString thanks for updated version.
    Last edited by LucasCain; Jan 26th, 2021 at 10:16 PM.

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,302

    Re: Auto resize ListView columns to fit either the header text or content

    Team effort, baby!

    Actually, it occurred to me that that could be improved a little more. If there are no items then we can use the existing instance method, so we only need to use our own code if there are items:
    vb.net Code:
    1. Imports System.Runtime.CompilerServices
    2.  
    3. Public Module ListViewExtensions
    4.  
    5.     <Extension>
    6.     Public Sub AutoResizeColumns(source As ListView)
    7.         Dim items = source.Items.Cast(Of ListViewItem).ToArray()
    8.         Dim itemCount = items.Length
    9.  
    10.         If itemCount = 0 Then
    11.             source.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize)
    12.             Return
    13.         End If
    14.  
    15.         'Create a single Graphics object with which to measure all text.
    16.         Using g = source.CreateGraphics()
    17.             For Each column As ColumnHeader In source.Columns
    18.                 'Assume that we're autosizing based on the header unless determined otherwise.
    19.                 Dim style = ColumnHeaderAutoResizeStyle.HeaderSize
    20.  
    21.                 'Get the pixel width of the header text.
    22.                 Dim headerWidth = g.MeasureString(column.Text, source.Font).Width
    23.  
    24.                 'get the greatest pixel width of the subitems.
    25.                 Dim maxSubItemWidth = items.Max(Function(item) g.MeasureString(item.SubItems(column.Index).Text, source.Font).Width)
    26.  
    27.                 If maxSubItemWidth > headerWidth Then
    28.                     style = ColumnHeaderAutoResizeStyle.ColumnContent
    29.                 End If
    30.  
    31.                 column.AutoResize(style)
    32.             Next
    33.         End Using
    34.     End Sub
    35.  
    36. End Module

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width