BugFinder
BugFinder

Reputation: 17868

Update datagridview from background thread odd behavior

I have some data, and I update it in a task: The app is a hack at the moment for an idea so apologies for the code.

Task.Factory.StartNew(() =>
    {
        dataGridView1.BeginInvoke((Action)(() =>
            {
                dataGridView1.SuspendLayout();
            }));

        dataSet1.Reset();
        da.Fill(dataSet1);

        dataGridView1.BeginInvoke((Action)(() =>
            {
                dataGridView1.DataSource = dataSet1.Tables[0];
                dataGridView1.Columns[0].Visible = false;
                dataGridView1.Columns[1].Width = 50;
                dataGridView1.ResumeLayout();
            }));
    }
    ).ContinueWith(task =>
        {
            if (dataSet1.Tables[0].Rows.Count > 0)
            {
                if (lastcount != dataSet1.Tables[0].Rows.Count)
                {
                    lastcount = dataSet1.Tables[0].Rows.Count;
                    if (lastcount == 0)
                    {
                        NotifyWithMessage("The items have been cleared", "Items cleared");
                    }
                    else
                    {
                        NotifyWithMessage(String.Format("There are {0} new items in your monitor", dataSet1.Tables[0].Rows.Count));
                    }
                }
            }
        }
    );

Now, the code fundamentally works. No errors, which is nice..

When it was updated outside a task, there was no flashing of the datavgridview at all, when I run it in debug, it's very minor and well within acceptable for the hack.. the moment I run it outside debugging... it's terribly obvious! The suspend and resume layouts have not made any difference at all. I need the code in the thread, because the UI is lumpy responsive without - whereas it's acceptable, but it has the bad refresh now.

My Datagridview is custom coloured depending on cell colours, but, I just cant see why there's the difference between debug and release, I'd expect the performance the other way round!

(I tried Invoke and BeginInvoke...)

I looked at Horrible redraw performance of the DataGridView on one of my two screens

And under debug, this doesn't flicker at all, not even a bit... Under release conditions, there is a ridiculous flicker...

What can I do?

Upvotes: 1

Views: 1894

Answers (2)

Martin Moser
Martin Moser

Reputation: 6267

Kick off a task that fills the dataset in the background, and when this task is done, you do a BeginInvoke, where you Suspend the layout, assign the data and resume.

With the version you have now, there are soo many possibilities when which the code path is executed that it's hard to predict what will happen.

The rendering has to be on the UI thread, so all you can do is to try to optimize the code for it. And the Async part I'd do as described at the beginning of the post.

Upvotes: 2

BugFinder
BugFinder

Reputation: 17868

In the end heres what I did: I rean the query into a new dataset, if the count was the same, then I didnt update the grid, if the count had changed I did.

timer1.Stop();

        Task<Boolean>.Factory.StartNew(() =>
            {
                DataSet t = new DataSet();
                //_dataSet1.Reset();
                Boolean ok = false;
                Int16 retries = 0;
                while (!ok && retries<3)
                try
                {
                    da.Fill(t);
                    ok = true;
                }
                catch
                {
                    retries++;
                    Thread.Sleep(1000);
                }
                //if (!ok) throw new Exception("DB error");
                if (!ok) return false;
                try
                {
                    if (t.Tables.Count > 0 && t.Tables[0].Rows.Count != _lastcount)
                    {
                        _dataSet1 = t;
                        _lastcount = t.Tables[0].Rows.Count;
                        return true;
                    }
                }
                catch {  }
                return false;
            }).ContinueWith(task =>
                {
                    if (task.IsFaulted)
                    {
                        SQLFailed();
                        return;
                    }
                    if (!task.Result) return;


                    Invoke((Action) (() =>
                                         {
                                             dataGridView1.DataSource = _dataSet1.Tables[0];
                                             dataGridView1.Columns[0].Visible = false;
                                             dataGridView1.Columns[1].Width = 50;
                                         }));

                    if (_lastcount == 0)
                    {
                        NotifyWithMessage("The items have been cleared", "Items cleared");
                    }
                    else
                    {
                        NotifyWithMessage(String.Format("There are {0} new items in your monitor", _lastcount));
                    }
                });


    timer1.Start();

Upvotes: 1

Related Questions