如何在不同的线程上创建和显示WPF窗口?

时间:2009-07-10 18:59:38

标签: wpf multithreading

我需要从同一个进程创建两个(或更多)WPF窗口。但窗口必须由单独的线程处理,因为它们不应该相互阻塞。我该怎么做?

在WinForms中,这可以通过以下方式实现:

  • 开始一个新主题
  • 从新主题
  • 创建表单
  • 使用表单作为参数
  • 调用Application.Run

但是我如何在WPF中做同样的事情?

4 个答案:

答案 0 :(得分:45)

正如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();
}

编辑: 这是一个古老的答案,但由于它似乎经常被访问,我还可以考虑以下修改/改进(未经测试)。

如果你想要关闭这样一个窗口,只需从线程(委托)外部保留对Window对象的引用,然后调用close,就像这样:

void CloseWindowSafe(Window w)
{
    if (w.Dispatcher.CheckAccess())
        w.Close();
    else
        w.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(w.Close));
}

// ...
CloseWindowSafe(tempWindow);

如果新线程可以终止(强制中止),则与评论中的问题一致:

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
}

免责声明:不要在家中这样做,中止线程(几乎总是)违反最佳做法。应该通过任何各种同步技术优雅地处理线程,或者在这种情况下,只需通过调用window.Close()

答案 1 :(得分:15)

无论价值多少,因为这个答案是Google提供的第一个结果。我还要添加以下Eugene Prystupa's Weblog

  

“我们的简化解决方案有一个问题。关闭特定窗口 NOT 终止此窗口的线程调度程序,因此线程继续运行,在关闭所有窗口后,进程将不会终止并且将成为一个ghost进程。[简单]解决这个问题的方法是将我们的线程标记为背景(使用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();
}

答案 2 :(得分:3)

我想我找到了答案。看看Jon Skeet在这个question中的答案。

基本上你在你的线程启动方法中这样做:

private void ThreadStartingPoint()
{
    Window1 tempWindow = new Window1();
    tempWindow.Show();       
    System.Windows.Threading.Dispatcher.Run();
}

答案 3 :(得分:2)

正是我在寻找的东西。

我这样做是这样的:

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

public partial class MainWindow : Window
{
    public MainWindow(Thread splashWindowThread)
    {
        InitializeComponent();

        MyInializaComponent();

        splashWindowThread.Abort();
    }

//void DoStuff(){};
}

在程序完成所有加载后,我需要启动闪屏才能消失。