Content by Category
.NET 1.x
.NET 2.0
.NET 3.0
.NET 3.5
.NET 4.0
.NET 4.5
.NET Assemblies
.NET Framework
.NET Getting Started
Accessibility
ADO.NET
Advertorials
Agile Development
AJAX
Amazon Web Services
Analysis Services
Android
Architecture
Arduino
ASP .NET Web API
ASP.NET
ASP.NET MVC
ASP.NET WebForms
Azure
B2B (Business Integration)
BDD
Big Data
Bing
BizTalk
Book Excerpts
Build and Deploy
Business Intelligence
C#
C++
ClickOnce
Cloud Computing
Code Contracts
CODE Framework Info - non Technical
CODE on the Road!
COM+
Community
Conferences
Continuous Integration
Crystal Reports
CSLA.NET
CSS
Data
Debugger
Design Patterns
Development Process
Display Technologies
Distributed Computing
Document Database
DotNetNuke
DSL
Dynamic Languages
Dynamic Programming
Editorials
Enterprise Services ("COM+")
Entity Framework
Events
Expression Blend
F#
Fox to Fox
Frameworks
Functional Programming
Git
Graphics
HTML 5
Internet Explorer 8.0
Interviews
IOS
iPhone
Iron Ruby
Java
Java Script
JavaScript
jQuery
JSON
Lightswitch
LINQ
Linux
LUA
Mac OS X
MDX
Messaging
Metro
Microsoft Application Blocks
Microsoft Business Rules Framework
Microsoft Dynamics
Microsoft Expression
Microsoft Office
Mobile Development
Mobile PC
Mono
MsBuild
MVVM
MySQL
Network
NHibernate
node.js
NOSQL
Nuget
Object Oriented Development
Objective C
Odata
OLAP
Open Source
Opinion
Opinions
Oracle
ORM
Other Languages
Parallel Programming
Patterns
PHP
Podcasts
Post Mortem
PowerPoint
Print/Output
Prism
Product News
Product Reviews
Project Management
Prolog
Python
Q&A
Rails
Rake
Razor
Reporting Services
REST
RIA Services
Ruby
Ruby on Rails
Scheme
Search
Security
Services
SharePoint
SignalR
Silverlight
SOA
Social Networks
Software & Law
Software Business
Source Control
Speech-Enabled Applications
SQL Server
SQL Server 2000
SQL Server 2005
SQL Server 2008
SQL Server 2012
SQL Server CE/AnyWhere/Mobile/Compact
SSIS
Subversion
Sync Framework
Tablet PC
TDD
Team System
Techniques
Testing and Quality Control
TFS
Tips
TypeScript
UI Design
UML
User Groups
VB Script
VB.NET
Version Control
VFP and .NET
VFP and SQL Server
Virtual Earth
Vista
Visual Basic
Visual Basic 6 (and older)
Visual FoxPro
Visual Studio .NET
Visual Studio 11
Visual Studio 2005
Visual Studio 2008
Visual Studio 2010
Visual Studio 2011
Visual Studio 2012
Visual Studio Tools for Office
VSX
WCF
Web Development (general)
Web Services
WebMatrix
WF
Whitepapers
Windows 7
Windows 8
Windows Azure
Windows Live
Windows Phone 7
Windows Phone SDK
Windows Server
Windows Vista
WinForms
WinRT
Workflow
WPF
XAML
Xiine Documentation
XML
XNA
XSLT



LearnNow


XAMALOT
 


SSWUG

Reader rating:
Click here to read 14 comments about this article.
Article source: CoDe (2004 - March/April)


Article Pages: < Previous - 1 2  3  4 5 - Next >


Asynchronous Windows Forms Programming (Cont.)

.NET 2.0 BackgroundWorker

The Windows Forms team and the .NET architects are well-aware of the problems just described. To address them, the next version of .NET (Whidbey) contains a new component called BackgroundWorker defined in the System.ComponentModel namespace. If you have access to the Whidbey beta distributed at PDC, you can find BackgroundWorker in the Components tab of a Windows Forms project. If you drop it on a form, you can use BackgroundWorker to dispatch asynchronous work, report progress and completion, and do all that while encapsulating the interaction with ISynchronizeInvoke. Using this approach gives developers a much smoother and superior programming model. Listing 2 shows the definition of BackgroundWorker and its supporting classes.

"
Use BackgroundWorker to dispatch asynchronous work, report progress and completion, and do all that while encapsulating the interaction with ISynchronizeInvoke.
"

BackgroundWorker has a public delegate called DoWork of the type DoWorkEventHandler. To invoke a method asynchronously, wrap a method with a matching signature to DoWorkEventHandler and add it as a target to DoWork. Then, call the RunWorkerAsync() method to invoke the method on a thread from the thread pool:

