0

This is my requirement:

On a button click I need to get the data from database and populate in a datagridview, for which I'm using a function. As the retrieval may take a long time and I want to use the UI meanwhile, I want this function to run in a separate thread. For this, I'm using async callback. But between the begininvoke() and endinvoke() function. I'm not writing any code (I don't know what to write to make the UI respond).

The datagridview is getting populated correctly but the UI is blocked when I'm trying to access it when the function is retrieving the data.

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
Laya
  • 59
  • 1
  • 1
  • 11

3 Answers3

1

I'd recommend not to start the long running operation from the UI thread. Start another thread first, and then do the long running operation in that separate thread. When it is done, post the results back to the UI using the Form.Invoke() method. This way, the UI thread is not affected directly.

Instead of creating another thread by hand, you can also use a construct like BackgroundWorker.

If you do start the long running operation from the UI thread, you'd need to call Application.DoEvents() periodically (e.g. inside a loop). However, if the long running operation is an IO intensive -- meaning you are waiting for an IO operation most of the time -- then you won't get to call Application.DoEvents() as often as you'd like. This will make the UI seem less responsive or jerky. The seperate thread, as I mentioned above, is a better way in this regard.

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • So, should i use backgroundworker instead of async calls in this case? – Laya May 17 '12 at 06:00
  • if you're using a _BeginXXX_ method that takes an AsyncCallback delegate, then it should already be doing the work in a separate thread. Then you don't need to use a BackgroundWorker. See http://stackoverflow.com/questions/1047662/what-is-asynccallback. However, if you're dealing with a blocking operation, then yes you should use a BackgroundWorkder (or create/run a separate thread by hand). – Eren Ersönmez May 17 '12 at 06:15
  • yes the work is being done in a separate thread i can see it from the way the datagridview is getting populated. but, the ui is getting blocked by the time the contents from the backend are retrieved and added in the datagridview. – Laya May 17 '12 at 06:25
  • you might be doing some extra work with the data after the retrieval is completed. Please post some code for the data retrieval and loading the UI, so that we can see what you're doing. – Eren Ersönmez May 17 '12 at 06:31
  • please post the code nicely formatted in the question. really hard to read in the comments. – Eren Ersönmez May 17 '12 at 07:12
  • in button_click : DataMgr dm = new DataMgr(); dm.DemoEndInvoke(parameters necessary for the function); In DataMgr class, public void DemoEndInvoke(parameters) { MethodDelegate dlgt = new MethodDelegate(countIssuingEntities); TempValueHolder tmp = new TempValueHolder(); IAsyncResult ar = dlgt.BeginInvoke(parameters); tmp = dlgt.EndInvoke(ar); } – Laya May 17 '12 at 07:24
  • i'm not getting how to start the comments in a new line. – Laya May 17 '12 at 08:37
  • Hey i got it. Thank you all for your responses. – Laya May 17 '12 at 09:58
  • you're welcome. Now for other's to benefit from this, please post your code in the _question_ (edit your question) and accept one of the answers. – Eren Ersönmez May 17 '12 at 11:06
0

If you are using a loop to Populate your DataGridView, You can use the Method Application.DoEvents() inside your loop to make your UI remain Responsive during the population of the DataGridView.

Update

As you stated the problem is not the loop, I think the best approach will be using the BackgroundWorker class.

Where you can populate the DataGridView in the DoWork() event of the BackgroundWorker

And you can start the BackgroundWorker.DoWork() event during the button_click event of your Code!

Writwick
  • 2,133
  • 6
  • 23
  • 54
  • I"m not using any loop to populate my gridview. When i click the button, the appropriate contents are loaded into the gridview from the UI – Laya May 17 '12 at 05:59
  • How the contents are loaded?? Are the the items loaded one after another?? – Writwick May 17 '12 at 06:02
  • yes they are loaded row wise. When i click the button once, one row is loaded. – Laya May 17 '12 at 06:08
  • then add the `Application.DoEvents()` at the start and/or end of the `button_click`event – Writwick May 17 '12 at 06:10
  • @I.am.WritZ that won't help. It will still block the UI inbetween the DoEvents calls. – Eren Ersönmez May 17 '12 at 06:20
  • Oh! I got that! I thought that you were populating the DataGrid One By One and Adding All the Item caused the Problem..But I mistaken you...I think `BackgroundWorker` class can help you...where you can populate the `DataGridView` in the `DoWork()` event of the `BackgroundWorker` and can start the `BackgroundWorker.DoWork()` event during the `button_click` event! – Writwick May 17 '12 at 06:24
0

First of all, i should create asynccallback function in the UI form itself, not in middle level which is, in my case , DataMgr. Also, i should add the last two parameters for begininvoke function with appropriate values where i have passed null values. It should be

MethodDelegate dlgt = new MethodDelegate(DataMgr.countIssuingEntities);
 TempValueHolder tmp = new TempValueHolder();
 AsyncCallback cb = new AsyncCallback(MyAsyncCallBack);
  IAsyncResult ar = dlgt.BeginInvoke(issueGroupId, element.ControlType, (EvaluatingEntityCombo.SelectedItem as CIQHydCore.RefData.RefDataInfo).Id, (IssuingEntityCombo.SelectedItem as CIQHydCore.RefData.RefDataInfo).Id, str1, str2,**cb,dlgt**);

and in MyAsyncCallBack function we need to populate the datgridview with the retrieved values from the end

Laya
  • 59
  • 1
  • 1
  • 11