VB.Net 线程和 Addhandler 问题

VB.Net Threading and Addhandler Troubles

Whosebug 社区大家好!

我正在研究 class "SendLogfileClass"。在此 class 中,我通过电子邮件将日志文件发送到所述电子邮件帐户。该部分按预期工作。我遇到的问题是尝试处理异步完成事件。在上述事件中,Addhandler 触发并在主窗体上设置 StatusBar.StatusLabel。

以下是一些相关的代码块:

#Region "Imports"

    Imports System
    Imports System.Net
    Imports System.Net.Mail
    Imports System.Net.Mime
    Imports System.Threading
    Imports System.ComponentModel
    Imports System.IO

#End Region

Public Class Form1

#Region "Public"

    Private SendmailThread As Thread
    Private MailBody As String = Nothing

#End Region

#Region "Private"

    Private mailSent As Boolean = False

#End Region

    Public Function GetTimestamp() As String

        Dim t As Date = Date.Now
        Dim timestamp As String = Nothing

        Try

            timestamp = t.ToLongTimeString & " " & t.ToLongDateString

        Catch ex As Exception

            Return 1

        End Try

        Return timestamp

    End Function

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Try

            If LoggerClock.Enabled = True Then

                OutputConsole.Text = "logger Started: " & GetTimestamp() & vbNewLine
                OutputConsole.AppendText("Logfile Opened: " & GetTimestamp() & vbNewLine)

                StatusLabel.Text = "Logger Status: Active"
                StatusBar.Refresh()

            Else

                OutputConsole.Text = "logger Started: " & GetTimestamp() & vbNewLine

                StatusLabel.Text = "Logger Status: Inactive"
                StatusBar.Refresh()
            End If

            SendlogClock.Enabled = True

            ToggleViewForm(1)

        Catch ex As Exception

            Exit Sub

        End Try

    End Sub

    Public Function SetStatus(ByVal [status] As String) As Integer

        Try

            Thread.Sleep(1000)
            StatusLabel.Text = [status]
            StatusBar.Refresh()

        Catch ex As Exception

            Return 1

        End Try

        Return 0

    End Function

    Private Sub SendlogThreadTask()

        Try

            SendLogfile("user@gmail.com", "Logger Logfile", MailBody).ToString()

        Catch ex As Exception

            Exit Sub

        End Try

    End Sub

    Private Sub SendlogClock_Tick(sender As Object, e As EventArgs) Handles SendlogClock.Tick

        Try

            OutputConsole.AppendText("Logfile Closed: " & GetTimestamp() & vbNewLine)

            SendmailThread = New Thread(AddressOf SendlogThreadTask)
            SendmailThread.IsBackground = True
            SendmailThread.Start()

            OutputConsole.ResetText()
            OutputConsole.Text = "Logfile Opened: " & GetTimestamp() & vbNewLine

        Catch ex As Exception

            Exit Sub

        End Try

    End Sub

    Public Sub SendCompletedCallback(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)

        Try

            ' Get the unique identifier for this asynchronous operation.
            Dim token As String = CStr(e.UserState)

            If e.Cancelled Then

                StatusLabel.Text = "Send Canceled... " & token
                StatusBar.Refresh()

            End If

            If e.Error IsNot Nothing Then

                StatusLabel.Text = "Error: " & token & " " & e.Error.ToString() & " "
                StatusBar.Refresh()

            Else

                StatusLabel.Text = "Message Sent... "
                StatusBar.Refresh()

            End If

            mailSent = True

        Catch ex As Exception

            Exit Sub

        End Try

    End Sub

    Public Function SendLogfile(ByVal mailTo As String, ByVal mailSubject As String, ByVal mailBody As String, Optional ByVal doAttach As Boolean = False, Optional ByVal messageAttach As String = Nothing) As Integer

        Try

            ' SMTP Server
            Dim SmtpServer As String = "mail.domain.com"

            ' Command line argument must the the SMTP host.
            Dim Cli As New SmtpClient(SmtpServer)

            ' Specify the e-mail sender.
            ' Create a mailing address that includes a UTF8 character
            ' in the display name.
            Dim [from] As New MailAddress("logger@domain.com", "logger " & ChrW(&HD8) & " logs", System.Text.Encoding.UTF8)

            ' Set destinations for the e-mail message.
            Dim [to] As New MailAddress(mailTo)

            ' Specify the message content.
            Dim message As New MailMessage([from], [to])

            message.Body = mailBody

            ' Include some non-ASCII characters in body and subject.
            Dim someArrows As New String(New Char() {ChrW(&H2190), ChrW(&H2191), ChrW(&H2192), ChrW(&H2193)})

            message.Body += Environment.NewLine & someArrows
            message.BodyEncoding = System.Text.Encoding.UTF8
            message.Subject = mailSubject & someArrows
            message.SubjectEncoding = System.Text.Encoding.UTF8

            ' Put the mail attachment in a list of items
            'Dim attachment As New Attachment(messageAttach)

            ' Attach file.
            'If doAttach = True Then

            'If File.Exists(messageAttach) Then

            'message.Attachments.Add(attachment)

            'End If

            'End If

            ' Set the method that is called back when the send operation ends.
            AddHandler Cli.SendCompleted, AddressOf SendCompletedCallback

            ' The userState can be any object that allows your callback 
            ' method to identify this send operation.
            ' For this example, the userToken is a string constant.
            Dim userState As String = "OK"

            Cli.SendAsync(message, userState)

           'MsgBox("Sending message... press c to cancel mail. Press any other key to exit.")

            Dim answer As String = "OK" ' or CANCEL

            ' If the user canceled the send, and mail hasn't been sent yet,
            ' then cancel the pending operation.
            If answer.StartsWith("C") AndAlso mailSent = False Then

                Cli.SendAsyncCancel()

            End If

            ' Clean up.
            message.Dispose()

        Catch ex As Exception

            MsgBox("Encountered Error: " & vbNewLine & vbNewLine & ex.ToString())
            Return 1

        End Try

        Return 0

    End Function

End Class

您的事件处理程序在辅助线程上执行,并且在该事件处理程序中您指的是 MainForm 的默认实例。默认实例是特定于线程的,因此它是一个与您在屏幕上看到的不同的表单对象。

您通常可以使用 SynchronizationContext class 来启用对 UI 线程的方法调用编组,但在您的情况下这是不可能的,因为您实际上是在创建对象辅助线程也是。在这种情况下,您必须将对现有 MainForm 对象的引用传递给该邮件发件人,并使用它来编组对 UI 线程的方法调用,使用其 InvokeRequiredInvoke/BeginInvoke 位成员。