0

I have a windows forms application which creates a background thread to search in files and adds matching file names to a DataGridView. Background thread uses BeginInvoke to add rows to the DataGridView and everything works fine if the background thread does not return thousands of results. The UI works perfectly fine even if the background thread processes thousands of files, unless it tries to a a few thousands of rows to the DataGridView.

I tried adding rows one by one, and buffering them and adding 100 rows at once. But the application UI become nonresponsive all the time. The background process works faster than the UI thread and there are always new rows to add to the DataGridView.

I even tried Application.DoEvents (in the UI thread) but it did not help either.

Any ideas? Can I fix it without adding a delay to the background thread?

Thanks in advance

Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
Nathan B.
  • 131
  • 4
  • 2
    What's the point in having the BGW produce results faster than the UI can display them? Or for the user to read them? You're wasting memory without benefit. – Hans Passant Mar 12 '11 at 23:17

5 Answers5

2

Make sure you call SuspendLayout() and ResumeLayout() before and after adding all the new rows, respectively. Without calling SuspendLayout before adding all the rows, the DataGridView will repaint itself after each added row, which will slow things down a bit.

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
2

It looks like using Invoke instead of BeginInvoke to add rows is the easiest solution. It slows down the background thread a little bit but it prevents the UI to become nonresponsive. Since you don't add a predefined delay to the background thread I think it may be acceptable to slow the background thread a little bit only to let the UI thread catch up. Using SuspendLayout and ResumeLayout did not help either while using BeginInvoke. I did not try virtual mode with shared rows yet but that may help too.

Nathan B.
  • 131
  • 4
  • Interesting. I wouldn't have thought of that (truthfully, I didn't process the ramifications of BeginInvoke). But it makes perfect sense when you mention it. – Jim Mischel Mar 13 '11 at 00:05
1

Try using data virtualisation: http://msdn.microsoft.com/en-us/library/ms171622.aspx

Rob Fonseca-Ensor
  • 15,510
  • 44
  • 57
0

One way would be to have the main thread create a BlockingCollection<string> that serves as a queue that the background thread can add the strings to. When the background thread is done adding, it calls CompleteAdding.

The UI thread also creates a timer that fires at some frequency (probably that you determine experimentally). The timer's Elapsed event looks to see if there's anything in the queue and, if so, removes one item and adds it to the DataGridView. When the timer's Elapsed event sees that the queue's IsComplete property is True, it stops and disposes of the timer.

Providing your timer doesn't do things too quickly, that should keep your UI responsive, and you don't have to fiddle with adding delays to the background thread.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
0

The problem form me seemed to be that the scrollbars repaint themselves everytime a row is added if i add let's say like 10000 rows. I solved this by setting the scrollbars of datagridview to None before populating, and restoring after populated, like this:

ScrollBars bars = this.ScrollBars; this.ScrollBars = System.Windows.Forms.ScrollBars.None;

... populate here (i have an overriden DataGridView control)

this.ScrollBars = bars;

SuspendLayout doesn't work for some reason in the case of adding thousands of rows.

Jaska
  • 81
  • 1
  • 1