BackgroundWorker backgroundWorker;
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += OnDoWork;
backgroundWorker.RunWorkerAsync(100);

void OnDoWork(object sender,DoWorkEventArgs doWorkArgs)
{...}

BackgroundWorker offers two overloaded versions of RunWorkerAsync():

public void RunWorkerAsync();
public void RunWorkerAsync(object argument);

You can use the argument parameter to pass any argument to the asynchronous method. Internally, RunWorkerAsync() will construct a DoWorkEventArgs object containing the argument, invoke the DoWork delegate asynchronously, and pass it the DoWorkEventArgs object and itself as the sender.

The asynchronous method can access the Argument property of DoWorkEventArgs to retrieve the argument passed to RunWorkerAsync(). The asynchronous method should also set the value of the Result property of DoWorkEventArgs with the retuned value.

Any party interested in being notified when the asynchronous method is completed should subscribe to the RunWorkerCompleted member delegate of BackgroundWorker. RunWorkerCompleted is a delegate of the type RunWorkerCompletedEventHandler. The completion notification method accepts a parameter of type RunWorkerCompletedEventArgs, which contains the result of the method execution (the value you set in the Result property of DoWorkEventArgs inside the asynchronous method), as well as error and cancellation information.

When the asynchronous method execution is completed, BackgroundWorker cannot simply invoke the RunWorkerCompleted delegate because that invocation will be on the thread from the thread pool, and any control or form that subscribed to RunWorkerCompleted cannot be called directly. Instead, BackgroundWorker checks whether each of the target objects in RunWorkerCompleted supports ISynchronizeInvoke, and if invoke is required. If so, it will marshal the call to the owning thread of the target object.

To support progress reports, BackgroundWorker provides a member delegate called ProgressChanged of the type ProgressChangedEventHandler. Any party interested in progress notification should subscribe to ProgressChanged. When the asynchronous method wishes to notify about progress, it calls BackgroundWorker's method, ReportProgress, to correctly marshal the progress notification to any Windows Forms object.

To cancel a method, anybody from any thread can call BackgroundWorker's CancelAsync(). Calling CancelAsync() results in having the CancellationPending property of BackgroundWorker return true. Inside the asynchronous method, you should periodically check the value of CancellationPending, and if it is true, you should set the Cancel property of DoWorkEventArgs to true and return from the method. In the completion method you could check the value of the Cancelled property of RunWorkerCompletedEventArgs to detect whether the method has run to its completion or it was cancelled.

In case you derive from BackgroundWorker in order to specialize its behavior, the subclass you provide may also want to be notified of progress reports and completion events. One way to do that would be to provide event handling methods at the scope of the subclass, and add these methods as targets for the ProgressChanged or RunWorkerCompleted member delegates. However, it is a bit inconvenient to have to subscribe to events of your own base class. To that end, BackgroundWorker provides two protected virtual methods: OnProgressChanged() and OnRunWorkerCompleted(). These methods invoke their respective delegates, ProgressChanged and RunWorkerCompleted. You can override them, and perform some pre or post event processing:

public class MyBackgroundWorker : BackgroundWorker
{
   protected override void OnRunWorkerCompleted(        RunWorkerCompletedEventArgs completedArgs)
   {
      // do some pre-event processing, then: 
      base.OnRunWorkerCompleted(completedArgs);
   }
}

Note that it is very important to call BackgroundWorker's implementation of these methods, otherwise the events will never be raised.

BackgroundWorker has two Boolean properties that control progress reports and cancellation?WorkerReportsProgress and WorkerSupportsCancellation. Both properties are false by default, but of course you need to set them to true in most cases.

Listing 3 shows the same application as in Listing 1, except this time it uses a single BackgroundWorker component. Note how smooth and easy the code is for handling progress reports and completion. Because you are guaranteed to always execute on the correct thread, you can access and assigned the controls' properties directly.

&


Listing 2: BackgroundWorker definition
public class BackgroundWorker : Component
{
   public event DoWorkEventHandler DoWork;
   public event ProgressChangedEventHandler ProgressChanged;
   public event RunWorkerCompletedEventHandler RunWorkerCompleted;

   public bool WorkerSupportsCancellation{get;set;}
   public bool WorkerReportsProgress{get;set;}
   public bool CancellationPending{get;}
   public void RunWorkerAsync();
   public void RunWorkerAsync(object argument);
   public void ReportProgress(int percent);
   public void CancelAsync();
   protected virtual void OnProgressChanged(                            ProgressChangedEventArgs progressArgs);   protected virtual void OnRunWorkerCompleted(                        RunWorkerCompletedEventArgs completedArgs);
}
public delegate void DoWorkEventHandler(object sender,                                        DoWorkEventArgs e);
public delegate void ProgressChangedEventHandler(object sender,                                       ProgressChangedEventArgs e);
public delegate void RunWorkerCompletedEventHandler(object sender,                                    RunWorkerCompletedEventArgs e);

