我可以回到线程执行上下文吗?

时间:2014-01-28 11:24:38

标签: c# .net wpf multithreading user-interface

我需要在另一个线程上创建一个表单,比如应用程序启动时的启动画面。

LoadingMyForm w = null;
Thread thread = new Thread(() =>
{
    try
    {
        w = new LoadingMyForm();
        w.Show();

        System.Windows.Threading.Dispatcher.Run();
    }
    catch (Exception ex)
    {
        w.Close();
        w = null;
    }
});

thread.SetApartmentState(ApartmentState.STA);
thread.Start();

现在可以使用,但要停止它,我必须调用thread.Abort();这将引发异常,当我捕获该异常时,如您所见,我关闭窗口。是否有某种机制可以返回线程执行上下文并只调用表单上的Close方法?

据我所知:

System.Windows.Threading.Dispatcher.Run();

保持我的线程活着,至少,是否可以分配其他操作在这个线程上运行?

2 个答案:

答案 0 :(得分:2)

只需使用表单Dispatcher即可完成工作。最简单的电话就是这样做:

w.Dispatcher.Invoke(w.Close);

...虽然您可能想要为包装逻辑的LoadingMyForm类添加一个方法:

public void ThreadSafeClose()
{
    Dispatcher.Invoke(Close);
}

你应该注意到,虽然这会安全地关闭窗口,但它会让ThreadDispatcher仍在运行 - 你可能想要手动关闭它们,但是你的问题听起来就是你的声音想要以后重新使用该线程。同样,Dispatcher.InvokeDispatcher.BeginInvoke方法可以帮助您。

答案 1 :(得分:1)

以下是另一种方法。用法:

var splash = new SplashWindow();

// continue when the window is shown
splash.Start(() => new LoadingMyForm());

// do some initialization work
// ...

splash.Stop();

实现:

class SplashWindow
{
    CancellationTokenSource _cts;
    Thread _thread;

    // show window
    public void Start(Func<Window> createWindow)
    {
        var tcs = new TaskCompletionSource<bool>(false);
        _cts = new CancellationTokenSource();
        var token = _cts.Token;

        _thread = new Thread(() =>
        {
            var window = createWindow();
            window.Loaded += (s, e) =>
            {
                // window is shown
                tcs.SetResult(true);
            };

            var dispather = Dispatcher.CurrentDispatcher;
            dispather.InvokeAsync(() =>
                window.Show());

            using (token.Register(() =>
                dispather.BeginInvokeShutdown(DispatcherPriority.Normal),
                useSynchronizationContext: false))
            {
                Dispatcher.Run();
            }

            window.Close();
        });

        _thread.IsBackground = true;
        _thread.SetApartmentState(ApartmentState.STA);
        _thread.Start();
        tcs.Task.Wait();
    }

    // hide window
    public void Stop()
    {
        _cts.Cancel();
        _thread.Join();
    }
}