2017-06-28 3 views
0

Hy là!Mettre à jour le contrôle GUI à partir du thread de travail d'arrière-plan et d'une classe de base

Premier. J'ai lu beaucoup des autres questions connexes, mais ne répond à ma question (s)


J'ai une application Winform qui fait des tests sur certains périphériques et enregistre également les progrès. Et faisons un exemple.

L'interface utilisateur est la forme principale.

à partir de l'interface utilisateur Je démarre un fond d'écran. Et à l'intérieur je fais les tests.

A est la classe de base. B hérite du A et ajoute d'autres méthodes.

Mon but est de connecter des messages à partir de:
- l'interface utilisateur MainForm
- du travailleur de fond méthode DoWork
- de la classe B
- de la classe A

Je peux le faire, sauf pour le dernier cas. Il semble qu'une autre zone de texte riche est créée, qui a le texte mais n'est jamais affichée ...

J'ai créé un module appelé "Logger", qui a des fonctions qui vont se connecter à un fichier, afficher un dialogue et se connecter à un richtextbox (ou un contrôle)

Exemple de code pour comprendre et essayer:

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 

approche 1

fil utilisation en toute sécurité

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 

Approche 2

utilisation partagée variables

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 

Approche 3
Utiliser travailleur de fond 'avancement du rapport'

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 

Approche 4
utilisation Syncronization Contexte

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 

Ainsi, la demande est:

Je veux mettre à jour ma rtbMessageLog.Text de la classe A (ou la classe de base - voir exemple de code)

Merci

+1

Cela fait beaucoup à digérer, mais peut-être vous devriez séparer le module d'enregistrement de la façon dont le message est affiché. par exemple. Peut-être votre 'Public Sub Log d'origine (message As String, MessageType facultatif MessageType = MessageType.ErrorMessage)' pourrait déclencher un événement que vous pouvez gérer dans la classe MainForm pour mettre à jour le RTB ou afficher une boîte de message (en utilisant InvokeRequired etc. sur le fil de l'interface utilisateur), et vous pourriez le gérer ailleurs pour vous connecter à un fichier, etc. Il suffit de lancer des idées pour le moment! – Mark

+0

D'accord. Vos classes A et B doivent déclencher un ** événement ** auquel le formulaire est abonné. Une fois reçu, j'utiliserais Invoke() ou l'approche SynchronizationContext pour mettre à jour l'interface utilisateur ... ** mais ** vous utiliseriez des références directes au formulaire/contrôle parce que vous êtes déjà là (car c'est là que l'événement est reçu). Vous n'auriez besoin d'aucun membre partagé du tout. –

+0

Merci, pour vos idées ... Je vais essayer de les implémenter dans quelques heures ... Je n'ai jamais pensé à utiliser les événements ... –

Répondre

1

Avec l'aide des commentaires de @Mark et @Idle_Mind, j'ai réussi à trouver une solution.Merci beaucoup

je poste un code, peut-être il aider les autres:

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