C# 基于列内容和标题的 ListView AutoResizeColumns

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14133225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:46:17  来源:igfitidea点击:

ListView AutoResizeColumns based on both Column content and header

c#winformsvisual-studio-2010

提问by william007

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

我们使用这两种方法根据列内容和标题分别调整列长度。

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

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.

但是如何基于两者进行调整?即调整为标题和列内容的最长长度。

回答by Anton Kedrov

lvw.Columns[0].Width = -2

lvw.Columns[0].Width = -2

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

有关详细信息,请参阅 MSDN 中的备注: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.

另请注意,MSDN 说“要自动调整到列标题的宽度,请将 Width 属性设置为 -2。”,但实际上它适用于列标题和列内容。

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

回答by matsolof

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.

该方法没有经过很好的测试,但至少它在我使用它的上下文中有效。

回答by Tanguy

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

正如这里所回答的,调用这两个调整大小选项可以完成这项工作:

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

回答by Asrhael

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.
  1. 为每列创建一个 ColumnHeader 对象。
  2. 根据 HeaderSize(在两列上)通过 AutoResize 设置大小
  3. 将该值存储在整数变量中
  4. 根据 ColumnContent(在两列上)通过 AutoResize 设置大小
  5. 通过旧值和新值之间的 Max 条件更新每个 Integer 变量的值(对于每列)。
  6. 为每个 ColumnHeader 对象设置列宽大小。

In VB.NET:

在 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

回答by GreggD

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).

这是可用于任何 ListView 的 C# 解决方案。它假设您的列数和标题对于任何给定的列表视图都不会更改。如果您想每次都重新计算标题宽度(如果标题更改或列数更改),请摆脱 listViewHeaderWidths 字典。

    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();
    }

回答by Hyman Gajanan

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

Anton Kedrov 的答案是最好的,但就我而言,我有一个包含 50 多列的列表视图,在这种情况下我经常更新其数据,我注意到列表视图的 this.AutoResizeColumns 执行速度更快,因此我也在编写此解决方案

First Method by setting with to -2

通过设置为 -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);
}

回答by TarmoPikaro

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:

确实可以使用 MeasureText 然后计算剩余的空间并以某种方式分布在所有列之间。但这是我快速编码的快速而肮脏的方法:

    /// <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:

并根据您拥有的列数 - 您指定每一列的“百分比”或简单的数字。例如对于 3 列 - 调用如下所示:

        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.

这会将列大小分配为:6 * 100% / (6 + 3 + 1) = 60% 用于第一列,30% 用于下一列,10% 用于剩余。

This is somehow poor man quick implementation. :-)

这是不知何故的穷人快速实施。:-)

回答by Ben W.

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 largerto 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.
  1. 将列自动调整为标题。
  2. 遍历列并将每列的最小宽度属性设置为当前列宽(这保证您的列永远不会太小而无法看到标题)。
  3. 从现在开始,按内容自动调整列大小。

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.

没有必要像其他海报建议的那样单独跟踪宽度并重置它们。设置列的最小宽度可以解决问题,直到更改标题文本,在这种情况下,您将最小宽度设置为 0,仅自动调整修改后的列的大小,然后再次将最小宽度设置为当前宽度。

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).

编辑:抱歉,我忘了我没有使用标准的列表视图,而是使用了 3rd 方产品 BetterListView(有免费版本)。标准列表视图列似乎不支持最小宽度。我强烈推荐 BetterListView 作为一个很好的选择(更好的功能集和性能)。