我正在编写Excel Addin,我想从中显示WPF Windows。 在主线程(= Excel的计算线程)上启动这些似乎搞乱了Excel,所以我需要在一个单独的(STA-)线程中启动它们。
我正在努力解决的问题是如何最好地从我的主线程中使用该窗口。 假设我想在自己的STA线程中打开窗口,但稍后从我的主线程获取或设置任何属性(比如改变它的大小,位置,或者只是为了这个例子只显示它的窗口标题)。
有没有最好的做法呢?
我目前所做的是:
public class UserForm<T>
where T : Window
{
private T instance; // instance of the UserForm
protected ManualResetEventSlim signalInitialized = new ManualResetEventSlim(false); // Triggered when the instance has been created
private static StaTaskScheduler staTaskScheduler = new StaTaskScheduler(1);
protected Dispatcher dispatcher; // Dispatcher running the UserForm
private UserForm(Func<T> constructor)
{
Task.Factory.StartNew(
() =>
{
T win = constructor();
var helper = new WindowInteropHelper(win);
helper.Owner = ExcelDnaUtil.WindowHandle;
win.Show();
win.Closed += (sender1, e1) => win.Dispatcher.InvokeShutdown();
this.instance = win;
signalInitialized.Set(); // to signal that this.instance is now set and available to use
this.dispatcher = Dispatcher.CurrentDispatcher;
Dispatcher.Run();
},
CancellationToken.None,
TaskCreationOptions.None,
staTaskScheduler);
}
public static UserForm<T> Create<T>(Func<T> constructor)
where T : Window
{
return new UserForm<T>(constructor);
}
public static UserForm<T> Create<T>()
where T : Window, new()
{
return new UserForm<T>(() => new T());
}
public void Execute(Action<T> action)
{
WaitHandle.WaitAll(new WaitHandle[] { signalInitialized.WaitHandle });
this.dispatcher.Invoke(() => action(this.instance));
}
}
然后我可以做类似
的事情var form = UserForm<MyWindowClass>.Create();
form.Execute(win => win.Show());
form.Execute(win => MessageBox.Show("Title of the window: " + win.Title));
这样可行,但我不确定这是否是一个干净/好的方法呢?这有什么潜在的问题,或者更好的方法来实现这个目标吗?
谢谢!