C# 向面板发送WM_SETREDRAW消息后刷新

C# 向面板发送WM_SETREDRAW消息后刷新,c#,refresh,panel,redraw,C#,Refresh,Panel,Redraw,如果我使用上面的代码进行测试,面板的某些部分不会被刷新。 在未添加新控件的位置上,可以看到Clear()之前的旧控件 如果我放置面板.Controls.Clear()在ControlHelper.SuspendDrawing(面板)之前一切都按预期进行但是一些闪烁是可见的,这是我试图避免的 这是怎么回事?根据我是在挂起之前还是之后清除控件集合,如何才能发挥作用?您的target.Refresh()调用不会完全使删除旧控件的区域无效。因为它是一个“虚拟”方法,所以它可能会被重写,并且可能会产生这样

如果我使用上面的代码进行测试,面板的某些部分不会被刷新。 在未添加新控件的位置上,可以看到Clear()之前的旧控件

如果我放置
面板.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();
}