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
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
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. –
Merci, pour vos idées ... Je vais essayer de les implémenter dans quelques heures ... Je n'ai jamais pensé à utiliser les événements ... –