【问题标题】:Multithreaded Delegates/Events多线程委托/事件
【发布时间】:2010-05-05 21:56:02
【问题描述】:

我正在尝试根据后台线程上的轮询禁用 .NET 应用程序中的部分 UI。后台线程检查应用使用的全局数据库连接是否仍然打开且可操作。

我需要做的,并且更愿意在不轮询 UI 线程的情况下这样做,是添加一个事件处理程序,如果连接状态发生变化,它可以由后台线程引发。这样,任何表单都可以有一个处理程序来禁用那些需要连接才能运行的 UI 部分。

尝试在包含线程子线程的类中使用直接事件声明,并在后台线程中引发事件,从而导致有关从其他线程访问 UI 控件的跨线程执行错误。

显然,有一种正确的方法可以做到这一点,但我们在事件(主要是单线程应用程序)方面的经验有限,而在委托方面几乎没有经验。我已经阅读了代表的文档和示例,它似乎更接近我们的需要,但我不确定如何使它在这种情况下工作。

该应用程序主要使用 VB.NET 编写,但也可以使用 C# 提供示例或帮助。

【问题讨论】:

  • 在 dotNET 中,您不应该有一个持续打开的全局连接。阅读 ConnectionPooling。 stackoverflow.com/questions/2715714
  • @Henk Holterman:如果您不了解他的情况,您不能发表此声明。此外,不建议使用 Microsoft 包含在框架中的提供程序。
  • @AMissico:使用我下面的技术,没关系(它同样适用于两者......)
  • @AMissico,什么不推荐?
  • @Henk Holterman:不建议维护打开的连接,因为 Microsoft 包含在框架中的提供程序是为连接池而设计的,就像您提到的那样。然而,并非所有提供商都是这样设计的。

标签: .net multithreading events delegates


【解决方案1】:

您可以将引发的事件编组回 UI 线程。由于这很可能(如果您设计得很好)是从一个单独的类中完成的,因此我的建议是将当前 SynchronizationContext 的副本传递到您处理后台进程的类中。

下面是一些 C# 示例代码:

public class BackgroundWork
{
    public SynchronizationContext Context { get; private set; }
    public BackgroundWork(SynchronizationContext context)
    {
        this.Context = context;
    }

    // Thread handler, etc...

    // Method to raise event
    void RaiseEvent()
    {
         Context.Post( (state) =>
         {
             // Raise the event
             this.ConnectionStatusChanged(this, EventArgs.Empty);
         }, null);
    }
}

然后,当您构造类时(在您的 UI 线程中),将当前上下文传递给它:

BackgroundWork worker = new BackgroundWork(SynchronizationContext.Current); // This passes the UI thread context...
worker.Start();

(顺便说一下,这与 BackgroundWorker 类使用的技术相同,这就是为什么它对 Windows 窗体和 WPF 的工作方式相同......)

【讨论】:

    【解决方案2】:

    你使用Control.Dispatcher.Invoke解决了跨线程执行错误:

    public void EnventHandlerMethod(object sender, EventArgs e)
    {
        myLabel.Dispatch.Invoke(new Action(() => { myLabel.Content = "Updated"; }));
    }
    

    事件处理程序的签名可能因您正在处理的事件而异。当然如果你只是在另一个线程中改变控件,你只需要上述方法的主体即可。

    这(我认为)也假设 .NET 3.5

    【讨论】:

    • 这在客户端订阅端解决了它,但在连接池端没有解决......
    【解决方案3】:

    尝试您要更改的控件的Invoke 方法,或者任何真正的控件,并提供一个小功能来完成您想要的工作。或者查看 BeginInvoke 了解异步操作。

    请注意线程问题、更改“主”线程正在更改的变量等。

    【讨论】:

    • 这(几乎)在客户端订阅端解决了它,但在连接池端没有解决......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多