On Fri, 25 Apr 2008 10:03:00 -0700, Dave <Da**@noWeb.comwrote:
I have a class that Form1 calls to do some work. I would like to report
back
progress from the class to a richtextbox, will call it m_report, on the
form.
Like in the class,
Form1.m_report.Text= "Calculating variable 10";
A common pattern in .NET is to declare an event in your class that does
work, to which your form class subscribes an event handler. The current
progess would be passed as an argument to the event handler; usually this
is via a class derived from EventArgs and which includes the specific
value appropriate.
If your worker class would raise the event on a thread other than the main
GUI thread, the other thing you'll need to do is, in your form's event
handler method, use the Control.Invoke() method to execute the actual
assignment to your control on the main GUI thread.
Here's the basic elements you'll need to put together:
Anywhere:
class CalculationProgressEventArgs : EventArgs
{
// poor-man's property :)
public readonly int Variable;
public CalculationProgressEventArgs(int variable)
{
Variable = variable;
}
}
delegate void CalculationProgressEventHandler(object sender,
CalculationProgressEventArgs e);
In your worker class:
event CalculationProgressEventHandler CalculationProgress;
void RaiseCalculationProgress(int variable)
{
CalculationProgressEventHandler handler = CalculationProgress;
if (handler != null)
{
handler(this, new CalculationProgressEventArgs(variable);
}
}
In your form class, wherever you initialize your worker class:
Worker worker = ...;
worker.CalculationProgress += CalculationProgressHandler;
Then the actual event handler method:
void CalculationProgressHandler(object sender,
CalculationProgressEventArgs e)
{
Invoke((MethodInvoker)delegate { m_report.Text = "Calculation
variable " + e.Variable; });
}
Notes:
-- I've followed the .NET pattern for declaring events. There is no
actual requirement that you do so. Your event can have whatever method
signature you like. If you just want to pass a single integer parameter,
you could do that if you want, and eliminate the "EventArgs"-derived class
altogether.
-- I have deviated from the .NET pattern with respect to the
cross-thread invocation. Specifically, (almost?) all of the MSDN samples
will show you checking InvokeRequired and then either performing some
operation if it's false, or calling Invoke on the same method if it's
true. I think this is a waste and overly complicates the method. As you
can see, I prefer to simply assume that InvokeRequired is true (it's not
harmful for this assumption to be wrong), and use an anonymous method as
my invoked method.
-- The method that your worker class will call when it wants to raise
the event is, of course, RaiseCalculationProgress(), passing the specific
integer value appropriate at that time. This will check to see if any
delegate has been subscribed to the event, and if so it will invoke that
delegate. Since the delegate type is actually a multi-cast delegate, at
this point all subscribed handlers will be called in sequence, on the
current thread. Often there is only one subscribed delegate, but there
could be arbitrarily many.
Hope that helps.
Pete