为什么会阻塞?(带有事件和委托的VB.NET多线程处理)

为什么会阻塞?(带有事件和委托的VB.NET多线程处理),vb.net,user-interface,delegates,multithreading,blocking,Vb.net,User Interface,Delegates,Multithreading,Blocking,我有一个功能,dll中的类显示一个表单,要求用户在单击按钮说“重试”之前清除打印机上的故障。用户只是点击了重试,没有费心清除故障,所以我现在编写了一个互锁: 在调用窗体上的“enable”方法之前,已调用窗体上的按钮处于禁用状态 这是通过委托调用完成的,因为触发这些更改的事件来自运行在不同线程上的其他DLL 表单的“enable”方法连接到一个事件处理程序中,处理来自不同线程(监视以太网IO服务器的线程)的事件 我遇到的问题是“\u Fault\u StateChanged”事件从未触发。我怀疑

我有一个功能,dll中的类显示一个表单,要求用户在单击按钮说“重试”之前清除打印机上的故障。用户只是点击了重试,没有费心清除故障,所以我现在编写了一个互锁: 在调用窗体上的“enable”方法之前,已调用窗体上的按钮处于禁用状态

这是通过委托调用完成的,因为触发这些更改的事件来自运行在不同线程上的其他DLL

表单的“enable”方法连接到一个事件处理程序中,处理来自不同线程(监视以太网IO服务器的线程)的事件

我遇到的问题是“\u Fault\u StateChanged”事件从未触发。我怀疑原因是我在这里使用的“ShowDialog”和“DialogResult”技术,但我在这个应用程序的其他地方使用了完全相同的技术

任何建议都很好

请参见下面的代码摘录:

主要课堂节选

Public Class StatePrintHandler

    Private WithEvents _RetryForm As frmRetryReject

    Private Delegate Sub delShowRetryDialog()
    Private Delegate Sub delResetEnable()

    Private Sub InvokeResetEnable()
        Dim del As delResetEnable
        del = New delResetEnable(AddressOf ResetEnable)
        del.Invoke()
    End Sub

    Private Sub InvokeRetryDialogue()
        Dim del As delShowRetryDialog
        del = New delShowRetryDialog(AddressOf ShowRetryDialog)
        del.Invoke()
    End Sub

    Private Sub ShowRetryDialog()
        _RetryForm = New frmRetryReject
        _RetryForm.Prep()
        _RetryForm.ShowDialog()
        If (_RetryForm.DialogResult = Windows.Forms.DialogResult.OK) Then
            Me._RetryForm.Visible = False
        End If
    End Sub


Private Sub ResetEnable()
    If (Not IsNothing(_RetryForm)) Then
        _RetryForm.ResetEnable()
    Else
        AuditTrail("Retry form not active, no action", True)
    End If
End Sub


'Event handler for status change coming in on a different thread
    Private Sub _Fault_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _fault.StateChanged
        If (e.NewState) Then
                AuditTrail("Labeller has faulted out during cycling", True)
        Else
                InvokeResetEnable()
        End If
    End Sub
End Class
Public Class frmRetryReject
    Private Delegate Sub delEnable()
    Public Event Complete()
    Public Sub Prep()
        Me.OK_Button.Enabled = False
    End Sub
    Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub
    Public Sub ResetEnable()
        If (IsHandleCreated) Then
            Dim params() As Object = {}
            Me.Invoke(New delEnable(AddressOf InvokeEnable), params)
        End If
    End Sub
    Private Sub InvokeEnable()
        Me.OK_Button.Enabled = True
    End Sub
End Class
重试表单类摘录

Public Class StatePrintHandler

    Private WithEvents _RetryForm As frmRetryReject

    Private Delegate Sub delShowRetryDialog()
    Private Delegate Sub delResetEnable()

    Private Sub InvokeResetEnable()
        Dim del As delResetEnable
        del = New delResetEnable(AddressOf ResetEnable)
        del.Invoke()
    End Sub

    Private Sub InvokeRetryDialogue()
        Dim del As delShowRetryDialog
        del = New delShowRetryDialog(AddressOf ShowRetryDialog)
        del.Invoke()
    End Sub

    Private Sub ShowRetryDialog()
        _RetryForm = New frmRetryReject
        _RetryForm.Prep()
        _RetryForm.ShowDialog()
        If (_RetryForm.DialogResult = Windows.Forms.DialogResult.OK) Then
            Me._RetryForm.Visible = False
        End If
    End Sub


