ListView Final Column Autosize 创建滚动条

4 c# listview winforms

我正在实现一个派生自 ListView 的自定义控件。

我希望最后一列填充剩余空间(这是一个很常见的任务),我已经通过重写 OnResize 方法来解决这个问题:

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

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

或通过另一种方法:

        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;
    }
Run Code Online (Sandbox Code Playgroud)

编辑:

在我将 ListView 停靠到父容器并通过该控件调整大小之前,这一切正常。每当控件大小缩小时(即,将边框拖动一个像素),我就会在底部看到一个滚动条,它根本无法移动(甚至不能移动一个像素)。

其结果是,当我拖动父级的大小时,ListView 中会留下一个闪烁的滚动条,并且当​​拖动停止时,它有 50% 的机会出现在那里。

Gra*_*ian 5

ObjectListView(.NET WinForms ListView 的开源包装器)允许这种“扩展最后一列以填充可用空间”。事实上,要正确地做起来比乍看起来更困难——不要相信任何人告诉你的不是这样的:)

如果您使用 ObjectListView,您就可以免费获得该问题以及其他几个问题的解决方案。但如果您想自己完成所有工作,您需要:

  • 使用 ClientSize 而不是 DisplayRectangle (正如 @zxpro 已经说过的)
  • 使用布局事件而不是调整大小事件。
  • 侦听 ColumnResized 事件并执行相同的工作
  • 不要在设计模式下自动调整大小——这会变得非常混乱。

最棘手的问题只有在窗口缩小时才会出现——水平滚动条令人讨厌地闪烁,有时在缩小完成后仍然存在。这似乎正是您的情况所发生的情况。

解决方案是拦截 WM_WINDOWPOSCHANGING 消息并将 ListView 的大小调整为新的大小。

protected override void WndProc(ref Message m) {
    switch (m.Msg) {
        case 0x46: // WM_WINDOWPOSCHANGING
            this.HandleWindowPosChanging(ref m);
            base.WndProc(ref m);
            break;
        default:
            base.WndProc(ref m);
            break;
    }
}

protected virtual void HandleWindowPosChanging(ref Message m) {
    const int SWP_NOSIZE = 1;

    NativeMethods.WINDOWPOS pos = (NativeMethods.WINDOWPOS)m.GetLParam(typeof(NativeMethods.WINDOWPOS));
    if ((pos.flags & SWP_NOSIZE) == 0) {
        if (pos.cx < this.Bounds.Width) // only when shrinking
            // pos.cx is the window width, not the client area width, so we have to subtract the border widths
            this.ResizeFreeSpaceFillingColumns(pos.cx - (this.Bounds.Width - this.ClientSize.Width));
    }
}
Run Code Online (Sandbox Code Playgroud)