问题
I have an VSTO application-level add-in, with my own custom task pane. I'm trying to intercept the SelectionChange event, and display information in my custom task pane that's relevant to the selection. I do know how to do that synchronously.
However the process of fetching the information to display is slow, and I don't want to block the application while I fetch the information. Furthermore, the user may change the selection several times, and I want to cancel any in-progress "fetch" operation if this happens.
I've tried await-ing the long-running operation, but since I don't have a form open, there is no synchronization context in place, hence I get an InvalidOperationException (cross-thread operation not valid) as soon as I try to update the controls on my task pane.
async void Application_WindowSelectionChange(PowerPoint.Selection selection)
{
var results = await MyLongRunningOperation(cancellationTokenSource.Token);
myControl.Text = DescribeResults(results); // BOOM!
}
What's the best way to overcome this? I tried doing as Stephen suggested in the link above, by putting the following at the start of the selection-changed event handler:
SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext())
That didn't work. Suddenly all my other event handlers started erroring, saying "BeginInvoke cannot be called until the handle has been created". I tried putting the same code at the start of every event handler, in case it was an all-or-nothing deal. That didn't work either. Perhaps I should have created one WindowsFormsSynchronizationContext
object and used it for all the handlers - but I'm aware I'm now clutching at straws.
If that doesn't work, what other approaches should I try? Is BeginInvoke
still the way to go, or can I jump over to the UI thread some other way?
回答1:
Suddenly all my other event handlers started erroring, saying "BeginInvoke cannot be called until the handle has been created".
That's curious. I'm also grasping at straws, but try this:
Control control = new Control();
IntPtr handle = control.Handle;
instead of calling SynchronizationContext.SetSynchronizationContext
directly. You may need to do this at the beginning of each event.
(Idea taken from this blog entry).
来源:https://stackoverflow.com/questions/12898569/how-to-run-a-background-process-in-response-to-selection-change-event-in-vsto-of