0

I'm working on a c# Window Forms project, .Net framework 4.7.2

Main form has 3 controls: datagridview1, button1 and panel1 (with a progressBar inside panel1). There is no autosize in columns and rows of datagridview.

On button click, a very large datatable is retrieved in an asyncronous way from a database. Datatable is then bound to my datagridview, but user interface becomes frozen, while I would like it to be active.

Example code is:

    public Form1()
    {
        InitializeComponent();
        dataGridView1.Dock = DockStyle.Fill;
        panel1.Visible = false;
        panel1.Dock = DockStyle.Bottom;
        button1.Dock = DockStyle.Top;
        //progressBar1 is inside panel1
        progressBar1.Style = ProgressBarStyle.Marquee;
        progressBar1.Dock = DockStyle.Fill;
        panel1.BringToFront();
        dataGridView1.BringToFront();
    }

    private DataTable GetDataTable()
    {
        //Datatable is retrieved from a database indeed, with long-time queries.
        DataTable dt = new DataTable();
        for (int k = 0; k < 600; k++) dt.Columns.Add(k.ToString());
        for (int r = 0; r < 100; r++)
        {
            DataRow newRow = dt.NewRow();
            for (int c = 0; c < 600; c++) newRow[c] = r.ToString() + c.ToString();
            dt.Rows.Add(newRow);
        }
        return dt;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        panel1.Visible = true;
        DataTable dt = null;
        await Task.Run(() =>
        {
             dt = GetDataTable();
        });
        dataGridView1.DataSource = dt; //it takes time to draw (many cells). UI is frozen: progressbar value remain fixed
        panel1.Visible = false;
    }

I know that standard datagridview control is not good for large datasets, but we have to use it.

Is there any best practice to have my user interface (my progressbar indicator) active while a large datagridview is rendering?

Thanks

Edit: As suggested by dr.null, I have used System.Windows.Forms.Timer. Code is:

private async void button1_Click(object sender, EventArgs e)
    {
        panel1.Visible = true;
        Timer timer = new Timer();
        timer.Interval = (10); // 10 millisecs
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();
        DataTable dt = null;
        await Task.Run(() =>
        {
             dt = GetDataTable(); //it takes time but it is on a different task. UI is not frozen
        });
        dataGridView1.DataSource = dt; //it takes time to draw (many cells). UI is frozen: progressbar value remain fixed. How to view progressbar active while datagridview is rendering?
        timer.Stop();
        timer.Tick -= new EventHandler(timer_Tick);
        panel1.Visible = false;
    }
    private void timer_Tick(object sender, EventArgs e)
    {
        panel1.Refresh();
    }
user1630809
  • 522
  • 1
  • 3
  • 13
  • Anything here of use : https://stackoverflow.com/questions/12126889/how-to-use-winforms-progress-bar – PaulF Sep 07 '22 at 14:29
  • Thanks, but I don't know if it is my case. A very long operation, GetDataTable(), is inside a task, as in your example. The problem is on line 'dataGridView1.DataSource = dt;' which is on the main thread (user interface thread). Moreover, my progressbar style is marque, I don't need any percentage progressbar. – user1630809 Sep 07 '22 at 14:41
  • Consider [Implementing Virtual Mode in the Windows Forms DataGridView Control](https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/implementing-virtual-mode-wf-datagridview-control?view=netframeworkdesktop-4.8) to display the amount of rows. Do you really need to show all of that in a grid? What's the point? Anyway, read the referred link if you have no choice. – dr.null Sep 07 '22 at 14:57
  • I have tried with virtual mode and cellvalueneeded event which retrieves cell value from my datatable (which is now defined as a global variable). Anyway, even if datagridview rendering would be faster, it always freezes interface and progressbar indicator. – user1630809 Sep 07 '22 at 15:20
  • 1
    If your only concern here is the progress bar, try using a `Timer` to `.Invalidate();` or `.Refresh();` it. – dr.null Sep 07 '22 at 15:36
  • Thanks, progress bar remains active for a while, but then it stops with the same problem. It seems that no other user interface process is considered while rendering datagridview. Code is edited as for your suggestion – user1630809 Sep 07 '22 at 16:11
  • Everything in the UI is on that one thread. All handlers must run to completion before anything else can run. I think that you are likely screwed unless DataGridView has a method (which I don't see) that can suspend/resume its visual updating (like `Control.SuspendLayout` and `ResumeLayout` does for laying out controls). You could try that (since they're methods on `Control`). – Flydog57 Sep 07 '22 at 16:57
  • `progressBar1.Refresh();` and replace this `Timer timer = new Timer();` with a class member. Switch to the designer and drop one. Please note the mentioned suggestions here are just pain killers. What causes that pain is what you need to handle. – dr.null Sep 07 '22 at 17:18
  • Unfortunately, none of your suggestions worked for me: neither suspending layout, nor progressBar1.Refresh with timer at design mode. – user1630809 Sep 08 '22 at 08:04
  • No problem and don't give up. Grab some ideas from [this](https://stackoverflow.com/a/60571698/14171304) answer and try to apply them. It is `vb.net` though, won't be an issue for you. Right? Good luck. – dr.null Sep 08 '22 at 10:20
  • In the suggested example, it seems to me that adding and drawing items in the combobox is faster than drawing several cells in a datagridview. My problem can be summed up simply as 'how to prevent user interface freezing while drawing a very large datagridview'. – user1630809 Sep 08 '22 at 12:01
  • You can't. With this magnitude of data to populate, that what causes the pain as I said earlier. Either adopt the idea of the last referred solution or similar ones, or reduce what you get from the `db`, or provide some paging mechanism, or go for the virtual mode and make sure that you implement it as the book says. See the docs. – dr.null Sep 08 '22 at 19:07
  • Paging has been implemented (10 records per page), but the problem is the high number of columns. I have also used a listview, but scrolling is too slow. – user1630809 Sep 09 '22 at 10:01

0 Answers0