繁体   English   中英

如何使代码等待直到bool发出信号才能继续

[英]How do i make the code wait until a bool signals it to continue

我创建了一个WPF应用程序,然后通过删除app.xaml并将构建设置为类库将其转换为DLL。 我正在使用C#Windows窗体来测试DLL。 WPF DLL已预先加载,因此可以稍后调用它以立即显示和显示,而无需等待加载。 我想要完成的是调用Show(ShowWPFApp)并使代码等待,直到通过调用WPFAppResponse来翻转布尔值(此操作通过初始加载传入)。 我现在拥有它的方式导致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();
        }
    }
}

可以使用解决方法

await Task.Delay(1000);

在你的while循环中。 这可能会延迟while循环的每次运行,并且UI不会冻结。 我不确定这是否适用于您的情况。 试试让我知道。 希望这可以帮助。

您需要将执行返回给UI线程的事件循环,以便UI不会冻结。 在表单应用程序中,您可以执行以下操作:

while(waitOnShowWindow)
{
    //Code waits until bool is set to false
    System.Windows.Forms.Application.DoEvents();
}

编辑:

正如Eric指出的那样,使用DoEvents()时可能存在问题,所以不要随意使用它。 请参阅如何使用DoEvents()而不是“邪恶”?

在像这样的测试应用程序中,它允许代码工作。 但是,更好的解决方案是重新构造应用程序,以便在不需要调用时使用多线程(如果需要)。

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

问题是你的循环:

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

该循环在UI线程上运行,阻止它处理Windows消息。 (如果这个概念对你来说是新的,那么请查阅它,因为它对于Windows UI的东西很重要。)为了响应UI,它必须运行Windows消息循环。 我看到两个解决方案:

  1. 创建自己的消息循环。
  2. 立即返回,然后稍后得到结果。

解决方案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 -第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线程。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM