WPF 可以/是否有多个 GUI 线程? [英] Can/Does WPF have multiple GUI threads?

查看:21
本文介绍了WPF 可以/是否有多个 GUI 线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

WPF 可以/是否有多个 GUI 线程?还是它总是只有一个 GUI 线程(即使我有多个窗口/对话框)?

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 线程.需要显式地创建线程(通过创建一个新的 <代码>线程).

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).

注意: 模态对话框可能是通过使用 Dispatcher.PushFrame() 阻止此方法的调用者,同时仍允许调度事件.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