如何在不阻止WPF中的UI线程的情况下执行InitializeComponent?

时间:2021-04-04 20:57:41

I want to open Window B from Window A, inside a Button click event, as follows:

我想在Window Click事件中从Window A打开Window B,如下所示:

MainWindow mainWin = new MainWindow();
mainWin.Show();

The problem is that in MainWindow constructor there's the InitializeComponent method and some others, and it takes a couple of seconds to execute, blocking the UI (I have a spinning icon and it doesn't spin).

问题是在MainWindow构造函数中有InitializeComponent方法和其他一些方法,并且需要几秒钟的时间来执行,阻塞UI(我有一个旋转的图标,它不会旋转)。

Here's what I've tried:

这是我尝试过的:

await Task.Run(() => mainWin = new MainWindow()); // Exception: thread must be STA :(

and

await Dispatcher.InvokeAsync(new Action(() => mainWin = new MainWindow()));

and

await Dispatcher.BeginInvoke(new Action(async delegate {
    mainWin = new MainWindow();
}));

EDIT: This is how MainWindow constructor looks like:

编辑:这是MainWindow构造函数的样子:

public MainWindow()
{
    InitializeComponent(); // Takes about 3 seconds...
}

By no means I'm a C# or WPF or threading expert, I found those "solutions" and I just tried them with no success. I want to know if there's a way to execute InitializeComponent async or how to keep my animation playing.

绝不是我是C#或WPF或线程专家,我找到了那些“解决方案”而我只是尝试了它们并没有成功。我想知道是否有办法执行InitializeComponent异步或如何保持我的动画播放。

I'm using C# WPF (no MVVM) and .NET Framework 4.6. Thank you in advance.

我正在使用C#WPF(没有MVVM)和.NET Framework 4.6。先谢谢你。

1 个解决方案

#1


-1  

You can create window in another thread. The downside is that any access to that window's controls from main thread must be done via Dispatcher.Invoke/BeginInvoke.

您可以在另一个线程中创建窗口。缺点是必须通过Dispatcher.Invoke / BeginInvoke从主线程访问该窗口的控件。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using System.Threading;
using System.Windows.Threading;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {             

        public MainWindow()
        {
            InitializeComponent();            
        }

        void ThreadProc()
        {
            //create second window in background thread
            Window window2 = new Window2();
            window2.Show();

            //start WPF message loop
            DispatcherFrame frame = new DispatcherFrame();            
            Dispatcher.PushFrame(frame);
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            //start background thread
            Thread thread2;
            thread2 = new Thread(ThreadProc);
            thread2.IsBackground = true;
            thread2.SetApartmentState(ApartmentState.STA);
            thread2.Start();
        }  

    // To access Window2 from MainWindow, do like that:
    //window2.Dispatcher.Invoke(() => { window2.Title = "Hello, world"; });    

    }    
}

#1


-1  

You can create window in another thread. The downside is that any access to that window's controls from main thread must be done via Dispatcher.Invoke/BeginInvoke.

您可以在另一个线程中创建窗口。缺点是必须通过Dispatcher.Invoke / BeginInvoke从主线程访问该窗口的控件。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using System.Threading;
using System.Windows.Threading;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {             

        public MainWindow()
        {
            InitializeComponent();            
        }

        void ThreadProc()
        {
            //create second window in background thread
            Window window2 = new Window2();
            window2.Show();

            //start WPF message loop
            DispatcherFrame frame = new DispatcherFrame();            
            Dispatcher.PushFrame(frame);
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            //start background thread
            Thread thread2;
            thread2 = new Thread(ThreadProc);
            thread2.IsBackground = true;
            thread2.SetApartmentState(ApartmentState.STA);
            thread2.Start();
        }  

    // To access Window2 from MainWindow, do like that:
    //window2.Dispatcher.Invoke(() => { window2.Title = "Hello, world"; });    

    }    
}