Progress Bar pattern

  • Thread starter Thread starter Craig Buchanan
  • Start date Start date
C

Craig Buchanan

I need to display a progress meter, that accepts cancellation, during a
long-running process in my add-in.

Originally, I planned to use the BackgroundWorker, but soon learned of the
cross-threading issues that occur w/ Outlook.

I've written a replacement, but I want to make sure that the pattern is a
decent one.

I created a progress form that contains the progress bar and a cancel
button. the form has a public method that is use to update the progress
bar's UI. it also has a Cancelled event that is triggered when the cancel
button is clicked.

In the long-running process, i create an instance of this form and delegate
it's Cancelled event to another procedure. Each time a message is sent, i
update the progress bar thru the popup's public method. doevents is called
at the end of each loop. when the process is completed, i close the popup.

in the deletegated Cancelled method, a module-level variable
"CancellationPending" is set to true. This variable is checked in the loop
mentioned above. if it is true, appropriate action is taken.

Does this seem to be a reasonable approach?

Thanks for your time,

Craig Buchanan
 
It seems reasonable.

A solution with a background thread would require marshaling the thread
context of the background thread to the main addin thread. I usually get the
main context after some Outlook UI is established, such as NewExplorer() and
NewInspector(). I first call System.Windows.Forms.Application.DoEvents to
prime the message pump (no thread context otherwise) and get the current
context using System.Threading.SynchronizationContext.Current. I store that
in a globally available SynchronizationContext object.

I usually do this when I need to call into some ActiveX control from a
separate thread, such as when populating a Web browser control from a
WordMail thread in Outlook. When I need to call into that control I pass
arguments to the control using an array of arguments and call the form with
the control using System.Threading.SendOrPostCallback to post a callback. If
the callback isn't null I set the SynchronizationContext to the previously
stored global SynchronizationContext and use context.Send to send the
callback the arguments.

It's complex to establish and maintain, but in some cases it's the only way
to do things. In your case for the progress control I'd do it the way you
suggested.
 
Thanks Ken.

Ken Slovak - said:
It seems reasonable.

A solution with a background thread would require marshaling the thread
context of the background thread to the main addin thread. I usually get
the main context after some Outlook UI is established, such as
NewExplorer() and NewInspector(). I first call
System.Windows.Forms.Application.DoEvents to prime the message pump (no
thread context otherwise) and get the current context using
System.Threading.SynchronizationContext.Current. I store that in a
globally available SynchronizationContext object.

I usually do this when I need to call into some ActiveX control from a
separate thread, such as when populating a Web browser control from a
WordMail thread in Outlook. When I need to call into that control I pass
arguments to the control using an array of arguments and call the form
with the control using System.Threading.SendOrPostCallback to post a
callback. If the callback isn't null I set the SynchronizationContext to
the previously stored global SynchronizationContext and use context.Send
to send the callback the arguments.

It's complex to establish and maintain, but in some cases it's the only
way to do things. In your case for the progress control I'd do it the way
you suggested.
 
Back
Top