我正在实现一个派生自 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% 的机会出现在那里。
ObjectListView(.NET WinForms ListView 的开源包装器)允许这种“扩展最后一列以填充可用空间”。事实上,要正确地做起来比乍看起来更困难——不要相信任何人告诉你的不是这样的:)
如果您使用 ObjectListView,您就可以免费获得该问题以及其他几个问题的解决方案。但如果您想自己完成所有工作,您需要:
最棘手的问题只有在窗口缩小时才会出现——水平滚动条令人讨厌地闪烁,有时在缩小完成后仍然存在。这似乎正是您的情况所发生的情况。
解决方案是拦截 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)