Handling multiple operations using BackgroundWorker - c#

I have a DataGridView on a winform. I am dynamically adding DatagridViewButtonColumn in the load method of form with button name as btnAction and text displayed on it as "Process".
So, every row in the grid would have this Process button in the last column.
On click event of this button, I am using a BackgroundWorker to call a method which does some calculations. Once the calculations are over, I need to update that clicked button's text as "Processed" in that row in the grid. Now, how do i handle this scenario?-->
The user clicks on multiple Process buttons and I need to trigger calculations for all the corresponding rows in the grid.Can it be handled using BackgroundWorker or I need to use threading here?
Please assist with code snippet if possible.

The short answer is that the same BackgroundWorker cannot be called again while it is running. If you do that you will get an error:
This BackgroundWorker is currently
busy and cannot run multiple tasks
concurrently.
This issue has been discussed here on StackOverflow: This BackgroundWorker is currently busy and cannot run multiple tasks concurrently
What you need to do is either create a new background worker for each button or queue your background worker requests. There is a queued background worker implementation here.
Whichever way you go you will need to be careful that the code you write is all threadsafe.

I had a similar scenario while using a BackgroundWorker process.
The following Codeproject article helped me a lot to get around it.
http://www.codeproject.com/KB/cpp/BackgroundWorker_Threads.aspx

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.runworkercompleted(v=vs.85).aspx
Will show you how to handle the backgroundworker.runworkercompleted event which will let you do something once the backgroundworker is done (whether by error or completion you will have to check).

Related

How do i display a progress bar while loading a datatable to DataGridview?

I have a method called GetAllRecords() that will return a datatable of 200K records. When I checked it took about 5 seconds to load data to the datagrid and window froze.
DataTable dt = Records.GetAllRecords();
I know I have to use Background worker controls and it's three events, but I cannot figureout how to use them properly. For instance, the progress bar must show real progress not a fake one. I could slow the progress bar using sleep() of the thread class but it would be a fake progress bar.
Could any one here please give me step by step instructions on how to create a real progress bar on my windows form?
Before .NET 2.0 there was not Background worker control, in those days how programmer wrote real progress bars?
thanks
If you do a search of the site, as well as Google, you'll see that there are several attempts at doing this:
SO Link
MSDN Link
These solutions basically update the progress bar after you add each row to the grid, though if you're trying to show progress for an actual database call I don't think you'll be able to be very accurate on that.
I think the main problem you'll have is that you won't have event hooks to let you know exactly where the time-consuming part of the binding comes into play. I'm assuming that it takes 5 seconds once you bind the data to the grid and that you're not counting the load time of actually pulling down the records.
Pre-BackgroundWorker
The BackgroundWorker class is basically just a convenience to you handling the threading yourself and invoking any progress back to the UI thread for you. You would have to spawn your own thread, and call BeginInvoke on your control once work is done to apply the data to the UI thread, since you can't make changes to the UI on any thread but the main one.
For the basics on how to implement a BackgroundWorker and a ProgressBar you can consult the examples given in the MSDN pages for ProgressBar and BackgroundWorker
As for actually making the percentage completed-property of your ProgressBar make sense, the key lies in finding a meaningful value to use as the argument for BackgroundWorker.ReportProgress(int). As you have probably noticed, in most tutorials and examples, people will normally just do a Thread.Sleep(100) inside a for-loop from 1 -> 100 and then send the iteration variable as the argument to ReportProgress.
The easiest solution for you is probably to set the ProgressBarStyle property to Marquee. That way your users can rest assured that your application hasn't frozen and that progress IS being made, although they won't know how long it will take for the operation to complete.

How To Scan Files and Show Details of Current Scanning Without Making The Application Non-Responsive?

