我有一个相信结构良好的.NET 3.5表单应用程序(单元测试,依赖注入,SoC,表单只是中继输入和显示输出,不做任何逻辑,yadda yadda)我只是错过了关于如何让这一点工作的winforms知识。
当与数据库的连接丢失时 - 经常发生 - 我正在检测并处理它,并希望弹出一个模态表单,阻止使用应用程序直到重新建立连接。我不是百分百肯定如何做到这一点,因为我不是在等待用户输入,而是我使用计时器轮询数据库。
我的尝试是设计一个带有标签的表格并执行此操作:
partial class MySustainedDialog : Form {
public MySustainedDialog(string msg) {
InitializeComponent();
lbMessage.Text = msg;
}
public new void Show() {
base.ShowDialog();
}
public new void Hide() {
this.Close();
}
}
public class MyNoConnectionDialog : INoConnectionDialog {
private FakeSustainedDialog _dialog;
public void Show() {
var w = new BackgroundWorker();
w.DoWork += delegate {
_dialog = new MySustainedDialog("Connection Lost");
_dialog.Show();
};
w.RunWorkerAsync();
}
public void Hide() {
_dialog.Close();
}
}
这不起作用,因为_dialog.Close()是一个跨线程调用。我已经能够找到有关如何在Windows窗体中解决此问题的信息,但不是在需要自己创建表单的情况下。
有人可以给我一些建议,告诉我如何实现我的目标吗?
编辑:请注意,我只是因为缺乏其他想法而尝试了背景工作者,因为我不太熟悉UI的线程如何工作,所以我完全乐于接受建议。我还应该注意到,我不想关闭他们当前正在处理的表单,我只是想让它出现在它上面。就像一个OK / Cancel对话框但我可以通过编程方式打开和关闭(我需要控制它的外观)
答案 0 :(得分:2)
我不确定您整体方法的正确性,但要专门回答您的问题,请尝试将MySustainedDialog Hide()函数更改为:
public new void Hide()
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate { this.Hide(); });
return;
}
this.Close();
}
答案 1 :(得分:1)
没有理由使用后台工作程序来实际启动表单的新实例,只需从UI线程中执行即可。
答案 2 :(得分:1)
我在类似的情况下采取了两种方法。
一种是完全在主UI线程中操作。您可以使用 Windows.Forms.Timer 实例执行此操作,该实例将在主UI线程中触发。
优点是对所有UI组件的简单性和完全访问权限。缺点是任何阻止呼叫都会对用户体验产生巨大影响,从而阻止任何用户交互。因此,如果您需要长时间运行的命令,最终导致UI操作(例如,如果检查数据库需要几秒钟),那么您需要进行跨线程。
从代码角度来看,最简单的跨线程解决方案是从BackgroundWorker中调用 Control.Invoke 方法。
Invoke允许你将工作“发布”到控件,实质上是说“请使用你自己的线程来运行它。”
答案 3 :(得分:0)
将所有UI工作保留在主UI线程上而不是使用BackgroundWorker可能更简单吗?如果没有看到更多的代码,说这很棘手,但我认为你不应该需要它。
创建计时器时,可以指定它的Timer.SynchronizingObject以使其使用主UI线程。并坚持下去?
抱歉,如果不了解有关程序结构的更多信息,则无法提供更好的答案。