Question Updating UI label from another class in another thread?

Status
Not open for further replies.

tommykent1210

Member
Joined
Nov 2, 2011
Messages
10
Programming Experience
1-3
Hey guys (and girls?),

I've been programming in vb.NET for a while, and I've just began to sink my teeth into threading. And to be honest, its turning out to be a real pain.

Here is the code:

Form1.vb:
Imports System.Threading
Public Class Form1
    Dim trd As Thread
    Public Shared classy As New Class1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        trd = New Thread(AddressOf Dostuff)
        trd.IsBackground = True
        trd.Start()
    End Sub

    Public Delegate Sub SetTextDelegate(ByVal TheText As String)
    Private Sub delSetText(ByVal TheText As String)
        Label1.Text = TheText
        Label1.Update()
    End Sub

    Public Sub ChangeText(ByVal TheText As String)
        If Label1.InvokeRequired Then
            BeginInvoke(New SetTextDelegate(AddressOf delSetText), TheText)
        Else
            delSetText(TheText)
        End If
    End Sub


    Sub Dostuff()
        classy.Main()
    End Sub

End Class


Class1.vb:
Imports System.Threading
Public Class Class1


    Public Sub Main()
        For i As Integer = 0 To 100
            Form1.ChangeText("button " & i)
        Next
    End Sub

End Class



So, I have a form (form1) with a label on, this label simply reports the status of the thread. The thread begins the Class1.Main() sub, and I have a delegate setup to change the text propoerty of the label.

Now, I know the label is created on the UI thread, so I assumed the delegate would work. However, it seems that it updates the .text property, but doesnt redraw the control when .Update() is called :(

What am I doing wrong?

I have found lots of examples of delegates, but all run from within the same class. I want to use threads too, not a backgroundworker! This code is a "simplified" version of a project I am on, which is encountering the same problems :(

Thanks,
Tom
 
The default form instance feature is thread specific, accessing it from a different thread than the UI thread will only return you a brand new form instance.

You have two options;
  • the dependency option is to pass the form reference (Me) to the class so that the class can use it,
  • the good OOP option is to declare an event in the class and let any consumer (that is your form now!) handle that event.
 
Could you give me a code example of the second method (OOP method) :) I think I understand what you mean, but I'm not sure :)

Thanks
 
Here's an introduction to events in Visual Basic: Events
 
So I would make the events in class1, then in the main form, create an object of the class WithEvents?

Then have a timer set to raise the events every X seconds. The events are linked to functions that return the values?
 
Bump, I'm really not sure about this :( I've never used events before either. Do I create the event in the main for or the class?
 
An event is a signal that informs an application that something important has occurred.
Which of your classes should inform which? Which of your classes has information it wants to share? Where does the information come from?
 
The information is in class1, which it gets from a recursive crawling subroutine. The sub should then send the info to the main form :)
 
The sub should then send the info to the main form
When it comes to events, you are sending information without dependency. The "class1" using events doesn't send info to main form specifically, it just raise the event as indication of something happened. Any object that holds a reference to a 'class1' object can then subscribe to its events and get notified.
 
When it comes to events, you are sending information without dependency. The "class1" using events doesn't send into to main form specifically, it just raise the event as indication of something happened. Any object that holds a reference to a 'class1' object can then subscribe to its events and get notified.

Ok :) so I'd create the event In class1, but how would I actually update the controls? Would I just do:

In class1.vb:
Sub Xhandle() Handles Me.TheUpdateEvent
main.label1.text = "test"
main.label1.refresh()

End Sub


Then call (in form1.vb):
dim classy as new class1
RaiseEvent classy.TheUpdateEvent 



Thanks
Tom
 
Surely you meant Me.Label1, but not so fast. When you are raising an event, you are in effect just calling all event method handlers, so if your method that raises the event is running on a secondary thread then so will the event handlers. Everybody knows you can't access a control directly from a secondary thread, and as you already know how to invoke a method to access the control by UI thread you also know what to do when handling an async event.
 
Surely you meant Me.Label1, but not so fast. When you are raising an event, you are in effect just calling all event method handlers, so if your method that raises the event is running on a secondary thread then so will the event handlers. Everybody knows you can't access a control directly from a secondary thread, and as you already know how to invoke a method to access the control by UI thread you also know what to do when handling an async event.

Wait? I though it would be main.label1.text because I was creating the event in class1. I'm really confused. If I create the event in the class1, and call it from the UI thread (form1.vb) then how does the event know what the data is that is being passed to it?
 
That's right, you have that all backwards. If a class wants to notify listeners about something happening it must declare an event and raise it when that happens. You said so yourself, "The information is in class1", so only "class1" knows when something happens and can raise an event about it.
 
So, i make the event subs in class1.vb? Calling a delegate sub in the main form?

Do you have a code example? I'm completely confused :(

I have a main form, and another class. The main form needs to know when the other class has finished one recursive loop.

1. The main form open up.
2. The user clicks a button creating a new instance of the Class1, in it's own thread.
3. This begins the crawling recursive process.
4. After one round of recursion is finished, it needs to update the label1.text on the main form

I can't find any examples of doing this anywhere on the net. Do you have to use events? Because I can't seem to find any relevant info anywhere :(
 
Don't overcomplicate, events is such a basic thing. To enable a class to give notifications you just have to declare an event in it, whenever the notification is to be given you raise that event.
 
Status
Not open for further replies.
Back
Top