VB.Net Потоки и проблемы с обработчиками

Привет еще раз сообществу Stackru!

Я работаю над классом "SendLogfileClass". В этом классе я отправляю лог-файл по электронной почте на указанный адрес электронной почты. Эта часть работает как задумано. У меня проблемы с попыткой обработать событие завершения асинхронной обработки. Во время указанного события 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

1 ответ

Решение

Ваш обработчик событий выполняется во вторичном потоке, и в этом обработчике событий вы ссылаетесь на экземпляр по умолчанию MainForm, Экземпляры по умолчанию зависят от потока, поэтому это объект формы, отличный от того, который вы смотрите на экране.

Как правило, вы можете использовать SynchronizationContext класс для включения маршалинга вызова метода в поток пользовательского интерфейса, но это невозможно в вашем случае, потому что вы фактически создаете объект и во вторичном потоке. В этом случае вам придется передать ссылку на существующий MainForm объект в этот отправитель почты и использовать его для маршалинга вызова метода в потоке пользовательского интерфейса, используя его InvokeRequired а также Invoke/BeginInvoke члены.

Другие вопросы по тегам