我需要在另一个线程上创建一个表单,比如应用程序启动时的启动画面。
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();
保持我的线程活着,至少,是否可以分配其他操作在这个线程上运行?
答案 0 :(得分:2)
只需使用表单Dispatcher
即可完成工作。最简单的电话就是这样做:
w.Dispatcher.Invoke(w.Close);
...虽然您可能想要为包装逻辑的LoadingMyForm类添加一个方法:
public void ThreadSafeClose()
{
Dispatcher.Invoke(Close);
}
你应该注意到,虽然这会安全地关闭窗口,但它会让Thread
和Dispatcher
仍在运行 - 你可能想要手动关闭它们,但是你的问题听起来就是你的声音想要以后重新使用该线程。同样,Dispatcher.Invoke
和Dispatcher.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();
}
}