2017-06-28 71 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