25

we use this two methods to adjust column length based on Column content and header resp.

ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

But how to adjust based on both? i.e. adjust to the longest length for header and column content.

william007
  • 17,375
  • 25
  • 118
  • 194

8 Answers8

30

lvw.Columns[0].Width = -2

See remarks in MSDN for details: http://msdn.microsoft.com/en-us/library/system.windows.forms.columnheader.width.aspx

Also note that MSDN says that 'To autosize to the width of the column heading, set the Width property to -2.', but actually it works for column heading AND column contents.

Here is a code to prove that:

    lvw.Columns.Add(new String('x', 25));   // short header
    lvw.Items.Add(new String('x', 100));    // long content

    lvw.Columns[0].Width = -2;
    // in result column width will be set to fit content
Anton Kedrov
  • 1,767
  • 2
  • 13
  • 20
  • 1
    I do not think this is right, even the MSDN says: _To autosize to the width of the column heading, set the Width property to -2_. So it resizes based on header only, not both header and contents. – Martin Prikryl Dec 05 '13 at 09:33
  • Sorry if MSDN link mislead you. It was intended to show that this is legal to use this magic numbers. '-2' considers both, header AND contents. I have changed my answer to clarify this. – Anton Kedrov Dec 05 '13 at 12:38
  • I believe neither you nor MSDN are correct. From my testing, what you claim to be generally true is correct only for the last column in the view. For the last column the `-2` (or `LVSCW_AUTOSIZE_USEHEADER`) value, according to [`ListView_SetColumnWidth` macro](http://msdn.microsoft.com/en-us/library/windows/desktop/bb775074.aspx) doc, _width is set to fill the remaining width of the list-view control_. But actually it sets it to maximum of the remaining width and column or header contents length. But that's for the last column only. What works in your example as you have one column only. – Martin Prikryl Dec 07 '13 at 12:53
  • this solution is best if you are updating data once but if you are updating data again and again the i just create a ListViewitem with header text filled in each subitem and then just call re size on column content and then simply remove my added item this will reduce force re sizing for each column – Jack Gajanan Feb 03 '16 at 07:45
  • i have added code as new answer if it helps to some one – Jack Gajanan Feb 03 '16 at 07:46
  • In my tests I had two columns. When using -2 and having the contents of the column header larger than the contents of the column itself it ended up have a column header that was cut off. Maybe I'm missing something but I don't see how this answer has gotten so many upvotes. This is flat out not the correct solution. Tanguy's answer is simple and works perfectly. – Arvo Bowen May 26 '16 at 00:59
23

As answered here, calling both resizing options do the job :

myListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
myListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
Community
  • 1
  • 1
Tanguy
  • 351
  • 2
  • 6
  • 2
    It works, but it's weird: if the order of the calls is inverted it doesn't. – Angelo Mascaro Sep 30 '16 at 09:06
  • It works, but if the contents are very long it won't go past a certain limit, at least for an ObjectListView. Ended up using a variation of matsolof's answer. – AlexDev Mar 07 '17 at 15:53
9

This is what I use to adjust column width to both content and header:

public static void autoResizeColumns(ListView lv)
{
    lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
    ListView.ColumnHeaderCollection cc = lv.Columns;
    for (int i = 0; i < cc.Count; i++)
    {
        int colWidth = TextRenderer.MeasureText(cc[i].Text, lv.Font).Width + 10;
        if (colWidth > cc[i].Width)
        {
            cc[i].Width = colWidth;
        }
    }
}

Example use:

autoResizeColumns(listView1);

The method isn't that well tested, but at least it works in the context I'm using it in.

matsolof
  • 245
  • 2
  • 6
  • Thank you! This works well for me. Might I suggest you use capital letters for function names? In this case it will look like the original name, so instead I used: AutoResizeColumnsCustom. – goamn Jun 04 '14 at 23:07
  • I know it's conventional to use capital letters for function names. The reason I start the name of a function I've written with a lowercase letter is to not confuse such a function with a built-in C# function. – matsolof Jun 05 '14 at 06:52
1

It's possible indeed to use MeasureText and then to calculate how much space is left and somehow distribute between all columns. But this is quick-and-dirty approach which I have quickly coded:

    /// <summary>
    /// Enables autoresizing for specific listview.
    /// You can specify how much to scale in columnScaleNumbers array - length of that array
    /// should match column count which you have.
    /// </summary>
    /// <param name="listView">control for which to enable auto-resize</param>
    /// <param name="columnScaleNumbers">Percentage or numbers how much each column will be scaled.</param>
    private void EnableAutoresize(ListView listView, params int[] columnScaleNumbers)
    {
        listView.View = View.Details;
        for( int i = 0; i < columnScaleNumbers.Length; i++ )
        {
            if( i >= listView.Columns.Count )
                break;
            listView.Columns[i].Tag = columnScaleNumbers[i];
        }

        listView.SizeChanged += lvw_SizeChanged;
        DoResize(listView);
    }

    void lvw_SizeChanged(object sender, EventArgs e)
    {
        ListView listView = sender as ListView;
        DoResize(listView);
    }

    bool Resizing = false;
    void DoResize( ListView listView )
    {
        // Don't allow overlapping of SizeChanged calls
        if (!Resizing)
        {
            // Set the resizing flag
            Resizing = true;

            if (listView != null)
            {
                float totalColumnWidth = 0;

                // Get the sum of all column tags
                for (int i = 0; i < listView.Columns.Count; i++)
                    totalColumnWidth += Convert.ToInt32(listView.Columns[i].Tag);

                // Calculate the percentage of space each column should 
                // occupy in reference to the other columns and then set the 
                // width of the column to that percentage of the visible space.
                for (int i = 0; i < listView.Columns.Count; i++)
                {
                    float colPercentage = (Convert.ToInt32(listView.Columns[i].Tag) / totalColumnWidth);
                    listView.Columns[i].Width = (int)(colPercentage * listView.ClientRectangle.Width);
                }
            }
        }

        // Clear the resizing flag
        Resizing = false;            
    }

And depending how many columns you have - you specify each column "percentage" or simply number. For example for 3 columns - call looks like this:

        EnableAutoresize(listView1, 6, 3, 1);

This will distribute column sizes as: 6 * 100% / (6 + 3 + 1) = 60% for first column, 30% for next and 10% for remaining.

This is somehow poor man quick implementation. :-)

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
0

