C# 防止在调整Windows窗体大小时重画控件
我有一个TableLayoutPanel,它在一个SplitterPanel中保存动态数量的控件。用户可能希望调整面板大小以适应这些控件,以避免使用滚动条。这会对容器大小以及容器内的控件产生抖动。有时,在调整大小期间,父容器明显滞后于鼠标的移动(最多滞后3秒)C# 防止在调整Windows窗体大小时重画控件,c#,winforms,vsto,C#,Winforms,Vsto,我有一个TableLayoutPanel,它在一个SplitterPanel中保存动态数量的控件。用户可能希望调整面板大小以适应这些控件,以避免使用滚动条。这会对容器大小以及容器内的控件产生抖动。有时,在调整大小期间,父容器明显滞后于鼠标的移动(最多滞后3秒) 是否有任何方法可以防止在父容器调整大小期间重画控件,例如在调整大小期间隐藏所有元素或停止在鼠标拖动期间发生的调整大小事件,仅在onMouseUp事件时触发?您可以连接父容器的resize事件,并将e.Handled或e.Cancel属性设
是否有任何方法可以防止在父容器调整大小期间重画控件,例如在调整大小期间隐藏所有元素或停止在鼠标拖动期间发生的调整大小事件,仅在onMouseUp事件时触发?您可以连接父容器的resize事件,并将e.Handled或e.Cancel属性设置为true,然后在onMouseUp上手动重画。您可以连接父容器的resize事件,并将e.Handled或e.Cancel属性设置为true,然后在上手动重画在MouseUp上。正如Hans评论的那样,
SuspendLayout
和ResumeLayout
在这种情况下运行良好,同时暂停容器控件的绘图:
public static class Win32 {
public const int WM_SETREDRAW = 0x0b;
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public static void SuspendPainting(IntPtr hWnd) {
SendMessage(hWnd, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
}
public static void ResumePainting(IntPtr hWnd) {
SendMessage(hWnd, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
}
}
然后从中调整事件的大小:
private void Form1_ResizeBegin(object sender, EventArgs e) {
tableLayoutPanel1.SuspendLayout();
}
private void Form1_ResizeEnd(object sender, EventArgs e) {
Win32.SuspendPainting(tableLayoutPanel1.Handle);
tableLayoutPanel1.ResumeLayout();
Win32.ResumePainting(tableLayoutPanel1.Handle);
this.Refresh();
}
正如Hans所评论的,
SuspendLayout
和ResumeLayout
在这种情况下运行良好,同时暂停容器控件的绘图:
public static class Win32 {
public const int WM_SETREDRAW = 0x0b;
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public static void SuspendPainting(IntPtr hWnd) {
SendMessage(hWnd, WM_SETREDRAW, (IntPtr)0, IntPtr.Zero);
}
public static void ResumePainting(IntPtr hWnd) {
SendMessage(hWnd, WM_SETREDRAW, (IntPtr)1, IntPtr.Zero);
}
}
然后从中调整事件的大小:
private void Form1_ResizeBegin(object sender, EventArgs e) {
tableLayoutPanel1.SuspendLayout();
}
private void Form1_ResizeEnd(object sender, EventArgs e) {
Win32.SuspendPainting(tableLayoutPanel1.Handle);
tableLayoutPanel1.ResumeLayout();
Win32.ResumePainting(tableLayoutPanel1.Handle);
this.Refresh();
}
对我来说,将TableLayoutPanel设置为双缓冲区效果很好,然后我甚至不需要暂停布局。我在这个线程上找到了解决方案:使用这个网站上的双缓冲TableLayoutPanel类:
在这之后,我所需要做的就是,在重建项目并重新启动Visual Studio几次之后(为了使InitializeComponent()工作),进入.Designer.cs文件并将System.Windows.Forms.TableLayoutPanel类更改为新的DBLayoutPanel类。进入设计器文件并更改其中的类有助于节省时间,因为我在TableLayoutPanel中已经有很多控件。对我来说,将TableLayoutPanel设置为双缓冲区效果很好,然后我甚至不需要暂停布局。我在这个线程上找到了解决方案:使用这个网站上的双缓冲TableLayoutPanel类:
在这之后,我所需要做的就是,在重建项目并重新启动Visual Studio几次之后(为了使InitializeComponent()工作),进入.Designer.cs文件并将System.Windows.Forms.TableLayoutPanel类更改为新的DBLayoutPanel类。进入设计器文件并更改其中的类有助于节省时间,因为我在TableLayoutPanel中已经有很多控件。调用控件的SuspendLayout和ResumeLayout方法可以有所帮助的少数情况之一。它使TLP内容保持可见,并在调整大小时不闪烁。保持重绘抑制,将其环绕在ResumeLayout周围,使其不会绘制两次。@HansPassant先绘制还是先绘制有关系,SuspendPaint vs SuspendLayout?将SuspendPaint放在ResumeLayout()之前,然后再绘制ResumeLayout()。ResizeBegin只需要调用SuspendLayout。@HansPassant非常感谢这些提示。调用控件的SuspendLayout和ResumeLayout方法可以有所帮助的少数情况之一。它使TLP内容保持可见,并在调整大小时不闪烁。保持重绘抑制,将其环绕在ResumeLayout周围,使其不会绘制两次。@HansPassant先绘制还是先绘制有关系,SuspendPaint vs SuspendLayout?将SuspendPaint放在ResumeLayout()之前,然后再绘制ResumeLayout()。ResizeBegin只需要调用SuspendLayout。@HansPassant感谢您的提示。