Re: threading question
From: Lucvdv (replace_name_at_null.net)
Date: 09/03/04
- Next message: Cor Ligthert: "Re: No Equals on interfaces"
- Previous message: Boyd Ferris: "Re: crystal reports 9 and crystal reports.net"
- In reply to: Peter Huang: "Re: threading question"
- Next in thread: Peter Huang: "Re: threading question"
- Reply: Peter Huang: "Re: threading question"
- Messages sorted by: [ date ] [ thread ]
Date: Fri, 03 Sep 2004 09:31:06 +0200
On Fri, 03 Sep 2004 05:14:38 GMT, v-phuang@online.microsoft.com ("Peter
Huang") wrote:
> Hi,
>
> When did you create the control, if it is created in the working thread,
> there is no need to invoke across thread.
The control is created in the class constructor (sub New()), which means
it's created in the form's UI thread.
My problem was that ctl.InvokeRequired *always* returned False, whatever
thread it was called from, which meant some code in my app was executed in
the wrong thread while I expected the InvokeRequired/Invoke to take care of
that. I added sample code below to illustrate it.
The problem is solved, I just want to signal it because I found nothing in
the documetation that warns for this possibility, and someone else might be
bitten by it too.
Through some more experimenting, I found that [control].InvokeRequired
always returns False as long as the control hasn't been added to a form's
controls collection. The documentation says "Property Value: True if the
control's Handle was created on a different thread than the calling
thread", but just creating it in a form's UI thread isn't enough.
Sample code: the class is created in the form's constructor. The control
is created in the class's New(), so it is created by the UI thread.
FireTest calls InvokeRequired and Invoke on the control to ensure that the
event is fired in the UI thread, yet the event handler says it isn't.
The only place where FireTest is called is from within another thread, so
upon entry it should always log "InvokeRequired: True" in the debug pane,
followed by "InvokeRequired: False" when it's re-entered in the UI thread.
Instead, it reports False right away.
I included the full code, including auto-generated. You can create a new
standard windows app in VS.Net 2003 and paste everything below over the
generated code, it should work.
'----------------------------------------------------------------
Imports System.Threading
Public Class Form1
Inherits System.Windows.Forms.Form
Private tst As TestClass
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
tst = New TestClass
AddHandler tst.TestEvent, AddressOf TestEventHandler
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Button1 As System.Windows.Forms.Button
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(104, 80)
Me.Button1.Name = "Button1"
Me.Button1.TabIndex = 0
Me.Button1.Text = "Test"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 181)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub
#End Region
Private Class TestClass
Public Event TestEvent()
Private thr As Thread
Private m_Ctl As Control
Public Sub New()
m_Ctl = New Control
End Sub
Private Delegate Sub d_FireTest()
Private Sub FireTest()
Debug.WriteLine(m_Ctl.InvokeRequired, "InvokeRequired")
If m_Ctl.InvokeRequired Then
m_Ctl.Invoke(New d_FireTest(AddressOf FireTest))
Else
RaiseEvent TestEvent()
End If
End Sub
Public Sub Test()
thr = New Thread(AddressOf ThreadProc)
thr.Start()
End Sub
Private Sub ThreadProc()
Thread.Sleep(250)
FireTest()
End Sub
End Class
Private Sub TestEventHandler()
If Me.InvokeRequired Then
MsgBox("Event handler not running in UI thread")
Else
MsgBox("Test event OK")
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
tst.Test()
End Sub
End Class
- Next message: Cor Ligthert: "Re: No Equals on interfaces"
- Previous message: Boyd Ferris: "Re: crystal reports 9 and crystal reports.net"
- In reply to: Peter Huang: "Re: threading question"
- Next in thread: Peter Huang: "Re: threading question"
- Reply: Peter Huang: "Re: threading question"
- Messages sorted by: [ date ] [ thread ]