VB.Net: Event Handle Prozedur kann nicht auf Objekte einer Form zugreifen


Orakel

Erfahrenes Mitglied
Hallo zusammen

nach 7 Jahren habe ich mich doch mal wieder entschlossen mir VB.Net anzuschauen und schon beim ersten Versuch verstehe ich die Reaktion nicht.
Szenario: Auf einer Form befinden sich eine Textbox und ein Button. Der Button startet in einer Klasse einen Timer, der nach Ablauf einen Wert aus der Klasse zurückgeben soll. Das ganze Handling funktioniert auch bis auf die Tatsache, dass ich in der Handler Prozedur nicht mehr auf die Textbox zugreifen kann. Hier die verkürzten Codes

Die Form
Code:
Public Class frm_Main
   
    Private WithEvents                  cls_EventTest As New cEventTest

    Public Sub New()
        InitializeComponent()

        ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
        AddHandler cls_EventTest.TimerIsReady, AddressOf cls_EventTest_HandleEvent
    End Sub

    Private Sub cls_EventTest_HandleEvent( ByVal nValue As Integer ) Handles cls_EventTest.TimerIsReady
        Me.txt_Output.Text = CStr( nValue ) ' Hier entsteht der Fehler
    End Sub

    Private Sub btn_Test_Click(sender As Object, e As EventArgs) Handles btn_Test.Click
        cls_EventTest.StartTimer
    End Sub
End Class
Die Klasse
Code:
Imports System.Timers

Public Class cEventTest
    Private m_Timer                         As New System.Timers.Timer

    Public Event TimerIsReady( ByVal nValue As Integer )

    Public Function StartTimer()
        AddHandler m_Timer.Elapsed, New ElapsedEventHandler( AddressOf Me.TimerCallback )
        m_Timer.Interval = 5000
        m_Timer.AutoReset = False
        m_Timer.Enabled = True
    End Function

    Public Sub TimerCallback( ByVal oSender As Object, ByVal oEventArgs As ElapsedEventArgs )
        RaiseEvent TimerIsReady( 200 )
    End Sub
End Class
Kann mir hier evtl. einer auf die Sprünge helfen, und mir sagen wo meine Gehirnwindungen verknotet sind??

Danke
Das Orakel :)
 
Zuletzt bearbeitet:

Orakel

Erfahrenes Mitglied
So ich habe eine Lösung gefunden. Evtl. Kann mir dass ja mal einer erklären :)

Code:
Public Class frm_Main
    
    Private WithEvents                  cls_EventTest As New cEventTest

    Public Sub New()
        InitializeComponent()

        ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
        AddHandler cls_EventTest.TimerIsReady, AddressOf cls_EventTest_HandleEvent
    End Sub

    Private Sub cls_EventTest_HandleEvent( ByVal nValue As Integer ) Handles cls_EventTest.TimerIsReady
        Me.Invoke( New MethodInvoker( AddressOf Display ) ) ' Hier eine interne Funktion/Prozedur aufrufen
'        Me.txt_Output.Text = CStr( nValue )
    End Sub

    Private Sub btn_Test_Click(sender As Object, e As EventArgs) Handles btn_Test.Click
        cls_EventTest.StartTimer
    End Sub

    Private Sub Display( )
        Me.txt_Output.Text = CStr( "Hallo" )
    End Sub
End Class
Tschööö
das Orakel
 

Spyke

Premium-User
Schaut mir aus als wenn du Thread übergreifenden Aufrufe versucht hattest.

cls_EventTest_HandleEvent
scheint in einem Background Thread zu laufen, während deine TextBox im UI-/Hauptthread liegt.

Eigentlich hätte eine Thread Exception kommen müssen.

Mittels Invoke führst du deine Display Methode nun wieder im UI Thread aus, dort wo du auch zugriff auf deine TextBox hast.
 

Orakel

Erfahrenes Mitglied
Hallo Spyke

danke für die Info. Du hast recht, da kam eine Fehlermeldung mit einer Thread Exception. Kann ich den Handler so implementieren, dass er nicht in einem anderen Thread läuft?? Würde mich nur mal so interessieren. Wie gesagt bin ich gerade mal wieder in die Programmierung eingestiegen :) und die Informationsflut ist aktuell riesen groß :)

vielen Dank
Das Orakel
 
Zuletzt bearbeitet:

Orakel

Erfahrenes Mitglied
Habe noch mal ein Post aus meiner letzten Antwort gemacht.

Ich habs rausgefunden. Es liegt an dem verwendeten Timer in der Klasse. Nimmt man den lt. MS vorgeschlagenen System.Windows.Forms.Timer, dann klappt es so wie gedacht. Der von mir verwendete System.Timers.Timer reiht sein Elapsed-Ereignis in einem Thread Pool ein, der natürlich nix von meiner Form weiss. Und Hier das Erbegnis mit dem ich arbeiten kann :)


Code:
Public Class frm_Main
    Private WithEvents                  cls_EventTest As cWindowsTimer

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub cls_EventTest_HandleEvent( ByVal dValue As Double ) Handles cls_EventTest.TimerIsReady
        Me.txt_Output.Text = CStr( dValue )
    End Sub

    Private Sub btn_Test_Click(sender As Object, e As EventArgs) Handles btn_Test.Click
        cls_EventTest = New cWindowsTimer
        cls_EventTest.StartTimer( 2 )
    End Sub
End Class

Public Class cWindowsTimer
    Private WithEvents m_Timer                          As System.Windows.Forms.Timer
    Private m_dValue                                    As Double = 1

    Public Event TimerIsReady( ByVal dValue As Double )
    Public Sub StartTimer( ByVal nSeconds As Integer )
        m_Timer = New System.Windows.Forms.Timer
        m_Timer.Interval = nSeconds * 1000
        m_Timer.Enabled = True
    End Sub

    Private Sub m_Timer_Handler( ByVal oSender As Object, ByVal oEventArgs As System.EventArgs ) Handles m_Timer.Tick
        m_dValue = m_dValue + ( m_dValue * 0.01 )
        RaiseEvent TimerIsReady( m_dValue )
    End Sub
End Class
vielen Dank
Das Orakel
 

Neue Beiträge