In my case, I do this through the next steps (for two columns of data):

  1. Creating a ColumnHeader object for each column.
  2. Setting the size by AutoResize based on HeaderSize (on both columns)
  3. Store that value in a Integer variable
  4. Setting the size by AutoResize based on ColumnContent (on both columns)
  5. Updating the value of each Integer variable through the Max criteria between the old value and the new value (for each column).
  6. Setting the column width size for each ColumnHeader object.

In VB.NET:

'Create two header objects as ColumnHeader Class
Dim header1, header2 As ColumnHeader

'Construcción de los objetos header
header1 = New ColumnHeader
header1.Text = "ID"
header1.TextAlign = HorizontalAlignment.Right
header1.Width = 10

header2 = New ColumnHeader
header2.Text = "Combinaciones a Procesar"
header2.TextAlign = HorizontalAlignment.Left
header2.Width = 10

'Add two columns using your news headers objects 
ListView.Columns.Add(header1)
ListView.Columns.Add(header2)

'Fill three rows of data, for each column
ListView.Items.Add(New ListViewItem({"A1", "B1"}))
ListView.Items.Add(New ListViewItem({"A2", "B2"}))
ListView.Items.Add(New ListViewItem({"A3", "B3"}))

'Change the size of each column
Dim headsz1, headsz2 As Integer
SelectionInTable.ListView.AutoResizeColumn(0,             ColumnHeaderAutoResizeStyle.HeaderSize)
SelectionInTable.ListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.HeaderSize)
headsz1 = header1.Width
headsz2 = header2.Width
SelectionInTable.ListView.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent)
SelectionInTable.ListView.AutoResizeColumn(1,     ColumnHeaderAutoResizeStyle.ColumnContent)
headsz1 = Math.Max(headsz1, header1.Width)
headsz2 = Math.Max(headsz2, header2.Width)
header1.Width = headsz1
header2.Width = headsz2
Asrhael
  • 149
  • 1
  • 1
  • 7
0

Here's a C# solution that can be used for any ListView. It assumes your column count and headers won't change for any given list view. Get rid of the listViewHeaderWidths dictionary if you want to recalculate header widths every time (if headers change, or number of columns changes).

    private Dictionary<string, int[]> listViewHeaderWidths = new Dictionary<string, int[]>();    
    private void ResizeListViewColumns(ListView lv)
    {
        int[] headerWidths = listViewHeaderWidths.ContainsKey(lv.Name) ? listViewHeaderWidths[lv.Name] : null;

        lv.BeginUpdate();

        if (headerWidths == null)
        {
            lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

            headerWidths = new int[lv.Columns.Count];

            for (int i = 0; i < lv.Columns.Count; i++)
            {
                headerWidths[i] = lv.Columns[i].Width;
            }

            listViewHeaderWidths.Add(lv.Name, headerWidths);
        }

        lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

        for(int j = 0; j < lv.Columns.Count; j++)
        {
            lv.Columns[j].Width = Math.Max(lv.Columns[j].Width, headerWidths[j]);
        }

        lv.EndUpdate();
    }
GreggD
  • 131
  • 1
  • 3
0

Anton Kedrov answer is best one but in my case i have a listview with more than 50 columns and i update its data frequently in this case i notice listview's this.AutoResizeColumns performs much faster work so i m writing this solution also

First Method by setting with to -2

public void AutoUpdateColumnWidth(ListView lv)
{
    for (int i = 0; i <= lv.Columns.Count - 1; i++) {
        lv.Columns(i).Width = -2;
    }
}

Second method i used (less flicker on multiple calls)

public void AutoUpdateColumnWidth(ListView lv)
{
    ListViewItem nLstItem = new ListViewItem(lv.Columns(0).Text);
    for (int i = 1; i <= lv.Columns.Count - 1; i++) {
        nLstItem.SubItems.Add(lv.Columns(i).Text);
    }
    v.Items.Add(nLstItem);
    lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
    lv.Items.RemoveAt(nLstItem.Index);
}
Jack Gajanan
  • 1,596
  • 14
  • 18
0

This is simple (although it took me a while to figure out)...

We know that the width must be at least as great as the column headers, so that we see all of the header text. Beyond that, the width can expand larger to accommodate contents. Hence, we do the following:

  1. Autosize the columns to header.
  2. Iterate through the columns and set the minimum width property for each column to the current column width (which guarantees your columns will never get too small to see the header).
  3. From now on, autosize columns by content.

It is not necessary to track widths separately and reset them as other posters suggest. Setting the minimum width for the column solves the issue until the header text is changed, in which case you set the minimum width to 0, autosize just the modified column, and then set the minimum width to the current width again.

EDIT: My apologies, I forgot that I was not using the standard listview, but instead the 3rd party product BetterListView (a free version is available). The standard listview columns don't appear to support minimum width. I do recommend BetterListView highly as a great alternative (much better feature set and performance).

Ben W.
  • 23
  • 1
  • 6