WPF可以有多個GUI線程嗎?或者它總是隻有一個GUI線程(即使我有多個窗口/對話框)?可以/不可以WPF有多個GUI線程?
我在問,因爲我有來自其他線程的事件,我想在GUI線程中處理它們(因爲我需要根據事件修改主窗口的控件)。
btw:我知道我需要使用Dispatcher
對象來達到此目的。所以,我可以改述我的問題,並問:WPF中的所有GUI元素總是隻有一個Dispatcher
對象?
WPF可以有多個GUI線程嗎?或者它總是隻有一個GUI線程(即使我有多個窗口/對話框)?可以/不可以WPF有多個GUI線程?
我在問,因爲我有來自其他線程的事件,我想在GUI線程中處理它們(因爲我需要根據事件修改主窗口的控件)。
btw:我知道我需要使用Dispatcher
對象來達到此目的。所以,我可以改述我的問題,並問:WPF中的所有GUI元素總是隻有一個Dispatcher
對象?
基於第一個答案中的鏈接,我自己做了一些驗證。我想在此分享結果。首先:
可以有多個GUI線程(因此可以有多個Dispatcher
實例)。
但是:
只需在創建一個新的窗口(模與否)不創建一個新的GUI線程。需要明確創建線程(通過創建Thread
的新實例)。
注:而不是使用單獨的線程中,模態對話框很可能是通過利用Dispatcher.PushFrame()哪些塊被分派此方法的調用者,同時仍允許事件實現。
我已經創建了一個簡單的WPF類(再次,基於第一個答案的鏈接)來驗證所有這些東西。我在這裏分享它,所以你可以稍微玩一下。
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:
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");
}
}));
}
}
}
那麼如果你不能,那麼你不能,+1 – CloudyMarble 2013-02-21 13:36:25
是否已經閱讀了WPF線程模型文檔? http://msdn.microsoft.com/en-us/library/ms741870.aspx – 2011-04-19 13:13:18