#はじめに
コントロールの描画を一時的に止めたい場合、該当する(一番上の)コントロールへ WM_SETREDRAW メッセージを送ることで制御できます。
.NET Framework で Windows Forms 上の描画をコントロールするクラスを作ってみました。
※2019/3/12 Form に特化したクラスを追加
#コード
using ステートメントを利用する仕組みで、解除漏れを防いでいます。
Program.cs
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var sus = new RedrawSuspension(this.Handle))
{
// このなかでフォームの描画が抑制されます
}
this.Refresh(); // これを忘れると抑制解除したあとで描画が行われません
}
// ※2019/3/12 追加:こちらのほうがより安全
private void button2_Click(object sender, EventArgs e)
{
using (var sus = new FormRedrawSuspension(this))
{
// このなかでフォームの描画が抑制されます
}
// 抜けるとき(FormRedrawSuspensionオブジェクトがDisposeされるとき)に、フォームがRefreshされます。
}
/// <summary>
/// ※こちらは初代:FormRedrawSuspension のほうをおすすめします
/// コントロールの画面描画抑制を制御するオブジェクトを提供します。
/// </summary>
private class RedrawSuspension : IDisposable
{
private IntPtr _hWnd;
/// <summary>
/// オブジェクトを構築し、画面描画を抑制します。オブジェクトを破棄すると画面描画抑制が解除されます。
/// </summary>
/// <param name="hWnd">ウインドウハンドル</param>
public RedrawSuspension(IntPtr hWnd)
{
_hWnd = hWnd;
SendSetRedrawMessage(false);
}
/// <summary>
/// 画面描画抑制を解除して、オブジェクトを破棄します。
/// </summary>
public void Dispose()
{
SendSetRedrawMessage(true);
}
private void SendSetRedrawMessage(bool enableRedraw)
{
NativeMethods.SendMessage(_hWnd, NativeMethods.WM_SETREDRAW, enableRedraw ? new IntPtr(1) : IntPtr.Zero, IntPtr.Zero);
}
private class NativeMethods
{
// https://docs.microsoft.com/ja-jp/visualstudio/code-quality/ca1060-move-p-invokes-to-nativemethods-class
private NativeMethods() { }
[DllImport("user32.dll")]
internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 dwMsg, IntPtr wParam, IntPtr lParam);
internal const UInt32 WM_SETREDRAW = 11;
}
}
/// <summary>
/// ※2019/3/12 追加
/// フォームの画面描画抑制を制御するオブジェクトを提供します。
/// </summary>
internal class FormRedrawSuspension : IDisposable
{
private System.Windows.Forms.Form _form;
/// <summary>
/// オブジェクトを構築し、画面描画を抑制します。オブジェクトを破棄すると画面描画抑制が解除されます。
/// </summary>
/// <param name="form">制御するフォーム</param>
public FormRedrawSuspension(System.Windows.Forms.Form form)
{
_form = form;
SendSetRedrawMessage(false);
}
/// <summary>
/// 画面描画抑制を解除してフォームを再描画させ、オブジェクトを破棄します。
/// </summary>
public void Dispose()
{
SendSetRedrawMessage(true);
_form.Refresh();
}
private void SendSetRedrawMessage(bool enableRedraw)
{
NativeMethods.SendMessage(_form.Handle, NativeMethods.WM_SETREDRAW, enableRedraw ? new IntPtr(1) : IntPtr.Zero, IntPtr.Zero);
}
private class NativeMethods
{
// https://docs.microsoft.com/ja-jp/visualstudio/code-quality/ca1060-move-p-invokes-to-nativemethods-class
private NativeMethods() { }
[DllImport("user32.dll")]
internal static extern IntPtr SendMessage(IntPtr hWnd, UInt32 dwMsg, IntPtr wParam, IntPtr lParam);
internal const UInt32 WM_SETREDRAW = 11;
}
}
}
}
#使い方
コードにも載せましたが、FormRedrawSuspension(またはRedrawSuspension) クラスのオブジェクトを using ステートメントで括って生成させると、usingステートメント内では描画が抑制され、抜け出す(=オブジェクトを破棄する)ときに描画抑制が解除されます。FormRedrawSuspensionクラスの場合は、抜け出すときにフォームの再描画も自動で行われます。