【问题标题】:ListView AutoResizeColumns based on both Column content and headerListView AutoResizeColumns 基于 Column 内容和标题
【发布时间】:2012-12-17 11:30:55
【问题描述】:

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

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

但是如何根据两者进行调整呢?即调整到标题和列内容的最长长度。

【问题讨论】:

  • 这似乎是“边问边回答”类型的问题之一。

标签: c# winforms visual-studio-2010


【解决方案1】:

lvw.Columns[0].Width = -2

详见MSDN备注: http://msdn.microsoft.com/en-us/library/system.windows.forms.columnheader.width.aspx

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

这里有一段代码可以证明:

    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

【讨论】:

  • 我不认为这是正确的,甚至 MSDN 也说:要自动调整为列标题的宽度,请将 Width 属性设置为 -2。所以它只根据标题调整大小,而不是标题和内容。
  • 对不起,如果 MSDN 链接误导了您。其目的是表明使用这个幻数是合法的。 '-2' 同时考虑标题和内容。我已更改答案以澄清这一点。
  • 我相信你和 MSDN 都不对。根据我的测试,您声称通常正确的内容仅对视图中的最后一列是正确的。对于最后一列-2(或LVSCW_AUTOSIZE_USEHEADER)值,根据ListView_SetColumnWidth macro doc,宽度设置为填充列表视图控件的剩余宽度。但实际上它将其设置为剩余宽度和列或标题内容长度的最大值。但这仅适用于最后一列。在您的示例中有效,因为您只有一列。
  • 如果您只更新一次数据但如果您一次又一次地更新数据,我只需创建一个 ListViewitem 并在每个子项中填充标题文本,然后在列内容上调用 re size 和然后只需删除我添加的项目,这将减少每列的强制调整大小
  • 如果对某人有帮助,我已添加代码作为新答案
【解决方案2】:

正如here 的回答,调用这两个调整大小选项就可以了:

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

【讨论】:

  • 它有效,但很奇怪:如果调用的顺序颠倒了它就不会。
  • 它可以工作,但如果内容很长,它不会超过一定的限制,至少对于 ObjectListView。最终使用了 matsolof 答案的变体。
【解决方案3】:

这是我用来调整内容和标题的列宽:

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

使用示例:

autoResizeColumns(listView1);

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

【讨论】:

  • 谢谢!这对我很有效。我可以建议您使用大写字母作为函数名称吗?在这种情况下,它将看起来像原始名称,所以我使用:AutoResizeColumnsCustom.
  • 我知道在函数名中使用大写字母是惯例。我以小写字母开头的函数名称的原因是不要将此类函数与内置 C# 函数混淆。
【解决方案4】:

确实可以使用 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;            
    }

取决于你有多少列 - 你指定每列“百分比”或简单的数字。例如 3 列 - 调用如下所示:

        EnableAutoresize(listView1, 6, 3, 1);

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

这在某种程度上是穷人的快速实施。 :-)

【讨论】:

    【解决方案5】:

    在我的情况下,我通过接下来的步骤(对于两列数据)执行此操作:

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

    在 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
    

    【讨论】:

      【解决方案6】:

      这是一个可用于任何 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();
          }
      

      【讨论】:

        【解决方案7】:

        Anton Kedrov 的答案是最好的,但在我的情况下,我有一个超过 50 列的列表视图,我经常更新它的数据,在这种情况下我注意到列表视图的 this.AutoResizeColumns 执行更快的工作,所以我也在编写这个解决方案

        第一种方法,设置为 -2

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

        我使用的第二种方法(多次调用时闪烁较少)

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

        【讨论】:

          【解决方案8】:

          这很简单(虽然我花了一段时间才弄明白)...

          我们知道宽度必须至少与列标题一样大,这样我们才能看到所有标题文本。除此之外,宽度可以扩大以容纳内容。因此,我们执行以下操作:

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

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

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

          【讨论】:

            猜你喜欢
            • 2019-11-21
            • 2014-12-09
            • 1970-01-01
            • 2017-11-26
            • 2020-10-21
            • 2013-03-17
            • 2011-04-26
            • 1970-01-01
            • 2016-06-16
            相关资源
            最近更新 更多