2017-06-28 23 views
0

Hy there!從後臺工作線程和基類更新GUI控制

首先。我已經閱讀了很多其他相關的問題,但沒有回答我的問題(一個或多個)


我有一個WinForm應用程序,這使得在某些設備上的一些測試,還記錄了進展。我們來舉個例子。

UI是主要的形式。

從UI我開始一個後臺工作。在裏面我做測試。

A是基類。 B繼承了A並添加了更多方法。

我的目的是從日誌消息:
- 在MainForm的UI
- 從後臺工作的DoWork方法
- 從B類
- 從A類

我能做到這一點,除了對於最後一種情況。看來,另一個富文本框被創建,其中有文本,但從不顯示...

我已經創建了一個名爲「記錄器」,它具有一些功能,將登錄到一個文件,顯示一個對話框和模塊登錄到一個RichTextBox(或控制)

示例代碼的理解和努力:

Public Shared frm As MainForm 
Public Shared bgW As BackgroundWorker 
Public Shared syncContext As SynchronizationContext 

Public Sub New() ' construtor of the main form 
' This call is required by the designer. 
InitializeComponent() 
frm = Me 
bgW = bgWorker 
syncContext = SynchronizationContext.Current 
End Sub 

Public Module Logger 

''' Logs messages into a log file. Each day a new log file is made. 
Public Sub Log(message As String, Optional messageType As MessageType = MessageType.ErrorMessage) 

Try 
Catch ex As Exception 
End Try 

End Sub 

' here goes the method the logs into the control. Examples in the ''approaches'' section 

End Module 


Public Class A 

Public Sub LogA() 
Logger.Log("someting") 
End Sub 

End Class 

Public CLass B 
Inherits A 

Public Sub LogB() 
Logger.Log("nothing") 
End Sub 

Public Sub Do() 
MyBase.LogA() 
End Sub 

End Class 

Public Class Test 
public Sub Run() 

Dim bObj as new B() 
bObj.LogB() 
bObj.Do() 

End Sub 

End Class 


Private Sub BtnReset_Click(sender As Object, e As EventArgs) Handles btnReset.Click 
Logger.Log("inside click") 
bgWorker.RunWorkerAsync() 
End Sub 

Private Sub BgWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork 
Logger.Log("inside do work") 

Dim t as new Test() 
t.Run() 

End Sub 

方法1個

使用線程安全

Dim tempForm As Form 
Public Sub Log(destinationControl As RichTextBox, mainForm As Form, message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 
     ' cross operation exception 
     If Not String.IsNullOrWhiteSpace(message) Then 
      tempForm = mainForm 
      LogInRichTextBox(destinationControl, message, messageType, textColor, textFont) 
     End If 

End Sub 

    Private Sub LogInRichTextBox(destinationControl As RichTextBox, message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 

    If destinationControl.InvokeRequired Then 
     Dim myDelegate As New LogInBoxDelegate(AddressOf LogInRichTextBox) 
     tempForm.Invoke(myDelegate, New Object() {destinationControl, message, messageType, textColor, textFont}) 
    Else 
     destinationControl.AppendText(vbCrLf) 
    End If 

End Sub 

方法2

使用共享變量

Public Sub Log(mainForm As Form, message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 
     ' cross operation exception 
     If Not String.IsNullOrWhiteSpace(message) Then 
      tempForm = mainForm 
      LogInRichTextBox(message, messageType, textColor, textFont) 
     End If 

End Sub 

    Private Sub LogInRichTextBox(message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 

    If MainForm.frm.rtbMessageLog.InvokeRequired Then 
     Dim myDelegate As New LogInBoxDelegate(AddressOf LogInRichTextBox) 
     tempForm.Invoke(myDelegate, New Object() { MainForm.frm.rtbMessageLog, message, messageType, textColor, textFont}) 
    Else 
     MainForm.frm.rtbMessageLog.AppendText(vbCrLf) 
    End If 

End Sub 

方法3
使用背景工人報告進展'

Public Sub Log(mainForm As Form, message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 
     ' cross operation exception 
     If Not String.IsNullOrWhiteSpace(message) Then 
      tempForm = mainForm 
      LogInRichTextBox(message, messageType, textColor, textFont) 
     End If 

End Sub 

    Private Sub LogInRichTextBox(message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 

    MainForm.bgW.ReportProgress(0,message) 

End Sub 

    Private Sub BgWorker_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bgWorker.ProgressChanged 

       rtbMessageLog.AppendText(CStr(e.UserState)) 

    End Sub 

方法4
使用同步化語境

Public Sub Log(mainForm As Form, message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 
     ' cross operation exception 
     If Not String.IsNullOrWhiteSpace(message) Then 
      tempForm = mainForm 
      LogInRichTextBox(message, messageType, textColor, textFont) 
     End If 

End Sub 

    Private Sub LogInRichTextBox(message As String, messageType As MessageType, Optional textColor As Color = Nothing, Optional textFont As Font = Nothing) 

    MainForm.syncContext.Post(New Threading.SendOrPostCallback(Sub() MainForm.rtbMessageLog.AppendText(message)), Nothing) 

End Sub 

因此,請求是:

我想更新我的rtbMessageLog.Text從A類(或基類 - 見示例代碼)

謝謝

+1

這是一個很大的消化,但也許你應該如何顯示消息的記錄器模塊分開。例如也許你最初的'公共子日誌(消息作爲字符串,可選的messageType作爲消息類型= MessageType.ErrorMessage)'可能引發一個事件,你可以在MainForm類中處理更新RTB或顯示一個消息框(使用InvokeRequired等獲得在UI線程上),並且你可以在其他地方處理它以登錄到一個文件等等。只是在此刻拋出一些想法! – Mark

+0

同意。你的A類和B類應該提出一個表單訂閱的**事件**。當收到時,我會使用Invoke()或SynchronizationContext方法來更新UI ... **但是**您會使用Form/Control的直接引用,因爲您已經在那裏了(因爲這是事件發生的位置被接收)。你根本不需要任何Shared成員。 –

+0

謝謝您的想法......我會盡量在幾個小時內實施它們......從未想過要使用活動...... –

回答

1

在@Mark和@Idle_Mind的幫助下,我成功找到了解決方案。謝謝你這麼多

我發佈一些代碼,也許它會幫助別人:

Public Module Logger 

    Public Event LogInRichTextBoxEvent(message As String, textColor As Color, textFont As Font) 
    Delegate Sub LogInBoxDelegate(message As String, textColor As Color, textFont As Font) 

    ''' Logs messages into a log file. Each day a new log file is made. 
    Public Sub Log(message As String, Optional messageType As MessageType = MessageType.ErrorMessage) 
     Try 
     RaiseEvent LogInRichTextBoxEvent(message, textColor, textFont) 
     Catch ex As Exception 
     End Try 
    End Sub 

    ' here goes the method the logs into the control. Examples in the ''approaches'' section 

End Module 

Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    Try 
     AddHandler Logger.LogInRichTextBoxEvent, AddressOf ShouldLoggerHandler 
    catch ex as exception 
    End try 
End Sub 

Private Sub ShouldLoggerHandler(message As String, textColor As Color, textFont As Font) 
    If rtbMessageLog.InvokeRequired Then 
     Dim myDelegate As New LogInBoxDelegate(AddressOf ShouldLoggerHandler) 
     Me.Invoke(myDelegate, New Object() {message, textColor, textFont}) 
    Else 
     rtbMessageLog.AppendTxet(message) 
    End if 
End Sub