【C#】Winform 令人困擾的畫面閃爍問題解法

DoubleBuffered = true

如果 Control 沒有這個屬性,可以使用我下列擴充函式進行設定︰

public static void SetDoubleBuffered(this Control control, bool enable = true)
{
    typeof(DataGridView).InvokeMember(
        "DoubleBuffered",
        BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
        null,
        control,
        new object[] { enable });
}

DoubleBuffered 針對 DataGridView 載入大量資料時特別有幫助,所以我通常都這樣使用

public class MyGridView : DataGridView
{
        public MyGridView()
        {
            this.SetDoubleBuffered();
        }
}

DataGridView 載入大量資料時,拖拉 scrollbar 比較不會造成畫面閃爍,但對於畫面控制項閃爍沒什麼作用。

解決畫面控制項閃爍

在 Form 裡加入下列屬性 CreateParams,可以有效解決該畫面控制項閃爍的問題發生︰

public partial class MyForm : Form
{
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
            return cp;
        }
    }

    public MyForm()
    {
        InitializeComponent();
    }
}

不過開啟該屬性時有個缺點,那就是如果是用在 MDI 等多個畫面重疊時,

當關閉當前Form時,當前Form的影像會覆蓋在後面準備顯示出來的Form上面,

必須重新調整畫面Size迫使Form重繪畫面,才能恢復正常,

有鑑於此,必需要監控畫面被激活時,強迫畫面重繪,因此解法如下︰

public partial class MyForm : Form
{
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
            return cp;
        }
    }

    public MyForm()
    {
        InitializeComponent();
        
        // 加入下面這行迫使該畫面被啟用時重繪畫面控制項
        this.Activated += (sender, e) => { Invalidate(); };
    }
}

Thank you for your time.