调用OpenFileDialog.ShowDialog()时,Windows窗体GUI挂起

我的项目是一个三层架构项目,与后端的WCF服务进行通信。 当后端能够从服务获取数据时,它使用发布 – 订阅通知业务层,而后者通知GUI层。

我使用Visual Studios设计器在我的UI设计中添加了一个OpenFileDialog。 按钮事件处理程序调用ShowDialog消息。 但是,一旦我单击按钮,整个UI就会挂起。

谷歌搜索了一下,我发现使用委托是处理这样的任务的首选方式。 但是,无论是否有代表,问题仍然存在。

目前我的代码如下所示:

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

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

我在这里缺少什么?

我似乎已经解决了将[STAThread]属性添加到main方法的问题。 一旦我在调试器中运行程序,我被告知这样做 – 我以前没有这样做,因为我经常从Windows运行服务,而客户端定期从Windows运行。

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

任何人都可以解释究竟发生了什么

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

调试这很困难,你需要一个非托管调试器,因为这些shell扩展是非托管代码。 在死锁后进入中断时,您可能能够从调用堆栈中分辨出某些内容。 需要Windows调试符号,启用Microsoft符号服务器。 但最有效的方法是使用SysInternals的AutoRuns实用程序。 首先禁用所有未由Microsoft生成的shell扩展。 然后开始重新启用那些你不能一个接一个的生活。

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

 openFileDialog1->ShowHelp = true; 

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

我认为“委托”首选方式实际上是指使用单独的线程。 我将给你一个使用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,问题解决了……