.net Windows窗体:由应用程序而不是用户打开/关闭的模式窗体?

.net Windows窗体:由应用程序而不是用户打开/关闭的模式窗体?,.net,winforms,multithreading,.net,Winforms,Multithreading,我有一个我认为结构相当好的.NET 3.5表单应用程序单元测试,依赖注入,SoC,表单只是传递输入和显示输出,不做任何逻辑,yadda yadda我只是缺少winforms的知识,不知道如何让这部分工作 当与数据库的连接丢失时(经常发生),我会检测并处理它,并希望弹出一个模式表单,在重新建立连接之前阻止应用程序的使用。我不是100%确定如何做到这一点,因为我不是在等待用户输入,而是在使用计时器轮询数据库 我的尝试是设计一个带有标签的表单,并执行以下操作: partial class MySust

我有一个我认为结构相当好的.NET 3.5表单应用程序单元测试,依赖注入,SoC,表单只是传递输入和显示输出,不做任何逻辑,yadda yadda我只是缺少winforms的知识,不知道如何让这部分工作

当与数据库的连接丢失时(经常发生),我会检测并处理它,并希望弹出一个模式表单,在重新建立连接之前阻止应用程序的使用。我不是100%确定如何做到这一点,因为我不是在等待用户输入,而是在使用计时器轮询数据库

我的尝试是设计一个带有标签的表单,并执行以下操作:

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的线程工作方式,所以我完全愿意接受建议。我还应该注意,我不想关闭他们目前正在处理的表单,我只希望它出现在它的顶部。类似于“确定/取消”对话框,但我可以通过编程方式打开和关闭该对话框,并且我需要控制它的外观

将所有UI工作保留在主UI线程上而不是使用BackgroundWorker是否更简单?在没有看到更多代码的情况下说是很棘手的,但我认为您不应该需要这样做

创建计时器时,可以分配其timer.SynchronizingObject以使其使用主UI线程。坚持下去


很抱歉,如果不进一步了解程序的结构,就无法给出更好的答案。

将所有UI工作保留在主UI线程上,而不是使用BackgroundWorker,可能会更简单些吗?在没有看到更多代码的情况下说是很棘手的,但我认为您不应该需要这样做

创建计时器时,可以分配其timer.SynchronizingObject以使其使用主UI线程。坚持下去


很抱歉,如果不了解程序的结构,就无法给出更好的答案。

没有理由使用后台工作程序实际启动表单的新实例,您只需从UI线程执行即可。

没有理由使用后台工作程序实际启动表单的新实例,您只需从UI线程执行即可。

我不确定您的总体方法是否正确,但要具体回答您的问题,请尝试将MyCustomedDialog Hide函数更改为如下:

    public new void Hide()
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((MethodInvoker)delegate { this.Hide(); });
            return;
        }

        this.Close();
    }

我不确定您的总体方法是否正确,但为了具体回答您的问题,请尝试将MyCustomedDialog Hide函数更改为如下所示:

    public new void Hide()
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((MethodInvoker)delegate { this.Hide(); });
            return;
        }

        this.Close();
    }

在类似的情况下,我采取了两种方法

一种是完全在主UI线程中操作。您可以通过使用Windows.Forms.Timer实例来实现这一点,该实例将在主UI线程中启动

优点是简单且可完全访问所有UI组件。缺点是任何阻塞呼叫都会对用户体验产生巨大影响,阻止任何用户交互。因此,如果您需要长时间运行最终导致UI操作的命令(例如,如果检查数据库需要几秒钟),那么您需要跨线程执行

从代码的角度来看,最简单的跨线程解决方案是从BackgroundWorker调用Control.Invoke方法


Invoke允许您将工作发布到控件,本质上是说plz使用您拥有的线程来运行它。

在类似的情况下,我采用了两种方法

一种是完全在主UI线程中操作。您可以通过使用Windows.Forms.Timer实例来实现这一点,该实例将在主UI线程中启动

优点是简单且可完全访问所有UI组件。缺点是任何阻塞呼叫都会对用户体验产生巨大影响,阻止任何用户交互。因此,如果您需要长时间运行最终导致UI操作的命令(例如,如果检查数据库需要几秒钟),那么您需要跨线程执行

从代码的角度来看,最简单的跨线程解决方案是从BackgroundWorker调用Control.Invoke方法


Invoke允许您将工作发布到控件,本质上是说plz使用您拥有的线程来运行它。

我确定,我该怎么做?只需删除对后台工作程序的调用,然后在代码中显示表单,而不是使用委托即可。尝试和恢复连接的过程将衍生到另一个进程
当然,我该怎么做呢?只需删除对后台工作程序的调用,然后在代码中显示表单,而不是使用委托。尝试和恢复连接的进程将衍生到另一个进程。好的,但我不想关闭当前表单,我只想在其上添加无连接表单。我该怎么做呢?NoDatabaseForm=新的NoDatabaseForm;form.ShowDialog;无论您在何处实现计时器处理程序,都必须能够访问该窗体,以便在数据库返回时再次关闭它。也许你所有的依赖注入等都是令人困惑的东西。如何尝试写一个最小的应用程序,它可以做到这一点,然后把它放在你的appOk,但我不想关闭当前的表单,我只想在它上面的无连接表单。我该怎么做呢?NoDatabaseForm=新的NoDatabaseForm;form.ShowDialog;无论您在何处实现计时器处理程序,都必须能够访问该窗体,以便在数据库返回时再次关闭它。也许你所有的依赖注入等都是令人困惑的东西。试着编写一个最小的应用程序,不管怎样都能做到这一点,然后把它放在你的应用程序中,这和你搜索错误时推荐的一样。但是,请注意,MyNoConnectionDialog不是从表单继承的,因此没有任何调用或BeginInvoke。您将如何做到这一点?更改MyCustomedDialog中的一个,而不是MyNoConnectionDialog中的一个。您不需要更改MyNoConnectionDialog中的一个,因为它不直接访问任何GUI控件。这与搜索该错误时的建议相同,但是,请注意,MyNoConnectionDialog不从表单继承,因此没有任何调用或BeginInvoke。您将如何做到这一点?更改MyCustomedDialog中的一个,而不是MyNoConnectionDialog中的一个。您不需要更改MyNoConnectionDialog中的一个,因为它不直接访问任何GUI控件。