Mit Threads können in vb.net bestimmte Operationen von der Anwendung "abgelöst" werden. Mithilfe der Auslagerungen können z.B Timer oder Rechnenvorgängen im Hintergrund ausgeführt werden.
Möchte man aus einem Fremden Thread allerdings das Ergebnis später in der Anwendung wieder verwenden oder einen Event auslösen, so wird dieses penitrant von vb.net verweigert, da hier eine strikte Trennung zwischen den Vorgängen vorgegeben ist. Diese müssen vorher in einen "Invoke" ausgelagert werden, damit dort keine komplikationen auftreten können.
Wird z.B. ein Wert in eine Textbox geschrieben, so muss sicher gestellt werden, dass die Textbox gerade zur Verfügung steht und nicht bereits von irgendeinem anderen Thread bearbeitet wird. Sicherlich wird dieses bei einer simplen Textbox in einfachen Anwendungen selten passieren, man sollte dieses allerdings nicht unterschätzen. Wenn man sich einfach eingearbeitet hat, macht dieses später sogar Sinn.
Entsprechende Meldungen:
Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement [...] erfolgte von einem anderen Thread aus als dem Thread, für den es erstellt wurde.
Ich habe länger eine wirklich 100%ige Methode gesucht bis ich schließlich auf codeproject.com fündig geworden bin. Somit habe ich den vorhanden Quelltext genommen, in eine Klasse verpackt, deren Ergebnis unten zu sehen ist.
Herzstück ist die Funktion OnEvent, welche die Invoke Methode zur Verfügung steht. Hier wird einfach eine Klasse (ThreadEventEventArgs) übergeben, die alle Daten für einen Event bereit hält. Ausgelöst wird das Event schließlich über Ticker(eventMsg), welches z.B in einer Form entgegen genommen werden kann und ohne Begrenzung weiterverarbeitet werden kann.
Form1.vb
Public Class Form1
Dim WithEvents ExampleTicker As New ThreadEvent
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ExampleTicker.Intervall = 1
ExampleTicker.start()
End Sub
Private Sub ExampleTicker_received(ByVal sender As Object, ByVal e As ThreadEvent.ThreadEventEventArgs) Handles ExampleTicker.received
TextBox1.Text = e.ReceivedText
End Sub
End ClassThreadEvent.vb
Imports System.ComponentModel
Public Class ThreadEvent
Public Event received As EventHandler(Of ThreadEventEventArgs)
Private _Intervall As Integer = 1
Dim ThreadReceive As System.Threading.Thread
Dim _stopped As Boolean = False
Public Property Intervall() As Integer
Get
Return _Intervall
End Get
Set(ByVal value As Integer)
_Intervall = value
End Set
End Property
Private Sub ReceiveMessages()
Dim i As Integer = 0
Do
i = i + 1
Dim eventMsg As New ThreadEventEventArgs
eventMsg.ReceivedText = i.ToString
Ticker(eventMsg)
Threading.Thread.Sleep(Me._Intervall * 1000)
Loop Until _stopped = True
End Sub
Sub start()
NewInitialize()
End Sub
Sub stopped()
_stopped = True
If Not ThreadReceive Is Nothing Then
If ThreadReceive.IsAlive Then
ThreadReceive.Abort()
End If
End If
End Sub
Private Sub NewInitialize()
ThreadReceive = New System.Threading.Thread(AddressOf ReceiveMessages)
ThreadReceive.Start()
End Sub
Protected Sub Ticker(ByVal e As ThreadEventEventArgs)
OnEvent(Me, CType(e, EventArgs), receivedEvent)
End Sub
Private Sub OnEvent(ByVal sender As Object, ByVal e As EventArgs, ByVal [event] As System.Delegate)
Dim eventFired As Boolean = False
If [event] IsNot Nothing Then
For Each singleCast As System.Delegate In [event].GetInvocationList()
eventFired = False
Try
Dim syncInvoke As ISynchronizeInvoke = CType(singleCast.Target, ISynchronizeInvoke)
If syncInvoke IsNot Nothing AndAlso syncInvoke.InvokeRequired Then
eventFired = True
syncInvoke.Invoke(singleCast, New Object() {sender, e})
Else
eventFired = True
singleCast.DynamicInvoke(New Object() {sender, e})
End If
Catch ex As System.Reflection.TargetInvocationException
If Not eventFired Then
singleCast.DynamicInvoke(New Object() {sender, e})
End If
End Try
Next
End If
End Sub
Public Class ThreadEventEventArgs
Inherits EventArgs
Dim mReceivedText As String
Dim mReceivedRawText As String
Public Property ReceivedText() As String
Get
Return mReceivedText
End Get
Set(ByVal Value As String)
mReceivedText = Value
End Set
End Property
Public Property ReceivedRawText() As String
Get
Return mReceivedRawText
End Get
Set(ByVal Value As String)
mReceivedRawText = Value
End Set
End Property
End Class
End Class
Disqus - noscript
Daraus konnt ich mir ne Klasse baun die genau das macht, was ich haben wollt! ;)
http://www.vb-paradise.de/prog...