As the title suggests, I want to know if I'm doing things right or perhaps I've dag myself a hole.
I have a large Winforms app in which I'm using WindowsFormsSynchronizationContext class to execute code in a UI (main) thread regardless of what the current thread is. It is used whenever I need to access some part of the UI in the middle of another thread. You probably want to suggest just using BackgroundWorker but it's only practical in most basic scenarios, bear with me!
Here's how I'm using the class in question (code from Program.cs):
static SynchronizationContext _uiSyncCtx;
[STAThread]
static void Main()
{
try
{
// Store the class to a static variable
_uiSyncCtx = new WindowsFormsSynchronizationContext();
}
}
And then I have this helper method (also in Program.cs)
public static void InvokeUiAsync(Action callback)
{
_uiSyncCtx.Post(state =>
{
try
{
callback.Invoke();
}
catch (TargetInvocationException tiex)
{
HandleException(tiex.InnerException);
}
catch (Exception ex)
{
HandleException(ex);
}
}, null);
}
This helper method will enable me to run callback delegate inside the Main thread.
I would typically use it like this (code taken from some form or control class):
this.Enabled = false;
this.ExecuteWithProgress(() =>
{
try
{
...
}
catch (BackendException bex)
{
// Some non-fatal exception happened, report to end user
MessageBox.Show(bex.Message, Properties.Resources.SomeErrorResource, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
catch (Exception ex)
{
// Fatal exception, handle it
Program.HandleException(ex);
}
finally
{
// Whatever happens, make sure UI is updated
Program.InvokeUiAsync(() =>
{
this.Enabled = true;
ReflectChangesOnRestOfTheUI();
});
}
});
Note that ExecuteWithProgress is simply an extension method on Control class which enables me to execute a delegate in a new thread while displaying animated progress somewhere on the Control itself until the Thread is gone.
As you can see, InvokeUiAsync is a key player here, it enables me to update the UI from another thread. Above example is very simple demo, there are a lot more complex instances where InvokeUiAsync is called more often to update the UI.
And this works quite flawlessly so far, I've never had problems with it. My concern is, I've been doing things like this for a while now and I'm also sure I found out about WindowsFormsSynchronizationContext from Stackoverflow long ago.
What bothers me now is, if this works so darn well, why would anyone ever want to use Control.BeginInvoke approach instead? I've noticed people very often use it even though it relies on one (or few) controls where as with above approach you can update any part of the UI perfectly safely (i.e. update a floating toolbar, properties window, enable/disable another window etc.).
Are there any potential pitfalls in doing things this way that I may be missing?
I have read up on this stuff on MSDN but I'm still not smarter about it. Of course, I am aware of new 'parallel features' in .Net 4.5 but I'm still very interested in above questions.
Thanks for taking time to read this and sorry for bad English!
Aucun commentaire:
Enregistrer un commentaire