Windows窗体GUI在调用openfiledidialog . showdialog()时挂起



我的项目是一个三层架构项目,与后端WCF服务通信。当后端能够从服务获取数据时,它使用publish-subscribe通知业务层,业务层反过来通知GUI层。

我已经添加了一个OpenFileDialog到我的UI设计使用Visual studio设计器。按钮事件处理程序调用ShowDialog消息。但是,一旦我点击这个按钮,整个UI就挂起了。

在谷歌上搜索了一下之后,我发现使用委托是处理这类任务的首选方式。然而,无论有没有授权,问题仍然存在。

目前我的代码是这样的:

private void bOpen_Click(object sender, EventArgs e)
{
    Func<Image> del = delegate
    {
        OpenFileDialog d = new OpenFileDialog();
        if (d.ShowDialog() == DialogResult.OK)
        {
            return Image.FromFile(d.FileName);
        }
        return null;
    };
    Invoke(del);
}

我来自Java世界,所以我不太熟悉c# UI编程的复杂性。

我在这里错过了什么吗?

openFileDialog1->ShowHelp = true;

我把这行放在我的代码中,然后问题就解决了。

我似乎已经解决了将[STAThread]属性添加到主方法的问题。当我在调试器中运行程序时,我被告知要这样做——我以前没有这样做过,因为我经常在Visual Studio中运行服务,而在Windows中运行客户端。

[STAThread]
public static void Main(string[] args)
{
    GUI gui = new GUI();
    gui.ShowDialog();
}

有谁能解释一下到底是怎么回事吗

这往往是一个环境问题,当您使用OpenFileDialog时,许多shell扩展被加载到您的进程中。一个行为不当的人很容易搞砸你的程序。外面有很多不好的人。

调试这个是困难的,您需要一个非托管调试器,因为这些shell扩展是非托管代码。在死锁之后,您可能能够从调用堆栈中得知一些信息。Windows调试符号必需,启用微软符号服务器。但最有效的方法是使用SysInternals的AutoRuns实用程序。首先禁用所有非Microsoft生成的shell扩展。然后开始一个接一个地重新启用那些你不能没有的。

并且,正如您所发现的,这些shell扩展期望在STA线程上运行,并且当它们没有得到它时悲惨地失败。程序的UI线程必须始终是STA,也支持剪贴板、拖放和各种控件,如WebBrowser。通常总是由Main()方法上的[STAThread]属性自动处理,由项目模板放在那里。以及Application.Run()调用,这是实现STA契约所必需的。

我认为"委托"的首选方式实际上是指使用单独的线程。我将给你一个使用BackgroundWorker的例子。

它看起来像这样:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            m_Worker.DoWork += new DoWorkEventHandler(m_Worker_DoWork);
            m_Worker.ProgressChanged += new ProgressChangedEventHandler(m_Worker_ProgressChanged);
            m_Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_Worker_RunWorkerCompleted);
        }
        void m_Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Usually, used to update a progress bar
        }
        void m_Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Usually, used to add some code to notify the user that the job is done.
        }
        void m_Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            //e.Argument.ToString() contains the path to the file
            //Do what you want with the file returned.
        }        
        private void bOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog d = new OpenFileDialog();
            if (d.ShowDialog() == DialogResult.OK)
            {
                m_Worker.RunWorkerAsync(d.FileName);    
            }            
        }
        BackgroundWorker m_Worker = new BackgroundWorker();
    }

现在,至于你的UI"挂起"的原因,这是因为默认情况下,你的操作运行在UI线程上,所以如果你运行一些重的东西,UI将不会响应。

我也遇到过这个问题。我尝试了所有的解决方案,但没有一个能解决它。然后我把目标框架从。net framework 4.7改成了4.6.2,问题解决了…

我想我的问题是不同的,因为上面的解决方案都不适合我。

我编写了临时代码OpenFileDialog.FileName属性设置为非空或空字符串(当挂起发生时它是空字符串),并且我重新启动了我的计算机。当我再次启动Visual Studio并运行它时,它再次工作而没有挂起。

相关内容

  • 没有找到相关文章