//Partial defintions:
public class CancleEventArgs : EventArgs
{
   public bool Cancel{get;set;}
}
public class DoWorkEventArgs : CancleEventArgs
{
   public bool Result{get;set;}
   public readonly object Argument; 
}
public class ProgressChangedEventArgs : EventArgs
{
   public readonly int ProgressPercentage; 
}
public class AsyncCompletedEventArgs : EventArgs
{
   public readonly Exception Error;
   public readonly bool Cancelled;
}

public class RunWorkerCompletedEventArgs : AsyncCompletedEventArgs
{
   public readonly object Result;
}


Listing 3: Asycnhronous invocation in Windows Forms 2.0 using BackgroundWorker
public class AsyncClient : Form
{
   Label m_StatusLabel;
   Button m_StartButton;
   Button m_CancelButton;
   ProgressBar m_ProgressBar;
   BackgroundWorker m_BackgroundWorker;

   public AsyncClient()
   {
      InitializeComponent();
   }
   //The code in this method is mainatianed by the Visual Designer
   void InitializeComponent()
   {
      m_BackgroundWorker = new BackgroundWorker();
      m_BackgroundWorker.WorkerReportsProgress = true;
      m_BackgroundWorker.WorkerSupportsCancellation = true;

      //In C# 2.0 you can use just the method name, and the       //compiler will infer the delegate type
      m_BackgroundWorker.ProgressChanged      += OnProgressChanged;
      m_BackgroundWorker.RunWorkerCompleted += OnCompleted;
      m_BackgroundWorker.DoWork             += OnDoWork;
      
      /* Rest of the initialization */ 
   }
   void OnCancel(object sender,System.EventArgs e)
   {
      m_BackgroundWorker.CancelAsync();
      m_CancelButton.Enabled = false;
      m_StartButton.Enabled  = true;
   }
   void OnStart(object sender,EventArgs e)
   {
      m_ProgressBar.Value = 0;
      m_StatusLabel.Text = "Status: In Progress";
      m_BackgroundWorker.RunWorkerAsync(100);
      m_CancelButton.Enabled = true;
      m_StartButton.Enabled = false;
   }
   void OnDoWork(object sender,DoWorkEventArgs doWorkArgs)
   {
      Debug.Assert(doWorkArgs.Argument != null);
      BackgroundWorker backgroundWorker;
      backgroundWorker = sender as BackgroundWorker;
      Debug.Assert(backgroundWorker != null);

      int count = (int)doWorkArgs.Argument;
      doWorkArgs.Result = null;

      for(int progress=0;progress<=count;progress+=count/10)
      {
         if(backgroundWorker.CancellationPending)
         {
            doWorkArgs.Cancel = true;
            break;
         }
         Thread.Sleep(500);

         backgroundWorker.ReportProgress(progress);
      }   
   }
   void OnProgressChanged(object sender,                          ProgressChangedEventArgs progressArgs)
   {
      m_ProgressBar.Value = progressArgs.ProgressPercentage; 
   }
   void OnCompleted(object sender,                    RunWorkerCompletedEventArgs completedArgs)
   {
      if(completedArgs.Cancelled)
      {
         m_StatusLabel.Text = "Status: Cancelled";
      }
      else
      {
         m_StatusLabel.Text = "Status: Completed";
      }
      m_CancelButton.Enabled = false;
      m_StartButton.Enabled  = true;
   }
}


Article Pages: < Previous - 1 2  3  4 5 - Next Page: 'Implementing BackgroundWorker with .NET 1.1' >>

Page 1: Asynchronous Windows Forms Programming
Page 2: Windows Forms 1.1 and Asynchronous Execution (cont.)
Page 3: .NET 2.0 BackgroundWorker
Page 4: Implementing BackgroundWorker with .NET 1.1
Page 5: Implementing BackgroundWorker with .NET 1.1 (cont.)

How would you rate the quality of this article?
1 2 3 4 5
Poor      Outstanding

Tell us why you rated the content this way. (optional)

Average rating:
4.4 out of 5

86 people have rated this article.

Instantly Search Terabytes Of Text
“Lightning Fast”
– Redmond Mag
“Covers all data
sources” – eWeek
25+ fielded & full-text search options
dtSearch’s own document filters highlight hits in popular file types
Web Spider supports static & dynamic data
APIs for .NET, Java, C++, SQL, etc.
Win / Linux (64-bit & 32-bit)
www.dtSearch.com
 

      LearnNow

 

SSWUG