【发布时间】:2012-08-28 22:04:19
【问题描述】:
我知道有很多类似的问题,我已经阅读了很多。不幸的是,在阅读完它们后我仍然无法解决我的问题 - 但是我对 C# 比较陌生。根据docs,在使用调试器时,不是线程安全的问题会导致InvalidOperationException。我的问题不是这种情况。
我用一个简单的原始测试类重新创建了问题,以专注于我的问题。
主窗体应该显示一种进度对话框。
public partial class ImportStatusDialog : Form
{
public ImportStatusDialog()
{
InitializeComponent();
}
public void updateFileStatus(string path)
{
t_filename.Text = path;
}
public void updatePrintStatus()
{
t_printed.Text = "sent to printer";
}
public void updateImportStatus(string clientName)
{
t_client.Text = clientName;
}
public void updateArchiveStatus()
{
t_archived.Text = "archived";
}
}
当该代码在没有任何 Invoke() 的情况下从主窗体调用时:
private void button1_Click(object sender, EventArgs e)
{
ImportStatusDialog nDialog = new ImportStatusDialog();
nDialog.Show();
nDialog.updateFileStatus("test");
Thread.Sleep(1000);
nDialog.updateImportStatus("TestClient");
Thread.Sleep(1000);
nDialog.updatePrintStatus();
Thread.Sleep(1000);
nDialog.updateArchiveStatus();
Thread.Sleep(1000);
nDialog.Close();
}
即使我这样称呼它:
private void button3_Click(object sender, EventArgs e)
{
ImportStatusDialog nDialog = new ImportStatusDialog();
nDialog.Show();
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
nDialog.updateFileStatus("Test");
});
}
else
{
nDialog.updateFileStatus("Test");
}
Thread.Sleep(1000);
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
nDialog.updatePrintStatus();
});
}
else
{
nDialog.updatePrintStatus();
}
Thread.Sleep(1000);
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
nDialog.updateImportStatus("cName");
});
}
else
{
nDialog.updateImportStatus("cName");
}
Thread.Sleep(1000);
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
nDialog.updateArchiveStatus();
});
}
else
{
nDialog.updateArchiveStatus();
}
Thread.Sleep(1000);
nDialog.Close();
}
在设计器中看起来像这样的对话框(在我的示例中)
会这样显示:
当我使用 ShowDialog() 而不是 Show() 时,对话框会正确显示,但正如 API Doc 指出的那样
您可以使用此方法在您的 应用。调用此方法时,它后面的代码不是 直到对话框关闭后才执行
这不是我想要的,尤其是因为这意味着对话框更新只会在它再次关闭后才会发生。
我在这里做错了什么?这似乎是一个微不足道的问题,但解决方案却避开了我。请记住,我是 C# GUI 编程的新手。
另外,我想问一下使用 Invoke() 的正确位置是什么?你会在调用对话框方法时在主窗体中使用它还是在对话框更新方法本身中使用它?
【问题讨论】:
-
您在按钮单击处理程序中阻塞了主 UI 线程,这意味着无法重绘窗口。
-
如何防止这种情况发生?在此示例中,事件由按钮单击处理程序引发。在我的现实世界问题场景中,事件来自
FileSystemWatcher。但在这两种情况下,我都想对事件做出反应 -
你这样做是根本错误的。 GUI 编程与控制台模式编程完全不同。你无法猜测需要什么,你真的需要读一本书。
-
@HansPassant 我在看书。但是显然它太笼统了,并且没有涵盖使用多个表单的 GUI 处理。你能根据自己的经验推荐一本关于 GUI 设计和交互的好书吗?
标签: c# user-interface dialog thread-safety