views:

40

answers:

1

I need to "send" a piece of code from another thread (Excel Interop) to the UI thread to execute. Normally you'd use Invoke on the Form, which implements the ISynchronizeInvoke interface:

public class MyForm : Form
{
    ...
    private void Button_Click(object sender, EventArgs e)
    {
        SomeExcelWorkbook.OnBeforeClose += delegate(ref bool Cancel)
        {
            this.Invoke(someCode);
        };
    }
}

Unfortunately there is a layer of abstraction between the form code and the code that defines the event handler, and I don't have a reference to the form at that point:

public void CodeExecutedByUIThread()
{
    ISynchronizeInvoke sync;
    SomeExcelWorkbook.OnBeforeClose += delegate(ref bool Cancel)
    {
        sync.Invoke(someCode);
    };
}

When entering CodeExecutedByUIThread, we are still in the UI thread, so in theory everything needed should be there. Unfortunately the Form is the only class implementing that interface, is it?

How can I get an ISynchronizeInvoke from within the UI thread? Apparently Thread.CurrentThread doesn't provide it...

Or is there a way to get a SynchronizationContext? How would I retrieve and use that?

Update: Oh, I see, getting the SynchronizationContext object looks as simple as SynchronizationContext.Current, which doesn't need any reference to a form. So I'll google little bit more about how to use that.

+2  A: 

In general, I think that neither is possible.

This might seem like an obvious answer, but what we used in this case was to store both the SynchronizationContext and the reference to the Form (as an ISynchronizeInvoke) in a static class at application startup.

MainForm main = new MainForm();
EnvironmentService.UI = main;
EnvironmentService.UIContext = SynchronizationContext.Current;
Application.Run(main);
matiash
Oh, I see, getting the SynchronizationContext object looks fairly simple and should therefore work even without having a reference to the form.
chiccodoro
Be careful, since using SynchronizationContext.Current on a secondary thread will not get the context you want, that's why I recommend storing it from the main thread at application startup.
matiash
@matiash: Good point, have read that warning in a web resource as well in the meanwhile.
chiccodoro