星期五, 9月 08, 2023

[C#] FlowLayoutPanel 閃爍

Line 社群問題
在 WinForm FlowLayoutPanel 內要增加 100 個 Panel,造成畫面卡頓
第一時間是先測試 DoubleBuffer、SuspendLayout、ResumeLayout 這設定組合,發現完全沒有改善,接續才是朝向 FlowLayoutPanel 是否有特殊設定方向找,發現該討論 During FlowLayoutPanel scrolling, background distorts + flickers 可以改善該情況,以下測試 Code 是把 Label 塞進自訂 FlowLayoutPanel 內並觀察效果

UCFlowLayoutPanel - 覆寫 CreateParams

WS_CLIPCHILDREN 參數官方說明
Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.
這說明和網路上討論文章相符,都在在探討控件重疊時要如何繪製控件,後來發現把 Label 放進 FlowLayout 內也是一種控件重疊,另外該參數通常都會連 WS_CLIPSIBLINGS 一起研究討論
using System.Windows.Forms;

namespace FormFlickr
{
    public class UCFlowLayoutPanel : FlowLayoutPanel
    {
        public UCFlowLayoutPanel()
        {
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000; // WS_CLIPCHILDREN
                return cp;
            }
        }
    }
}

在 UCFlowLayout 內塞進 500 個 Label 控件


using System;
using System.Windows.Forms;

namespace FlowLayoutPanelFlickr
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i <= 500; i++)
            {
                Label label = new Label();
                label.Name = i.ToString();
                label.Text = i.ToString("000");

                // 設定這兩個屬性單純讓測試效果更明顯
                label.AutoSize = true;
                label.BorderStyle = BorderStyle.Fixed3D;
                flowLayoutPanel1.Controls.Add(label);
            }
        }
    }
}

測試結果

改善前


改善後


雖然覺得對於 WS_CLIPCHILDREN 應用還一知半解,但改善效果有出來就先紀錄下來

沒有留言:

張貼留言