Click here to Skip to main content
15,888,527 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
Hi all,

I need to change a label value in my application and I need to do this from another thread. Here's an example: Form1 is my main form and CheckState is the sub executed in a differend thread.
VB
Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Form1.Load
	Dim T As New Thread(AddressOf CheckState())
	T.IsBackground = False
	T.Start()
End Sub
Public Sub CheckState()
	If My.Settings.Enabled Then
		Form1.Label7.Text = "Enabled"
	Else
		Form1.Label7.Text = "Disabled"
	End If
End Sub

The problem with this code is that it simply does nothing... The label text is not changed and the program reports no errors or exceptions. Let's try to use Invoke:
VB
'The code in the Form1_Load is the same.
Public Sub CheckState()
    If My.Settings.Enabled Then
        Form1.Invoke(Sub() Form1.Label7.Text = "Enabled")
    Else
        Form1.Invoke(Sub() Form1.Label7.Text = "Disabled")
    End If
End Sub

An InvalidOperationException is thrown:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

I don't know what I'm doing wrong, so please help me!

FWhite
Posted
Comments
Ravi Bhavnani 25-Feb-15 12:48pm    
Does the answer on this SO page help?

http://stackoverflow.com/questions/25644824/vb-net-invoke-cannot-be-called-on-a-control-until-the-window-handle-has-been-cre

/ravi
Sergey Alexandrovich Kryukov 25-Feb-15 13:56pm    
This is so-oo... wrong.
—SA

You probably have to call the Form.Show methos before starting your thread in the Form.Load event handler, see this article: "Differences Among Form's Initialize, Load, and Activate Events"[^].
 
Share this answer
 
Comments
FWhite1 25-Feb-15 12:56pm    
Called the Form.Show before starting the thread, but no luck... it still throws the exception.
Wendelius 25-Feb-15 12:56pm    
That would certainly help, 5
FWhite1 25-Feb-15 12:57pm    
Calling the method directly from the Form1_Load obviously works, but since the method has to do long operations, the performance of the application would be worsened.
Sergey Alexandrovich Kryukov 25-Feb-15 13:56pm    
Nobody advised to call something else from Form.Load. By the way, this is the "fake" event I never ever use. It is probably introduced to give the user impression that things work similar to other libraries. Your code is certainly wrong. You can create the thread on this event handle, but you should not stat it. Start it in the Shown handler.
—SA
Sergey Alexandrovich Kryukov 25-Feb-15 13:53pm    
5ed. Using Shown event is one of the solutions (Solution 2).
—SA
As addition to solution 1, or perhaps move the thread start even to Shown[^] event.
 
Share this answer
 
Comments
FWhite1 25-Feb-15 12:59pm    
No, that does not work :(. Still the same exception if I use Invoke. If I don't use Invoke, the program does nothing...
Wendelius 25-Feb-15 13:07pm    
Are you sure you're creating the window in the UI thread, not in another thread?
FWhite1 25-Feb-15 13:11pm    
The only code I've in my Form1_Load event is:
<pre lang="vb">Me.BackgroundImage = My.Resources.wall</pre>
so I assume there's nothing that could change the thread in which the form is created...
Sergey Alexandrovich Kryukov 25-Feb-15 13:51pm    
No, the solution is apparently correct. You do something else in a wrong way. Such problems are quite easy to solve.
—SA
Sergey Alexandrovich Kryukov 25-Feb-15 13:50pm    
5ed. The solution is simple: you need to hoop up some moment of time when Window handle is already created. The inquirer already uses Control.Invoke, which makes sure the invoked call is done on the UI thread. There is only on remote possibility: the Control instance is not part of the UI hierarchy created on the UI thread in question. This is unlikely situation. Also, the inquirer can do something through Invoke, and something else not. :-)
—SA
This is incredibly strange. I moved the
CheckState
sub from the module to the Main form class and it worked. My code now looks like this:
VB
Public Class Form1
    Public Problem As ProblemType
    Dim Subscription As String = ""
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.BackgroundImage = My.Resources.wall
    End Sub
    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        Dim T As New Threading.Thread(AddressOf DecryptSub)
        T.IsBackground = False
        T.Start()
        Dim TR As New Threading.Thread(AddressOf CheckState)
        TR.IsBackground = False
        TR.Start()
        'CheckState() is now in Form1, not in Core (the module). This way it worked!
        If My.Settings.Enabled Then
            Me.Invoke(Sub() Me.Label1.Text = "Enabled")
        Else
            Me.Invoke(Sub() Me.Label1.Text = "Disabled")
        End If

    End Sub

End Class

I really can't understand why but the important thing is that it worked!

Thanks to everyone!
 
Share this answer
 
Here's my code:

FORM1:
VB
Public Class Form1
    Public Enum ProblemType
        MissingSubscription
        ErrorReadingSubscription
        SubscriptionExpired
    End Enum
    Public Problem As ProblemType
    Dim Subscription As String = ""
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        'Me.BackgroundImage = My.Resources.wall
        'This line of code was present in my original project to change the background of
        ' the form setting a different image in Resources. This is the ONLY line of code I 
        ' have in my original project, so no other operations are done at Form1_Load!
    End Sub
    Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        Dim T As New Threading.Thread(AddressOf DecryptSub)
        T.IsBackground = False
        T.Start()
        Dim TR As New Threading.Thread(AddressOf CheckState)
        TR.IsBackground = False
        TR.Start()
    End Sub
End Class


CORE (A MODULE):
VB
Module Core
    Public MainPath As String = My.Application.Info.DirectoryPath & "\License\Lic.lic"
    Public Sub DecryptSub()
        If My.Computer.FileSystem.FileExists(MainPath) Then
            Try
                'A class to decrypt and encrypt files using SHA. I've not included the code
                'cause I don't think it is relevant...
                'Dim Encrypt As New Encriptor
                'Subscription = Encrypt.DecryptFiles(MainPath)
            Catch ex As Exception
                Form1.Problem = Form1.ProblemType.MissingSubscription
                'LogEntry("Could not find subscription file.", MessageType.Failure)
            End Try

        End If
    End Sub
    Public Sub CheckState()
        'Here I have two different scenarios:
        'FIRST ONE:
        'If My.Settings.Enabled Then
        '    Form1.Label1.Text = "Enabled"
        'Else
        '    Form1.Label1.Text = "Disabled"
        'End If
        'No exceptions are thrown, but as you can see, the program does nothing and
        'the value of the Label remains "Value goes here!"



        'Second One:
        'If My.Settings.Enabled Then
        '    Form1.Invoke(Sub() Form1.Label1.Text = "Enabled")
        'Else
        '    Form1.Invoke(Sub() Form1.Label1.Text = "Disabled")
        'End If
        '
        'I get this exception:
        '
        'System.InvalidOperationException was unhandled
        'HResult = -2146233079
        '  Message=Impossibile chiamare Invoke o BeginInvoke su un controllo finché non viene creato un handle di finestra.
        '        Source = System.Windows.Forms
        'StackTrace:
        '       in System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
        '       in System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
        '       in System.Windows.Forms.Control.Invoke(Delegate method)
        '       in thread1.Core.CheckState() in Z:\desktop\thread1\thread1\Core.vb:riga 32
        '       in System.Threading.ThreadHelper.ThreadStart_Context(Object state)
        '       in System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
        '       in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
        '       in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
        '       in System.Threading.ThreadHelper.ThreadStart()
        'InnerException:

    End Sub
End Module


This is the relevant code that will reproduce the issue.

Thanks again!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900