Private Sub ResetEnable()
    If (Not IsNothing(_RetryForm)) Then
        _RetryForm.ResetEnable()
    Else
        AuditTrail("Retry form not active, no action", True)
    End If
End Sub


'Event handler for status change coming in on a different thread
    Private Sub _Fault_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _fault.StateChanged
        If (e.NewState) Then
                AuditTrail("Labeller has faulted out during cycling", True)
        Else
                InvokeResetEnable()
        End If
    End Sub
End Class
Public Class frmRetryReject
    Private Delegate Sub delEnable()
    Public Event Complete()
    Public Sub Prep()
        Me.OK_Button.Enabled = False
    End Sub
    Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
        Me.DialogResult = System.Windows.Forms.DialogResult.OK
        Me.Close()
    End Sub
    Public Sub ResetEnable()
        If (IsHandleCreated) Then
            Dim params() As Object = {}
            Me.Invoke(New delEnable(AddressOf InvokeEnable), params)
        End If
    End Sub
    Private Sub InvokeEnable()
        Me.OK_Button.Enabled = True
    End Sub
End Class
对Daniel评论的补充细节 这里的代码不完整,这是一个摘录。fault对象是对外部库的订阅,是以太网IO服务器的处理程序。 IOServer上的数字输入发生更改时,将触发_FaultStateChanged事件。我知道: 我的跟踪文件显示信号变化高,这将调用重试表单。 当重试屏幕仍在显示时,信号物理上再次变低。 …但事件不会发生

这就好像在ShowDialog/DialogResult完成之前,应用程序无法为即将到来的事件提供服务—但我对此感到困惑,因为我知道.NET 2.0中的ShowDialog没有阻塞,我应该仍然能够为事件提供服务,并且在应用程序的其他地方使用了相同的模式

有几件事需要注意: 主类在运行时通过基于配置的反射进行动态实例化。 这是VS2005SP2

如果这有帮助的话,我会在另一个代码框中发布整个类,但它可能会挤满整个场景

谢谢 安迪


我已经很久没有做任何Winforms工作了,但是您是否以模式显示对话框?因为这可能是委托调用未到达的原因

异步委托的工作方式是将调用细节序列化到框架内部的内存位置,然后将窗口消息发布到相关线程的顶级窗口。模态对话框的工作方式是进入一个消息处理循环,该循环窃取线程的所有消息,以便只有一个对话框可以响应。您可以看到这可能会产生怎样的冲突。

请尝试查看

在多线程示例和


(我)对模型内线程的回答。。。。这2个应该给你写代码开始

我不知道这是否只是因为您发布了部分代码,但InvokeResetEnable()中的调用不应该是del=New delResetEnable(AddressOf _RetryForm.ResetEnable),更改是您应该调用“_RetryForm.ResetEnable”,感谢您的输入。目标子例程实际上是本地的,我编辑了原始帖子以反映这一点。您的代码不完整--您正在监视的
状态更改
事件的
\u fault
对象是什么?那个处理程序真的没有启动吗(你可以在它上面设置一个断点,它永远不会被击中)?那么这段代码的其余部分可能不是您的问题所在。Daniel请参阅上面的编辑以回答您的问题。和YU62创建表单的ShowDialog调用应该将其呈现为模态,因此是的,它是模态表单,但我不明白模态表单为什么应该阻止事件进入我的主类(StateCimPAKPrintHandler)。。。正是此类处理来自IOServer的传入事件,然后调用委托以线程安全的方式更新模式表单(frmRetryReject)更改…以启用按钮。按照这种方式,就好像整个应用程序调用堆栈都被阻塞了,直到有人通过点击触发DialogResult返回的按钮来完成模式循环