C# 向面板发送WM_SETREDRAW消息后刷新
如果我使用上面的代码进行测试,面板的某些部分不会被刷新。 在未添加新控件的位置上,可以看到Clear()之前的旧控件 如果我放置C# 向面板发送WM_SETREDRAW消息后刷新,c#,refresh,panel,redraw,C#,Refresh,Panel,Redraw,如果我使用上面的代码进行测试,面板的某些部分不会被刷新。 在未添加新控件的位置上,可以看到Clear()之前的旧控件 如果我放置面板.Controls.Clear()在ControlHelper.SuspendDrawing(面板)之前一切都按预期进行但是一些闪烁是可见的,这是我试图避免的 这是怎么回事?根据我是在挂起之前还是之后清除控件集合,如何才能发挥作用?您的target.Refresh()调用不会完全使删除旧控件的区域无效。因为它是一个“虚拟”方法,所以它可能会被重写,并且可能会产生这样
面板.Controls.Clear()代码>在ControlHelper.SuspendDrawing(面板)之前代码>一切都按预期进行但是一些闪烁是可见的,这是我试图避免的
这是怎么回事?根据我是在挂起之前还是之后清除控件集合,如何才能发挥作用?您的target.Refresh()
调用不会完全使删除旧控件的区域无效。因为它是一个“虚拟”方法,所以它可能会被重写,并且可能会产生这样的副作用
为了保证完全覆盖,您应该使用ResumeDrawing()
中的Invalidate(true)
和Update()
方法。Invalidate(true)
方法将控件和所有子控件的整个区域设置为无效,并且Update()
方法将在最后只重新绘制一次所有内容
也应考虑将这些方法实现为.NET扩展。
这将自动将
SuspendDrawing()
和ResumeDrawing()
方法添加到每个System.Windows.Forms.Control中,其中您对声明扩展的命名空间有一个用法:
ControlHelper.SuspendDrawing(panel);
panel.Controls.Clear();
AddItemIdLabel();
AddLastEditedLabel();
AddDeleteButton();
AddSaveButton();
ControlHelper.ResumeDrawing(panel);
public static class ControlHelper
{
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
private const int WM_SETREDRAW = 0xB;
public static void SuspendDrawing(Control target)
{
SendMessage(target.Handle, WM_SETREDRAW, 0, 0);
}
public static void ResumeDrawing(Control target)
{
SendMessage(target.Handle, WM_SETREDRAW, 1, 0);
target.Refresh();
}
}
注意,提到的PInvoke是不正确的。应该是这样的:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);
private const int WM_SETREDRAW = 11;
public static void SuspendDrawing(this Control Target)
{
SendMessage(Target.Handle, WM_SETREDRAW, false, 0);
}
public static void ResumeDrawing(this Control Target)
{
SendMessage(Target.Handle, WM_SETREDRAW, true, 0);
Target.Invalidate(true);
Target.Update();
}
特别是返回类型为IntPtr而不是int(64位上的8字节而不是4字节)可能会随机导致运行时崩溃
资料来源:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);
private const int WM_SETREDRAW = 11;
public static void SuspendDrawing(this Control Target)
{
SendMessage(Target.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
}
public static void ResumeDrawing(this Control Target)
{
SendMessage(Target.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
Target.Invalidate(true);
Target.Update();
}