我的项目是一个三层架构项目,与后端的WCF服务进行通信。当后端能够从服务中获取数据时,它会使用publish-subscribe通知业务层,而后者通知GUI层。
我使用Visual Studios设计器为我的UI设计添加了一个OpenFileDialog。按钮事件处理程序调用ShowDialog消息。但是,一旦我点击按钮,整个用户界面就会挂起。
搜索了一下后,我发现使用委托是处理这样的任务的首选方式。但是,无论是否有代表,问题仍然存在。
目前我的代码如下:
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编程的复杂性。
我在这里缺少什么?
答案 0 :(得分:9)
我似乎解决了将[STAThread]属性添加到main方法的问题。一旦我在调试器中运行程序,我被告知这样做 - 我以前没有这样做,因为我经常从Windows运行服务,而客户端定期从Windows运行。
[STAThread]
public static void Main(string[] args)
{
GUI gui = new GUI();
gui.ShowDialog();
}
有人可以解释究竟发生了什么吗
答案 1 :(得分:7)
这往往是一个环境问题,当您使用OpenFileDialog时,很多shell扩展会被加载到您的进程中。一个行为不端的人很容易搞砸你的程序。那里有很多不好的东西。
调试这很困难,你需要一个非托管调试器,因为这些shell扩展是非托管代码。在死锁后进入中断时,您可能能够从调用堆栈中分辨出某些内容。需要Windows调试符号,启用Microsoft符号服务器。但最有效的方法是使用SysInternals的AutoRuns实用程序。首先禁用所有未由Microsoft生成的shell扩展。然后开始重新启用那些你不能一个接一个地生活的人。
并且,正如您所发现的那样,这些shell扩展期望在STA线程上运行,并且当它们没有得到它时会失败。程序的UI线程必须始终是STA,也支持剪贴板和拖放以及各种控件,如WebBrowser。通常由Main()方法的[STAThread]属性自动处理,由项目模板放在那里。和Application.Run()调用,需要实现STA合同。当你没有死锁时。
答案 2 :(得分:7)
openFileDialog1->ShowHelp = true;
我把这行放在我的代码中然后问题就解决了。
答案 3 :(得分:4)
我认为“委托”首选方式实际上是指使用单独的线程。 我将使用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就不会响应。
答案 4 :(得分:0)
我也遇到了这个问题。我在这里尝试了所有解决方案,没有人能解决。然后我将目标框架从.Net Framework 4.7更改为4.6.2,问题已解决...
答案 5 :(得分:0)
我认为我的问题有所不同,因为上述解决方案都不适合我。
我编写了临时代码,以将OpenFileDialog.FileName
属性设置为非null 或空字符串(挂断时为空字符串),然后重新启动计算机。当我再次启动Visual Studio并运行它时,它又再次正常工作而没有挂机。