c# Winforms中缓慢的UI渲染

本文关键字:UI 渲染 缓慢 Winforms | 更新日期: 2023-09-27 18:08:28

我正在制作一个相对初级的WinForms用户控件,其中包含许多按钮,每个按钮代表来自数据库的一个表。

调用InitializeComponent方法后,每个表中的数据被加载到相应的DataGridView中。

当点击上述按钮之一时,其对应的DataGridView和那些通过fk链接到主按钮的表将变得可见,然后BackgroundWorker逐渐将它们增加到所需的大小,并在短时间内将控件移动到适当的位置。

public uc1()
{
    InitializeComponent();
    PopulateTables();
    tableResizer.WorkerReportsProgress = true;
    tableResizer.WorkerSupportsCancellation = true;
    tableResizer.DoWork += tableResizer_DoWork;
    tableResizer.ProgressChanged += tableResizer_ProgressChanged;
    tableResizer.RunWorkerCompleted += tableResizer_RunWorkerCompleted;
    dgv5.SelectionChanged += show5Relations;
}
private void btn5_Click(object sender, EventArgs e)
{
    mainTable = 5;
    btn5.Visible = false;
    btn4.Visible = false;
    btn3.Visible = false;
    btn2.Visible = false;
    dgv5.Visible = true;
    dgv4.Visible = true;
    dgv3.Visible = true;
    dgv2.Visible = true;
    lbl6.Visible = false;
    lbl7.Visible = false;
    lbl1.Visible = false;
    tableResizer.RunWorkerAsync();
}
private void tableResizer_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    int expansion = 0;
    while (expansion < 30)
    {
        tableResizer.ReportProgress(mainTable);
        expansion++;
        System.Threading.Thread.Sleep(16);
    }
}
private void tableResizer_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage == 5)
    {
        dgv5.Size = new Size(dgv5.Size.Width + (((this.Width / 26) * 10) / 30), dgv5.Size.Height + (((this.Height / 24) * 10) / 30));
        dgv5.Location = new Point(dgv5.Location.X - (((this.Width / 26) * 10) / 60), dgv5.Location.Y - (((this.Height / 24) * 10) / 60));
        dgv4.Size = new Size(dgv4.Size.Width + (((this.Width / 26) * 10) / 30), dgv4.Size.Height + (((this.Height / 24) * 10) / 50));
        dgv4.Location = new Point(dgv4.Location.X - (((this.Width / 26) * 10) / 40), dgv4.Location.Y - (((this.Height / 24) * 10) / 120));
        dgv3.Size = new Size(dgv3.Size.Width + (((this.Width / 26) * 10) / 30), dgv3.Size.Height + (((this.Height / 24) * 10) / 50));
        dgv3.Location = new Point(dgv3.Location.X - (((this.Width / 26) * 10) / 40), dgv3.Location.Y - (((this.Height / 24) * 10) / 120));
        dgv2.Size = new Size(dgv2.Size.Width + (((this.Width / 26) * 10) / 30), dgv2.Size.Height + (((this.Height / 24) * 10) / 50));
        dgv2.Location = new Point(dgv2.Location.X - (((this.Width / 26) * 10) / 40), dgv2.Location.Y - (((this.Height / 24) * 10) / 120));
        btn1.Location = new Point(btn1.Location.X - (((this.Width / 26) * 10) / 130), btn1.Location.Y);
    }
}
private void tableResizer_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    if (mainTable == 5)
    {
        btn7.Visible = true;
        btn6.Visible = true;
        btn1.Visible = true;
        lbl5.Visible = true;
        lbl5.Location = new Point(dgv5.Location.X, dgv5.Location.Y - lbl5.Size.Height);
        lbl4.Visible = true;
        lbl4.Location = new Point(dgv4.Location.X, dgv4.Location.Y - lbl4.Size.Height);
        lbl3.Visible = true;
        lbl3.Location = new Point(dgv3.Location.X, dgv3.Location.Y - lbl3.Size.Height);
        lbl2.Visible = true;
        lbl2.Location = new Point(dgv2.Location.X, dgv2.Location.Y - lbl1.Size.Height);
    }
}

问题是,当tableResizer在做它的工作时,UI没有被渲染得足够快,结果,一个DataGridViews在工作完成之前是不完全可见的。

DoWork方法中增加睡眠的长度只能在60ms时修复此问题,此时渲染太不稳定而无法接受。任何超过30毫秒的都不行。

我对多线程和c#都比较陌生,所以我很确定有更有效的方法来解决这个问题。

我应该做些什么来确保流畅的渲染?

c# Winforms中缓慢的UI渲染

我已经找到解决问题的办法了。虽然我以前尝试过将DoubleBuffered设置为用户控件的true,但它没有帮助。问题是DataGridViews在默认情况下关闭了它,因为它是一个受保护的属性,所以不能设置为true。

在进一步调查这个问题之后(我本应该早点做的,我道歉),我发现了这个问题:在我的两个屏幕中的一个上,DataGridView的重绘性能非常糟糕

解决方法很简单。创建一个继承默认DataGridView的类,并将其DoubleBuffered属性赋值为true。

class CustomDataGridView: DataGridView
{
    public CustomDataGridView()
    {
        DoubleBuffered = true;
    } 
}