By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,285 Members | 1,647 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,285 IT Pros & Developers. It's quick & easy.

Strange behavior of Visible property in multithreading app

P: n/a
Can anyone explain why this happens with the code at the bottom?

It looked like a thread safety issue, but changing the declaration of
Label1 to Shared doesn't help.
Standard windows form; one label, two buttons.

- if Label1.Visible is set to True in the form designer, everything
works as expected. Button1 toggles the label visibility, and Button2
flashes it on for 250 msec.

- if Label1.Visible is set to False in the form designer and the
Button2_Click line in Form1_Load is commented out so the new thread
isn't started automatically at form load, everything still works the
same.

- if Label1.Visible is set to False in the form designer and the
Button2_Click line in Form1_Load is left enabled, the label always
remains hidden, regardless of the state of its Visible property.

The debug output shows that the property value flips between false and
true when Button1 is clicked, but the label remains invisible.

This code is simplified to the bare bones needed to reproduce the
problem:
Imports System.Threading

Public Class Form1
Inherits System.Windows.Forms.Form

[+] [ Windows Form Designer generated code ]

Private Sub ThreadProc()
Label1.Visible = True
Thread.Sleep(250)
Label1.Visible = False
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Button2_Click(Nothing, Nothing)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Label1.Visible = Not Label1.Visible
Debug.WriteLine(Label1.Visible)
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim thr As New Thread(AddressOf ThreadProc)
thr.Start()
End Sub
End Class
In the real application it's a servername validity test for an SQL
connection, it checks if the server exists and if the database exists
on the server. It's implemented as a separate thread to prevent
network problems from freezing the UI for the time-out period. The
label is used to indicate that the test is still in progress.

A mutex synchronizes everything that's accessed by more than one
thread there (i.e. the label and a few variables), it was left out
here because having it or not doesn't change anything to the problem.

Nov 20 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
* Lucvdv <re**********@null.net> scripsit:
This code is simplified to the bare bones needed to reproduce the
problem:
Imports System.Threading

Public Class Form1
Inherits System.Windows.Forms.Form

[+] [ Windows Form Designer generated code ]

Private Sub ThreadProc()
Label1.Visible = True
Thread.Sleep(250)
Label1.Visible = False


You /must not/ access instance members of Windows Forms forms/controls
from within another thread directly. Instead, you can use
'Control.Invoke'/'Control.BeginInvoke':

<URL:http://msdn.microsoft.com/library/en-us/dnforms/html/winforms06112002.asp>
<URL:http://msdn.microsoft.com/library/en-us/dnforms/html/winforms08162002.asp>
<URL:http://msdn.microsoft.com/library/en-us/dnforms/html/winforms01232003.asp>

<URL:http://www.devx.com/dotnet/Article/11358/>

<URL:http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemWindowsFormsControlClassInvokeTopic.asp >

Multithreading in Visual Basic .NET (Visual Basic Language Concepts)
<URL:http://msdn.microsoft.com/library/en-us/vbcn7/html/vaconthreadinginvisualbasic.asp>

<URL:http://dotnet.mvps.org/dotnet/samples/filesystem/downloads/FileSystemEnumerator.zip>

--
Herfried K. Wagner [MVP]
<URL:http://dotnet.mvps.org/>
Nov 20 '05 #2

P: n/a
On 14 Jul 2004 13:08:15 +0200, hi***************@gmx.at (Herfried K.
Wagner [MVP]) wrote:
You /must not/ access instance members of Windows Forms forms/controls
from within another thread directly. Instead, you can use [...]


Thanks, so it's what I expected it to be indeed.

What put me on the wrong leg is, in the 'label' documentation:
Any public static (Shared in Visual Basic) members of this type are
thread safe. Any instance members are not guaranteed to be thread
safe.


I thought it would be enough to change the declaration of the label
from "Friend Withevents" to "Shared" (shared and withevents don't seem
to mix well, but missing the events for a label is no problem).

But making it shared didn't change anything, so I started scratching
my hair.

Nov 20 '05 #3

P: n/a
On 14 Jul 2004 13:08:15 +0200, hi***************@gmx.at (Herfried K. Wagner
[MVP]) wrote:
You /must not/ access instance members of Windows Forms forms/controls


Thanks again. The bit of extra code below, idea stolen from one of the
links you posted, did it.

It's much more than necessary in this simple example, but in this form it
can be called from anywhere - it calls itself back in the right thread if
necessary.

Funny that InvokeRequired isn't shown by intellisense, but it's documented
and it works--or does that mean there's yet another pitfall?
Private Delegate Sub d_SetLabelVisibility(ByVal State As Boolean)

Private Sub SetLabelVisibility(ByVal State As Boolean)
If Label1.InvokeRequired Then
Dim delg As New d_SetLabelVisibility(AddressOf SetLabelVisibility)
Label1.Invoke(delg, New Object() {State})
Else
Label1.Visible = State
End If
End Sub

Private Sub ThreadProc()
SetLabelVisibility(True)
Thread.Sleep(250)
SetLabelVisibility(False)
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
SetLabelVisibility(Not Label1.Visible)
Debug.WriteLine(Label1.Visible)
End Sub

Nov 20 '05 #4

P: n/a
* Lucvdv <re**********@null.net> scripsit:
You /must not/ access instance members of Windows Forms forms/controls
from within another thread directly. Instead, you can use [...]


Thanks, so it's what I expected it to be indeed.

What put me on the wrong leg is, in the 'label' documentation:
Any public static (Shared in Visual Basic) members of this type are
thread safe. Any instance members are not guaranteed to be thread
safe.


I thought it would be enough to change the declaration of the label
from "Friend Withevents" to "Shared" (shared and withevents don't seem
to mix well, but missing the events for a label is no problem).


The sentence you quote from the docs is referring to members declared as
'Shared' inside the 'Label' class.

--
Herfried K. Wagner [MVP]
<URL:http://dotnet.mvps.org/>
Nov 20 '05 #5

P: n/a
On 14 Jul 2004 16:21:10 +0200, hi***************@gmx.at (Herfried K. Wagner
[MVP]) wrote:
Any public static (Shared in Visual Basic) members of this type are
thread safe. Any instance members are not guaranteed to be thread
safe.
The sentence you quote from the docs is referring to members declared as
'Shared' inside the 'Label' class.

Finally got it -- [members of] [this type] != [members] [of this type] :)

After seeing it, it's logical - if they meant the second, it would have
been "instances" instead of "members".

The problem is that when you read something wrong the first time, you often
keep reading it that way later too, and I probably wasn't fully focused
when I read it for the first time.

Nov 20 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.