11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WinForms向け、(安全に)画面描画を抑制するためのサンプル

Last updated at Posted at 2019-03-06

#はじめに
コントロールの描画を一時的に止めたい場合、該当する(一番上の)コントロールへ 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クラスの場合は、抜け出すときにフォームの再描画も自動で行われます。

11
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?