Question Custom Controls and Threads

stulish

Well-known member
Joined
Jun 6, 2013
Messages
61
Programming Experience
3-5
Hi i am having a problem with a custom control i have created, the form only has 3 labels on it Label1, Label2 and Label 3, there are PNG files in the resources that load into the background of the control depending on a warning level that is set.

The problem i am getting is when i try to set the line text:


Control.Line1text = "Something"
when i use this command in my program that used teh custom control i get:

Cross-thread operation not valid: Control 'Label2' accessed from a thread other than the thread it was created on.

The code is below:

VB.NET:
[COLOR=blue]Public[/COLOR] [COLOR=blue]Class[/COLOR] [COLOR=#2b91af]POWER_Box[/COLOR]
    [COLOR=blue]Dim[/COLOR] WarningProperty [COLOR=blue]As[/COLOR] [COLOR=blue]Short[/COLOR] = 0
    [COLOR=blue]Public[/COLOR] [COLOR=blue]Enum[/COLOR] [COLOR=#2b91af]Warnings[/COLOR]
        Clear = 0
        Warning = 1
        Critical = 2
    [COLOR=blue]End[/COLOR] [COLOR=blue]Enum[/COLOR]
    [COLOR=blue]Public[/COLOR] [COLOR=blue]Property[/COLOR] WarningLevel [COLOR=blue]As[/COLOR] [COLOR=#2b91af]Warnings[/COLOR]
        [COLOR=blue]Set[/COLOR](value [COLOR=blue]As[/COLOR] [COLOR=#2b91af]Warnings[/COLOR])
            WarningProperty = value
            [COLOR=blue]Dim[/COLOR] PS [COLOR=blue]As[/COLOR] IO.[COLOR=#2b91af]Stream[/COLOR]
            [COLOR=blue]Dim[/COLOR] bmp [COLOR=blue]As[/COLOR] [COLOR=#2b91af]Bitmap[/COLOR]
            PS = [COLOR=blue]Me[/COLOR].GetType.Assembly.GetManifestResourceStream([COLOR=#a31515]"POWER_Box.Text Box_"[/COLOR] & WarningProperty.ToString.Trim & [COLOR=#a31515]".png"[/COLOR])
            bmp = [COLOR=blue]New[/COLOR] [COLOR=#2b91af]Bitmap[/COLOR](PS)
            BackgroundImage = bmp
        [COLOR=blue]End[/COLOR] [COLOR=blue]Set[/COLOR]
        [COLOR=blue]Get[/COLOR]
            [COLOR=blue]Return[/COLOR] WarningProperty
        [COLOR=blue]End[/COLOR] [COLOR=blue]Get[/COLOR]
 
    [COLOR=blue]End[/COLOR] [COLOR=blue]Property[/COLOR]
    [COLOR=blue]Public[/COLOR] [COLOR=blue]Property[/COLOR] Line1text [COLOR=blue]As[/COLOR] [COLOR=blue]String[/COLOR]
        [COLOR=blue]Set[/COLOR](value [COLOR=blue]As[/COLOR] [COLOR=blue]String[/COLOR])
            Label1.Text = value
        [COLOR=blue]End[/COLOR] [COLOR=blue]Set[/COLOR]
        [COLOR=blue]Get[/COLOR]
            [COLOR=blue]Return[/COLOR] Label1.Text
        [COLOR=blue]End[/COLOR] [COLOR=blue]Get[/COLOR]
    [COLOR=blue]End[/COLOR] [COLOR=blue]Property[/COLOR]
    [COLOR=blue]Public[/COLOR] [COLOR=blue]Property[/COLOR] Line2text [COLOR=blue]As[/COLOR] [COLOR=blue]String[/COLOR]
        [COLOR=blue]Set[/COLOR](value [COLOR=blue]As[/COLOR] [COLOR=blue]String[/COLOR])
            Label2.Text = value
        [COLOR=blue]End[/COLOR] [COLOR=blue]Set[/COLOR]
        [COLOR=blue]Get[/COLOR]
            [COLOR=blue]Return[/COLOR] Label2.Text
        [COLOR=blue]End[/COLOR] [COLOR=blue]Get[/COLOR]
    [COLOR=blue]End[/COLOR] [COLOR=blue]Property[/COLOR]
    [COLOR=blue]Public[/COLOR] [COLOR=blue]Property[/COLOR] Line3text [COLOR=blue]As[/COLOR] [COLOR=blue]String[/COLOR]
        [COLOR=blue]Set[/COLOR](value [COLOR=blue]As[/COLOR] [COLOR=blue]String[/COLOR])
            Label3.Text = value
        [COLOR=blue]End[/COLOR] [COLOR=blue]Set[/COLOR]
        [COLOR=blue]Get[/COLOR]
            [COLOR=blue]Return[/COLOR] Label3.Text
        [COLOR=blue]End[/COLOR] [COLOR=blue]Get[/COLOR]
    [COLOR=blue]End[/COLOR] [COLOR=blue]Property[/COLOR]
[COLOR=blue]End[/COLOR] [COLOR=blue]Class[/COLOR]

What am i doing wrong, it seems to work except when trying to change the text during run time.
 
It appears you are trying to set that text from a secondary thread, you have to use the UI thread when accessing controls. BackgroundWorker component usually makes that easy in winforms environment, you can also use Control.Invoke to transfer invokation to UI thread.
 
As JohnH suggests, you should be somehow marshalling a method call to the UI thread first, before you try use a member of your user control. There are a number of ways to do that so, if you need specific advice, please let us know how you're accessing the secondary thread in the first place. If you're using a BackgroundWorker then don't touch any controls in the DoWork event handler; only update the UI in the ProgressChanged or RunWorkerCompleted event handler. Otherwise, if the code is in a form then you should be using the InvokeRequired property and Invoke method of your control to get back to the UI thread. Here's a break-down of how to write code that does that:

Accessing Controls from Worker Threads
 
Back
Top