I am developing a desktop application for pdf file management using C#.
When I search any folder for *.pdf the application stops responding for some time, which is undesired behavior.
I am using XmlWriter to write data (i.e. file name,author name,subject). Also I have a label to show current scanning of file but it only show last file after complition of scanning.
This is a classic problem.
Basically the thread which displays the application is the thread which is doing all the work. So any updates/responsivness of the GUI will have to wait until its finished.
The solution to this is to make it multithreaded. The simplest way is to use a Background Worker thread which will do the writing searching and whatever, and just leave the main thread free.
http://www.dotnetperls.com/backgroundworker
If you can update your program, .NET 4.0 has new IO functions that return before finishing:
For example EnumerateFiles:
http://msdn.microsoft.com/en-us/library/dd383458.aspx
In addition to Haedrian's answer, I'd say that you could use the ProgressChanged event of BackGroundWorker to handle updating your progress indicators.
More specifically, you could raise that event with ReportProgress method, passing the name of the file curently scanning, and in the BackGroundWorker.ProgressChanged event handler you could update the label you want to use to show the file under scanning
If you don't like to create an extra thread you can call
Application.DoEvents();
in the loop. This keeps application responding and updates the label.

WPF Animated ProgressBar in WinForms application

I have a WinForms application, and wanted to add some nice WPF controls, one of them being an 'indeterminate' progress bar.. which just animates nicely until I tell it to stop.
I have done this, and was racking my brains as to why it wasn't animating (changing the value of the progress bar).
I eventually tried showing my form (containing the ElementHost) modally, and hey presto, it animates, but I want to show the form non-modally, as I want to continue processing behind the scenes.
Is there some kind of setting that tells the ElementHost window to continue 'animating'?
Thanks
Rich.
There are many ways to do this , the simplest one is to use a backgroundworker for the lengthy task. The Backgroundworker has an event to report progress. Handle this event and in the handler change your progressbar's value. Just having an animation in the main thread while still doing work on the main thread will not work right ...
One other aproach you may try (though is not what I would recommend for a healty app) is to implement a DoEvents function and call it in the main thread when you want the progress bar to get updated ... Here is the link for the DoEvents implementation:
MSDN DoEvents sugestion
I would Strongly recommend the first approach though
As I mention in my comment above, the solution is to run the processing in a separte thread, which allows the .net Main GUI thread do its stuff, and animate the progress bar.

Write status messages to a textbox asynchronously?

I recently started programming in WinForms using C#. I have a requirement where I need to search a set of folders and the sub-folders and display the status information to a textbox as I do the search like -
Looking up folder "C:\Windows"...
Found 8 files...
Copying file 1 of 8 to "D:\Temp"...
I have a method which does all the searching and stuff. I don't know how to display the status messages (like above) to a textbox periodically. Currently, the form waits for the method to be complete, and displays the messages all at once. I want them to be displayed one by one as the method progresses.
Thanks in advance.
To properly solve this your searching function will need to be running on a background thread. If the searching occurs on the UI thread it will block updates to the display preventing a periodic status message from being displayed.
The easiest way to do this in a WinForms application is to use a BackgroundWorker. It has a minimum of support for running a task on a background and returning progress information to the UI thread. Additionally there are a lot of tutorials available online to get you started with a solution.
use a BackgroundWorkerThread and the ReportStatus function. That way your UI will be responsive while the search takes place.
Run the method that performs searches on a separate thread (if you're not doing so already). It's quite easy using the async delegate features in .NET.
You can then write to the text box from the worker thread using Control.BeginInvoke() - you must do this because access to UI control sis affinitized to the single UI thread.
You can also create a background worker thread and use the ReportProgress method to notify the UI of updates. There's a fairly complete example of this approach available here that you can download and examine.

C# refresh window while doing something else

following scenario. I have a datagridview and a progressbar, datagridview is being filled with some datas from active directory. Filling my datagridview takes about 3 minutes. Now, while my program is working everything is fine until I switch windows - like for example open web browser or anything else. When I swich back to my program the whole window is "frozen", progressbar is not showing any progress until filling is completed. How can I refresh my datagridview and progressbar so that something like this doesn't happen anymore? I've tried datagdidview.Invalidate() and Refresh() run every 5s (via Timer, yes it was enabled) but it doesn't work. What am I missing here?
Thanks!
You should fetch the data in a separate thread (e.g. using BackgroundWorker or a new thread), marshalling back to the UI thread (with BackgroundWorker.ReportProgress on Control.Invoke/BeginInvoke) when you need to interact with the UI. See this article for more information and sample code.
You need to run the UI and work methods on different threads otherwise the UI will lock when your datagridview is working.

Categories