WPF是否可以有多个GUI线程? [英] Can/Does WPF have multiple GUI threads?
问题描述
WPF是否可以有多个GUI线程?还是总是只有一个GUI线程(即使我有多个Windows/对话框)?
Can/Does WPF have multiple GUI threads? Or does it always only have one GUI thread (even if I have multiple windows/dialogs)?
我之所以问是因为我有来自其他线程的事件,并且我想在GUI线程中处理它们(因为我需要根据事件来修改主窗口的控件).
I'm asking because I have events coming from other threads and I'd like to handle them in the GUI thread (because I need to modify the controls of my main window accordings to the events).
顺便说一句:我知道我需要为此使用Dispatcher
对象.因此,我可以重新提问一下:WPF中的所有GUI元素始终只有一个Dispatcher
对象吗?
Btw: I know I need to use a Dispatcher
object for this purpose. So, I could rephrase my question and ask: Is there always only one Dispatcher
object for all GUI elements in WPF?
推荐答案
基于第一个答案中的链接,我自己进行了一些验证.我想在这里分享结果.首先:
Based on the link in the first answer I did some verification on my own. I'd like to share the results here. First of all:
可以有多个GUI线程(因此有多个Dispatcher
实例).
There can be multiple GUI threads (and therefor multiple Dispatcher
instances).
但是:
仅创建一个新窗口(是否有模式)不会创建一个新的GUI线程.一个人需要显式创建该线程(通过创建一个新的Thread
).
Simply creating a new window (modal or not) does not create a new GUI thread. One needs to create the thread explicitly (by creating a new instance of Thread
).
Note: Instead of using separate threads, modal dialogs are likely being realized by using Dispatcher.PushFrame() which blocks the caller of this method while still allowing events to be dispatched.
我创建了一个简单的WPF类(同样,基于第一个答案的链接)来验证所有这些内容.我在这里分享它,以便您可以尝试一下.
I've created a simple WPF class (again, based on the link from the first answer) to verify all this stuff. I share it here so you can play around with it a little bit.
MainWindow.xaml:
MainWindow.xaml:
<Window x:Class="WindowThreadingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="250" Height="130">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Thread's ID is "/>
<TextBlock x:Name="m_threadId"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Thread's threading apartment is "/>
<TextBlock x:Name="m_threadTA"/>
</StackPanel>
<Button Click="OnCreateNewWindow" Content="Open New Window"/>
<Button Click="OnAccessTest" Content="Access Test"/>
</StackPanel>
</Window>
MainWindow.xaml.cs:
MainWindow.xaml.cs:
using System;
using System.Threading;
using System.Windows;
using System.Windows.Media;
namespace WindowThreadingTest {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
private static uint s_windowNumber = 0;
private readonly MainWindow m_prevWindow;
public MainWindow() : this(null) { }
public MainWindow(MainWindow prevWindow) {
InitializeComponent();
this.m_prevWindow = prevWindow;
this.Title = String.Format("Window {0}", ++s_windowNumber);
Thread thread = Thread.CurrentThread;
this.m_threadId.Text = thread.ManagedThreadId.ToString();
this.m_threadTA.Text = thread.GetApartmentState().ToString();
}
private void OnCreateNewWindow(object sender, RoutedEventArgs e) {
CreateNewWindow(true, false, true);
}
private void CreateNewWindow(bool newThread, bool modal, bool showInTaskbar) {
MainWindow mw = this;
if (newThread) {
Thread thread = new Thread(() => {
MainWindow w = new MainWindow(this);
w.ShowInTaskbar = showInTaskbar;
if (modal) {
// ShowDialog automatically starts the event queue for the new windows in the new thread. The window isn't
// modal though.
w.ShowDialog();
} else {
w.Show();
w.Closed += (sender2, e2) => w.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
} else {
MainWindow w = new MainWindow(this);
w.ShowInTaskbar = showInTaskbar;
if (modal) {
// Even modal dialogs run in the same thread.
w.ShowDialog();
} else {
w.Show();
}
}
}
private void OnAccessTest(object sender, RoutedEventArgs e) {
if (m_prevWindow == null) {
return;
}
this.Background = Brushes.Lavender;
try {
m_prevWindow.Background = Brushes.LightBlue;
} catch (InvalidOperationException excpt) {
MessageBox.Show("Exception: " + excpt.Message, "Invalid Operation");
}
m_prevWindow.Dispatcher.Invoke((Action)(() => m_prevWindow.Background = Brushes.Green));
this.Dispatcher.Invoke((Action)(() => {
try {
m_prevWindow.Background = Brushes.Red;
} catch (InvalidOperationException excpt) {
MessageBox.Show("Exception: " + excpt.Message, "Invalid Dispatcher Operation");
}
}));
}
}
}
这篇关于WPF是否可以有多个GUI线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!