c# - 我如何使代码等到 bool 信号继续

标签 c# wpf multithreading winforms dll

我创建了WPF应用程序,然后通过删除app.xaml并将构 build 置为类库将其转换为DLL。我正在使用C#Windows窗体来测试DLL。 WPF DLL已预加载,因此以后可以调用它以立即显示和显示,而不必等待加载。我要完成的工作是调用Show(ShowWPFApp)并让代码等待,直到通过调用WPFAppResponse翻转 bool 值为止(此操作是通过初始加载传递的)。我现在拥有的方式导致UI冻结。关于如何使UI等待而不冻结UI的任何想法?

Windows窗体调用WPF DLL

namespace WindowsFormsDLLTest
{
    public partial class Form1 : Form
    {
        WPFDLL.LoadWPFApp wpfApp = null;
        public Form1()
        {
            InitializeComponent();
        }

        private void btnLoadWPFApp_Click(object sender, EventArgs e)
        {
            wpfApp = new WPFDLL.LoadWPFApp();
            try
            {
                wpfApp.Load();
            }
            catch (Exception ex)
            {

            }
        }

        private void btnShowWPFApp_Click(object sender, EventArgs e)
        {
            try
            {
                string result = null;
                result = wpfApp.ShowWPFApp("John Doe");
            }
            catch (Exception ex)
            {

            }
        }
    }
}

WPF DLL应用
namespace WPFDLL
{
    public class LoadWPFApp
    {
        private Application application = null;
        private MainWindow mainWindow = null;
        private bool waitOnShowWindow {get; set;}
        private string returnResults = null;

        public void Load()
        {
            StartLoadingWPFApp();
        }

        [STAThread]
        private void StartLoadingWPFApp()
        {
            application = new Application();

            SplashScreenWindow splashWindow = new SplashScreenWindow();
            splashWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
            splashWindow.Show();

            try
            {
                mainWindow = new MainWindow(WPFAppResponse);
                mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                splashWindow.Close();

                application.Run();
            }
            catch (Exception ex)
            {
                splashWindow.Close();
                MessageBox.Show("Error starting application:" + Environment.NewLine + ex.ToString(), "WPF App Error", MessageBoxButton.OK, MessageBoxImage.Error);
                mainWindow = null;
            }
        }

        public string ShowWPFApp(string person)
        {
            returnResults = null;
            mainWindow.LoadPerson(person);
            mainWindow.Show();

            while(waitOnShowWindow)
            {
                //Code waits until bool is set to false
            }

            return returnResults;
        }

        public void WPFAppResponse(string person)
        {
            returnResults = person;
            waitOnShowWindow = false;
            mainWindow.Hide();
        }
    }
}

最佳答案

从Windows窗体启动WPF应用很麻烦。您偶然发现了一个相当复杂的线程问题。通常的建议是改为将该WPF应用程序创建为WPF控件库。但是,我看到这可能无法解决您遇到的缓慢加载问题,这就是您制作轻量级WinForms包装器应用程序的原因。

问题是您的循环:

while(waitOnShowWindow)
{
    //Code waits until bool is set to false
}

该循环在UI线程上运行,阻止其处理Windows消息。 (如果您不熟悉该概念,请查找它,因为它对于Windows UI内容很重要。)要使UI响应,它必须正在运行Windows消息循环。我看到两个解决方案:
  • 创建您自己的消息循环。
  • 立即返回,然后再获取结果。

  • 解决方案1:
    要创建自己的消息循环,您需要使用Dispatcher.Run()或Dispatcher.PushFrame()之类的东西。试试看,看看是否可行:
    public string ShowWPFApp(string person)
    {
        returnResults = null;
        mainWindow.LoadPerson(person);
        mainWindow.Show();
        Dispatcher.CurrentDispatcher.Run();
        // do whatever to get the results
        return returnResults;
    }
    

    如果这不起作用,则可能需要改用PushFrame()。在Dispatcher.Run()无法正常工作的情况下,这是一些更深入的文章。
    http://www.codeproject.com/Articles/152137/DispatcherFrame-Look-in-Depth
    http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/

    解决方案2:
    public void ShowWPFApp(string person)
    {
        returnResults = null;
        mainWindow.LoadPerson(person);
        mainWindow.Show();
    }
    

    现在,该调用将不会阻塞UI线程,并且将显示WPF窗口。 Windows窗体应用程序正在运行消息循环,因此WPF现在可以运行。但是,您如何得到结果呢?由于它现在异步运行,因此您将不得不寻找其他方法来返回返回值。我认为MainWindow类上的事件是最简单的方法。

    另外:[STAThread]属性没有执行任何操作。 [STAThread]仅在应用程序的入口点具有含义。幸运的是,您的Windows窗体应用程序已经将[STAThread]放在Main()方法上,因此您的线程是STA线程。

    关于c# - 我如何使代码等到 bool 信号继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21414713/

    相关文章:

    c# - EF Code First 外键必须映射到一些在概念方面参与外键关联的 AssociationSet 或 EntitySet

    java - 代码的 “side-effects”到底是什么意思?

    使用 Jersey 的 Java Async REST Web 服务?

    c# - 读取 USB 大容量存储设备的字节

    c# - 读取命令行开关

    c# - 如何添加xsi :schemaLocation to serialized object

    .net - 将列表框项目的点击区域拉伸(stretch)到列表框的整个宽度? ListBox 样式通过主题隐式设置

    c# - 可以动态执行图像操作的图像 API/应用程序?

    wpf - 将数据集/数据表绑定(bind)到 xaml 数据网格

    c# - 多线程加载xml文件到内存