3
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();
    }
} 

上記のコードでテストすると、パネルの一部が更新されません。新しいコントロールが追加されていない場所では、Clear() の前の古いコントロールを見ることができます。

panel.Controls.Clear();を前に置くと、ControlHelper.SuspendDrawing(panel);すべてが意図したとおりに機能します、回避しようとしているちらつきが見えます。

それで、ここで何が起こっているのですか?サスペンドの前または後にコントロールのコレクションをクリアするかどうかによって、どのように違いがありますか?

4

2 に答える 2

1

あなたのtarget.Refresh()呼び出しは、古いコントロールが削除された領域を完全に無効にするわけではありません。Control.Refresh()は「仮想」メソッドであるため、オーバーライドされる可能性があり、このような副作用が生じる可能性があります。

完全なカバレッジを保証するには、内でInvalidate(true)&Update()メソッドを使用する必要がありますResumeDrawing()。このInvalidate(true)メソッドは、コントロールの領域全体とすべての子コントロールを無効に設定Update()し、最後に一度だけすべてを再描画します。

また、これらのメソッドを .NET 拡張機能として実装することを検討する必要があります。これにより、拡張機能が宣言されている名前空間の USING があるすべてのSystem.Windows.Forms.ControlSuspendDrawing()にメソッドとメソッドが自動的に追加されます。ResumeDrawing()

[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();
}
于 2015-12-19T14:10:13.803 に答える