<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Rob Windsor's Weblog : Smart Client</title><link>http://msmvps.com/blogs/windsor/archive/tags/Smart+Client/default.aspx</link><description>Tags: Smart Client</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Keep Client Applications Responsive with the BackgroundWorker</title><link>http://msmvps.com/blogs/windsor/archive/2006/11/09/Keep-Client-Applications-Responsive-with-the-BackgroundWorker.aspx</link><pubDate>Thu, 09 Nov 2006 09:58:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:269466</guid><dc:creator>windsor</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/windsor/rsscomments.aspx?PostID=269466</wfw:commentRss><comments>http://msmvps.com/blogs/windsor/archive/2006/11/09/Keep-Client-Applications-Responsive-with-the-BackgroundWorker.aspx#comments</comments><description>&lt;p&gt;Many applications need to perform some kind of long-running task like downloading a file, performing a complex calculation, or retrieving data from a database. Executing these tasks can make your application become unresponsive and end up making your users anxious. Take too long performing the task and the user will be looking for the Task Manager to kill your application. &lt;/p&gt;&lt;p&gt;The solution to this problem is to execute the long-running task on a second (or background) thread. This allows the user interface thread to continue working keeping your application responsive, but it presents you with a new problem. Creating multi-threaded applications is difficult - well actually it&amp;rsquo;s easy - it&amp;rsquo;s doing so properly, following all the rules, and not coding yourself into an all night debugging session that&amp;rsquo;s truly hard. &lt;/p&gt;&lt;p&gt;To help address this issue Microsoft added the BackgroundWorker component to .NET 2.0. This component is easy to use and understand and makes programming multi-threaded applications (without explicitly creating and managing threads) much safer for the developer. The exploration of the BackgroundWorker will be done through the creation of a demo application. &lt;/p&gt;&lt;p&gt;For a more comprehensive discussion of the topics covered in this article and to see how to achieve the same results using previous versions of .NET, see Chris Sells three-part series entitled Safe, Simple Multithreading in Windows Forms (&lt;a href="http://shrinkster.com/ddm"&gt;http://shrinkster.com/ddm&lt;/a&gt;). &lt;/p&gt;&lt;p&gt;Let&amp;#39;s assume you have a simple application with a Button and a ProgressBar. The&amp;nbsp;code below&amp;nbsp;will simulate a long-running task by putting the user interface thread to sleep, one half second at a time, in a loop. The loop is used to allow the program to report progress back to the user via&amp;nbsp;the ProgressBar. &lt;/p&gt;&lt;p&gt;&lt;font face="Lucida Console"&gt;Private Sub Button1_Click(...) Handles Button1.Click&lt;br /&gt;&amp;nbsp; Button1.Enabled = False&lt;br /&gt;&amp;nbsp; For i As Integer = 1 To 10&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProgressBar1.Value = i * 10&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Threading.Thread.Sleep(500)&lt;br /&gt;&amp;nbsp; Next&lt;br /&gt;&amp;nbsp; MessageBox.Show(&amp;quot;Done&amp;quot;, &amp;quot;Demo&amp;quot;)&lt;br /&gt;&amp;nbsp; Button1.Enabled = True&lt;br /&gt;End Sub&lt;/font&gt; &lt;/p&gt;&lt;p&gt;As it stands, clicking the Start Button will begin the long-running task and, while the ProgressBar will be updated as we iterate through the loop, the rest of the application will be unresponsive. You will not be able to move or resize the form until the loop completes. The remainder of this&amp;nbsp;post will discuss how to convert this code to run the loop on a background thread via the BackgroundWorker component. It will also show how to upgrade the application to allow the long-running task to be cancelled. &lt;/p&gt;&lt;p&gt;First, declare a private field for the BackgroundWorker. Then in the Form&amp;rsquo;s Load event handler, create the instance of the BackgroundWorker and set its WorkerReportsProgress and WorkerSupportsCancellation properties to True. These properties are set to False by default as a performance optimization. &lt;/p&gt;&lt;p&gt;&lt;font face="Lucida Console"&gt;Private WithEvents _worker As BackgroundWorker&lt;br /&gt;Private _working As Boolean&lt;br /&gt;Private Sub Form1_Load(...) Handles MyBase.Load&lt;br /&gt;&amp;nbsp; _worker = New BackgroundWorker&lt;br /&gt;&amp;nbsp; _worker.WorkerReportsProgress = True&lt;br /&gt;&amp;nbsp; _worker. WorkerSupportsCancellation = True&lt;br /&gt;End Sub&lt;/font&gt; &lt;/p&gt;&lt;p&gt;Create an event hander for the BackgroundWorker&amp;rsquo;s DoWork event and copy the existing code from the Button&amp;rsquo;s Click event hander to the newly created method. The Button is going to be used to both start the long-running task as well as cancel it. In the Click event handler check if the BackgroundWorker is currently busy; if it is signal a request to cancel the task by calling CancelAsync otherwise begin the task by calling RunWorkerAsync. It is important to note that the call to CancelAsync does not immediately terminate the task, it just signals a request to cancel. The code running the task must check for the request and handle it appropriately (see below).&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;font face="Lucida Console"&gt;Private Sub Button1_Click(...) Handles Button1.Click&lt;br /&gt;&amp;nbsp; If _worker.IsBusy Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _worker.CancelAsync()&lt;br /&gt;&amp;nbsp; Else&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Button1.Text = &amp;quot;Cancel&amp;quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _worker.RunWorkerAsync()&lt;br /&gt;&amp;nbsp; End If&lt;br /&gt;End Sub&lt;/font&gt; &lt;/p&gt;&lt;p&gt;The code copied to the DoWork event handler needs to be modified slightly. The code in this event handler executes on a background thread so it cannot safely update the user interface, thus the line that originally set the Value property of the ProgressBar has to be changed. Replace this line with a call to the ReportProgress method of the BackgroundWorker passing the percent completed as a parameter. This will trigger the ProgressChanged event where we can safely update the ProgressBar. In addition, this code has to check for a request from the user to cancel the task which can be done by inspecting the CancellationPending property of the BackgroundWorker. &lt;/p&gt;&lt;p&gt;&lt;font face="Lucida Console"&gt;Private Sub _worker_DoWork(...) Handles _worker.DoWork&lt;br /&gt;&amp;nbsp; For i As Integer = 1 To 10&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; _worker.ReportProgress(i * 10)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Threading.Thread.Sleep(500)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If _worker.CancellationPending Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; e.Cancel = True&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Exit For&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; End If&lt;br /&gt;&amp;nbsp; Next&lt;br /&gt;End Sub &lt;/font&gt;&lt;/p&gt;&lt;p&gt;&lt;font face="Lucida Console"&gt;Private Sub _worker_ProgressChanged(...) &lt;/font&gt;&lt;font face="Lucida Console"&gt;Handles _worker.ProgressChanged&lt;br /&gt;&amp;nbsp; ProgressBar1.Value = e.ProgressPercentage&lt;br /&gt;End Sub&lt;/font&gt; &lt;/p&gt;&lt;p&gt;Finally, the BackgroundWorker raises the RunWorkerCompleted event to notify the user interface that long-running task is done, either because it completed normally or because it was cancelled. &lt;/p&gt;&lt;p&gt;&lt;font face="Lucida Console"&gt;Private Sub _worker_RunWorkerCompleted(...) Handles _worker.RunWorkerCompleted&lt;br /&gt;&amp;nbsp; Dim msg As String = &amp;quot;Done&amp;quot;&lt;br /&gt;&amp;nbsp; If e.Cancelled Then&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; msg = &amp;quot;Cancelled&amp;quot;&lt;br /&gt;&amp;nbsp; End If&lt;br /&gt;&amp;nbsp; Button1.Text = &amp;quot;Start&amp;quot;&lt;br /&gt;&amp;nbsp; MessageBox.Show(msg, &amp;quot;Demo&amp;quot;)&lt;br /&gt;End Sub&lt;/font&gt; &lt;/p&gt;&lt;p&gt;This short example demonstrates the basic use of the BackgroundWorker. That is executing a long-running task on a background thread, showing progress, and allowing the user to cancel.&lt;/p&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=269466" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/windsor/archive/tags/Development/default.aspx">Development</category><category domain="http://msmvps.com/blogs/windsor/archive/tags/Article/default.aspx">Article</category><category domain="http://msmvps.com/blogs/windsor/archive/tags/Smart+Client/default.aspx">Smart Client</category><category domain="http://msmvps.com/blogs/windsor/archive/tags/DevCenter/default.aspx">DevCenter</category><category domain="http://msmvps.com/blogs/windsor/archive/tags/VB/default.aspx">VB</category></item></channel></rss>