如何在单独的线程上创建和显示 WPF 窗口?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1111369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I create and show WPF windows on separate threads?
提问by Mikael Sundberg
I need to create two (or more) WPF windows from the same process. But the windows must be handled by separate threads because they should not be able to block each other. How do I do this?
我需要从同一进程创建两个(或更多)WPF 窗口。但是这些窗口必须由单独的线程处理,因为它们不应该相互阻塞。我该怎么做呢?
In WinForms this is achieved by:
在 WinForms 中,这是通过以下方式实现的:
- Start a new thread
- Create a form from the new thread
- Call Application.Run with the form as parameter
- 开始一个新线程
- 从新线程创建表单
- 使用表单作为参数调用 Application.Run
But how do I do the same in WPF?
但是我如何在 WPF 中做同样的事情?
回答by Kenan E. K.
As msdnstates:
正如msdn所说:
private void NewWindowHandler(object sender, RoutedEventArgs e)
{
Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}
private void ThreadStartingPoint()
{
Window1 tempWindow = new Window1();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
EDIT: this IS an old answer, but since it seems to be visited often, I could also think of the following modifications/improvements (not tested).
编辑:这是一个旧答案,但由于它似乎经常被访问,我还可以考虑以下修改/改进(未测试)。
If you would like to close such a window, simply keep a reference to the Window object from outside of the thread (delegate), and then invoke close on it, something like this:
如果您想关闭这样的窗口,只需从线程外部(委托)保留对 Window 对象的引用,然后对其调用 close ,如下所示:
void CloseWindowSafe(Window w)
{
if (w.Dispatcher.CheckAccess())
w.Close();
else
w.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(w.Close));
}
// ...
CloseWindowSafe(tempWindow);
If the new thread could become terminated (aborted forcibly), in line with question in comments:
如果新线程可能终止(强行中止),根据评论中的问题:
private void ThreadStartingPoint()
{
try{
Window1 tempWindow = new Window1();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
catch(ThreadAbortException)
{
tempWindow.Close();
System.Windows.Threading.Dispatcher.InvokeShutdown();
}
//the CLR will "rethrow" thread abort exception automatically
}
DISCLAIMER: don't do this at home, aborting threads is (almost always) against best practices. Threads should be gracefully handled via any of the various synchronization techniques, or in this case, simply via an invoked window.Close()
免责声明:不要在家里这样做,中止线程(几乎总是)违反最佳实践。应该通过各种同步技术中的任何一种来优雅地处理线程,或者在这种情况下,只需通过调用window.Close()
回答by Christopher Aliotta
For whatever it is worth, since this answer is the first result provided by Google. I would also like to add the following taken from Eugene Prystupa's Weblog:
不管它值多少钱,因为这个答案是谷歌提供的第一个结果。我还想从Eugene Prystupa 的博客中添加以下内容:
"There is one catch to our simplified solution. Closing a particular window does NOTterminate this window's thread dispatcher, so the thread keeps running and, after closing all windows, the process will not terminate and will become a ghost process. [The] Simple (and not correct) solution to this is to mark our threads as background (using thread.IsBackground = true;). This will force them to terminate when main UI thread terminates.
The proper implementation will gracefully shut down the dispatcher when it is no longer needed. The code below is an example of a strategy to terminate the dispatcher when window closes:"
“这里有一个陷阱,以我们的简化的解决方案。关闭一个特定的窗口不会不终止本窗口的线程调度,因此线程保持运行,并关闭所有窗口后,该进程也不会终止,并且将成为一个克隆进程。[的]简单(并且不正确)解决方案是将我们的线程标记为后台(使用 thread.IsBackground = true;)。这将迫使它们在主 UI 线程终止时终止。
正确的实现将在不再需要时优雅地关闭调度程序。下面的代码是在窗口关闭时终止调度程序的策略示例:”
private void OnCreateNewWindow(object sender, RoutedEventArgs e)
{
Thread thread = new Thread(() =>
{
Window1 w = new Window1();
w.Show();
w.Closed += (sender2, e2) =>
w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
回答by Mikael Sundberg
I think I found the answer. Look at Jon Skeet's answer in this question.
我想我找到了答案。看看 Jon Skeet 在这个问题中的回答。
Basically you do like this in your thread start method:
基本上你在你的线程启动方法中这样做:
private void ThreadStartingPoint()
{
Window1 tempWindow = new Window1();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
回答by Omzig
Exactly What I was looking for.
正是我要找的。
I am doing it like this though:
不过我是这样做的:
App.xaml.cs
应用程序.xaml.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
var window = new MainWindow(newWindowThread);
window.DataContext = new MainWindowViewModel(window);
window.Show();
}
private void ThreadStartingPoint()
{
SplashWindow tempWindow = new SplashWindow();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
}
MainWindow.Xaml.cs
主窗口.Xaml.cs
public partial class MainWindow : Window
{
public MainWindow(Thread splashWindowThread)
{
InitializeComponent();
MyInializaComponent();
splashWindowThread.Abort();
}
//void DoStuff(){};
}
I needed my splash screen to go away after the program has done all of the loading.
在程序完成所有加载后,我需要我的启动画面消失。