使用在另一个(STA)线程

时间:2016-01-05 09:21:28

标签: c# wpf multithreading sta

我正在编写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));

这样可行,但我不确定这是否是一个干净/好的方法呢?这有什么潜在的问题,或者更好的方法来实现这个目标吗?

谢谢!

0 个答案:

没有答案