Paul,
That is an acceptable approach. However, you need to be aware of some
of the pitfalls inherent in multithreading programming especially when
Windows Forms are involved.
Threading in Windows Forms:
<http://www.yoda.arachsys.com/csharp/threads/winforms.shtml>
Shutting Down Worker Threads Gracefully
<http://www.yoda.arachsys.com/csharp/threads/shutdown.shtml>
Notice Jon's use of the ISynchronizeInvoke.BeginInvoke method in his
article "Threading in Windows Forms". That's the most important part.
Now, since you have a separate class that handles the long processing I
suggest you design it similar to the way Microsoft designed the
System.Timers.Timer class. That timer exposes a SynchronizingObject
property that takes an ISynchronizeInvoke which it uses to
automatically marshal its events on the thread hosting the
synchronizing object (which is usually the UI thread). For example:
public class IntensiveComputation
{
private ISynchronizeInvoke _Synchronizer = null;
public ISynchronizeInvoke SynchronizingObject
{
get { return _Synchronizer; }
set { _Synchronizer = value; }
}
public void Start()
{
// Start a thread here to run LongRunningMethod.
}
private void LongRunningMethod()
{
while (!done)
{
RaiseProgressUpdate(this, new EventArgs());
}
}
private void RaiseProgressUpdate(object sender, EventArgs args)
{
if (_Synchronizer != null && _Synchronizer.InvokeRequired)
{
// This recalls the current method, but on the desired thread.
Delegate m = new EventHandler(this.RaiseProgressUpdate);
object[] a = new object[] { sender, args };
_Synchronizer.BeginInvoke(m, a);
}
else
{
// Now we can actually raise the event.
if (ProgressUpdate != null)
{
ProgressUpdate(sender, args);
}
}
}
}
When the SynchronizingObject property is set to a Form or Control the
class automatically marshals ProgressUpdate on the UI thread, otherwise
the event is executed on the worker thread. You can use this pattern
for the Start and End events as well. This is a nice way of
encapsulating the marshaling logic. Be sure to read Jon's other
article on stopping worker threads gracefully.
Brian
dixp@usa.net wrote:[color=blue]
> I'm new to writing multithreaded apps and I have a design question. I
> have a winforms app and a class which has a method that does processing
> which is time intensive. I want the user to be able to kick off the
> process and continue to work in the appliaction while getting progress
> updates and the ability to cancel. The method that seems easiest to me
> is this:
>
> The class exposes certain events for progress. Start, ProgressUpdate,
> and End. Create an EventArgs class for passing data to the handlers.
> The form has an instance of this class with handlers for these events.
> When the user clicks go, a new thread kicks off that calls the method
> on the class to do processing.
> The method in the class raises the events at the appropriate time. The
> ui thread traps those events and updates the UI accordingly. The
> processing method in the class checks a variable after each chunk of
> processing to see if the user wants to cancel and raises the
> ProgressUpdate event. If the user clicks cancel in the form, the
> cancel member of the class instance is set to indicate the user's
> request and execution ends after the latest chunck of processing is
> complete.
>
> Since I'm new to multithreading, I'm unsure if this is a decent way to
> make everything work. Is this a solid design or am I commiting
> horrible crimes against the multithreading gods?
>
> Paul[/color]