ListView Final Column Autosize creates scrollbar

2020-03-24 05:11发布

I am implementing a custom control which derives from ListView.

I would like for the final column to fill the remaining space (Quite a common task), I have gone about this via overriding the OnResize method:

     protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);

        if (Columns.Count == 0)
            return;
        Columns[Columns.Count - 1].Width = -2; // -2 = Fill remaining space
    }

or via another method:

        protected override void OnResize(EventArgs e)
    {

        base.OnResize(e);

        if (!_autoFillLastColumn)
            return;

        if (Columns.Count == 0)
            return;

        int TotalWidth = 0;
        int i = 0;
        for (; i < Columns.Count - 1; i++)
        {
            TotalWidth += Columns[i].Width;
        }

        Columns[i].Width = this.DisplayRectangle.Width - TotalWidth;
    }

Edit:

This works fine until I dock the ListView into a parent container and resize via that control. Every second time the control size shrinks (IE, drag the the border one pixel), I get a scroll bar on the bottom which can't move at all (not even one pixel).

The result of which is when I drag the size of the parent I am left with a flickering scroll bar in the ListView, and a 50% chance it will be there when the dragging stops.

8条回答
家丑人穷心不美
2楼-- · 2020-03-24 05:56

Try using the ClientSize property. As MSDN puts it:

The client area of a control is the bounds of the control, minus the nonclient elements such as scroll bars, borders, title bars, and menus.

Edit: I've added a code sample demonstrating how achieve different fill behaviors.

public class MyListView : ListView
{
    public MyListView()
    {
        View = View.Details;
        Columns.Add(Column1);
        Columns.Add(Column2);
        Columns.Add(Column3);
    }

    private readonly ColumnHeader Column1 = new ColumnHeader();
    private readonly ColumnHeader Column2 = new ColumnHeader();
    private readonly ColumnHeader Column3 = new ColumnHeader();

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);

        // Constant width
        Column1.Width = 200;
        // 50% of the ListView's width
        Column2.Width = (ClientSize.Width/2);
        // Fill the remaining width, but no less than 100 px
        Column3.Width = Math.Max(100, ClientSize.Width - (Column1.Width + Column2.Width));
    }
}
查看更多
一纸荒年 Trace。
3楼-- · 2020-03-24 05:59

When a form containing a listview is restored to FormWindowState.Normal from a maximized state, horizontal scroll bar is displayed even though column widths have been correctly adjusted. This happens when the resized column width shrinks but not when it grows. Here's a hack that can correct this without resorting to win32 calls. (magic number [-2] is just a simple shortcut)

        // Member variable.
        private ListView myListView;

        // Method to resize last column.
        private void ResizeColumn(int width) {
              myListView.Columns[myListView.Columns.Count - 1].Width = width;
        }                  

        // ListView ClientSizeChanged event handler.
        private void Process_ListViewClientSizeChanged(object sender, EventArgs e)
        {
              // Get the width to resize the last column.
              int width = myListView.ClientSize.Width;
              for (int i = 0; i < myListView.Columns.Count - 1; i++)
                    width -= myListView.Columns[i].Width;

              // Last column width is growing. Use magic number to resize.
              if (width >= myListView.Columns[myListView.Columns.Count - 1].Width)
                    myListView.Columns[myListView.Columns.Count - 1].Width = -2;

              // Last column width is shrinking. 
              // Asynchronously invoke a method to resize the last column.
              else
                    myListView.BeginInvoke
                          ((MethodInvoker)delegate { ResizeColumn(width); });
        }
查看更多
登录 后发表回答