Threading WinForm

A

ajk

I am confused, I come from Win32 and am now trying to learn C#
threading

I have a simple winform with a button, in the button's eventhandler I
create a thread, I want the thread to report progress to the form i.e.
writing a line in a list box, but the app throws an exception
complaining about the listbox being in another thread. Fine, but how
do solve this in the simplest manner?

Here is some of the code:

in the button event handler I start the thread
...
Thread workerThread = new Thread(SimulatedClient);
workerThread.IsBackground = true;
workerThread.Name = "My Thread";
workerThread.Start(this); // the form instance passed
as argument
...

in the form I have a listbox say 'lbList'

the thread function is declared as (not sure if using static is needed
here)

private static void SimulatedClient(Object objParent)
{
MyFormClass mfc = (MyFormClass)objParent; // getting the
form instance
... do some stuff ...
mfc.Items.Add("Some Msg"); <-- gives the exception
}

All of the above is in the same form class.

I have looked at delegates and events a bit but the coin hasn't fallen
down yet :) In Win32 I would for instance send a message from the
thread to the main window, how is this done in C#/.NET?

Thanks in advance.
Anders.
 
M

Michael Nemtsev [MVP]

Hello ajk,

Read Jon's article http://www.yoda.arachsys.com/csharp/threads/winforms.shtml


---
WBR,
Michael Nemtsev [.NET/C# MVP] :: blog: http://spaces.live.com/laflour

"The greatest danger for most of us is not that our aim is too high and we
miss it, but that it is too low and we reach it" (c) Michelangelo


a> I am confused, I come from Win32 and am now trying to learn C#
a> threading
a>
a> I have a simple winform with a button, in the button's eventhandler I
a> create a thread, I want the thread to report progress to the form
a> i.e. writing a line in a list box, but the app throws an exception
a> complaining about the listbox being in another thread. Fine, but how
a> do solve this in the simplest manner?
a>
a> Here is some of the code:
a>
a> in the button event handler I start the thread
a> ...
a> Thread workerThread = new Thread(SimulatedClient);
a> workerThread.IsBackground = true;
a> workerThread.Name = "My Thread";
a> workerThread.Start(this); // the form instance passed
a> as argument
a> ...
a> in the form I have a listbox say 'lbList'
a>
a> the thread function is declared as (not sure if using static is
a> needed here)
a>
a> private static void SimulatedClient(Object objParent)
a> {
a> MyFormClass mfc = (MyFormClass)objParent; // getting the
a> form instance
a> ... do some stuff ...
a> mfc.Items.Add("Some Msg"); <-- gives the exception
a> }
a> All of the above is in the same form class.
a>
a> I have looked at delegates and events a bit but the coin hasn't
a> fallen down yet :) In Win32 I would for instance send a message from
a> the thread to the main window, how is this done in C#/.NET?
a>
a> Thanks in advance.
a> Anders.
 
M

Mufaka

You need to use BeginInvoke to marshal back to the ui thread.

Something like this (haven't compiled / typed in ide)

private delegate void AddItemDelegate(string text);

private void AddItem(string itemText)
{
if (lbList.InvokeRequired)
{
lbList.BeginInvoke(new AddItemDelegate(AddItem, new object[] {
itemText }));
}
else
{
lbList.Items.Add(itemText);
}
}

Your thread will call AddItem
 
P

Peter Duniho

I am confused, I come from Win32 and am now trying to learn C#
threading

I have a simple winform with a button, in the button's eventhandler I
create a thread, I want the thread to report progress to the form i.e.
writing a line in a list box, but the app throws an exception
complaining about the listbox being in another thread. Fine, but how
do solve this in the simplest manner?

http://search.msdn.microsoft.com/De...n-us&query="cross-thread operation not valid"

Or

http://groups.google.com/groups/sea...ges.csharp+cross-thread+operation&qt_s=Search

Or, for that matter...

Just click on the link in the debugger's exception alert that promises to
take you to additional help. Where it will explain what to do.

Pete
 
A

ajk

Mufaka said:
You need to use BeginInvoke to marshal back to the ui thread.

Something like this (haven't compiled / typed in ide)

private delegate void AddItemDelegate(string text);

private void AddItem(string itemText)
{
if (lbList.InvokeRequired)
{
lbList.BeginInvoke(new AddItemDelegate(AddItem, new object[] {
itemText }));
}
else
{
lbList.Items.Add(itemText);
}
}

Your thread will call AddItem
I am confused, I come from Win32 and am now trying to learn C#
threading

I have a simple winform with a button, in the button's eventhandler I
create a thread, I want the thread to report progress to the form i.e.
writing a line in a list box, but the app throws an exception
complaining about the listbox being in another thread. Fine, but how
do solve this in the simplest manner?

Here is some of the code:

in the button event handler I start the thread
...
Thread workerThread = new Thread(SimulatedClient);
workerThread.IsBackground = true;
workerThread.Name = "My Thread";
workerThread.Start(this); // the form instance passed
as argument
...

in the form I have a listbox say 'lbList'

the thread function is declared as (not sure if using static is needed
here)

private static void SimulatedClient(Object objParent)
{
MyFormClass mfc = (MyFormClass)objParent; // getting the
form instance
... do some stuff ...
mfc.Items.Add("Some Msg"); <-- gives the exception
}

All of the above is in the same form class.

I have looked at delegates and events a bit but the coin hasn't fallen
down yet :) In Win32 I would for instance send a message from the
thread to the main window, how is this done in C#/.NET?

Thanks in advance.
Anders.


Thank you, this was what I was looking for.

BR/Anders.
 
N

Nicholas Paldino [.NET/C# MVP]

There are a few things missing from this example. The first is that if
you are calling BeginInvoke, then you should have a corresponding call to
EndInvoke (as per the documentation in regards to this particular
asynchronous pattern).

BeginInvoke will make the posting of the windows message which causes
the call in the UI thread asynchronous. Execution will return immediately
after the call, and you can ^not^ assume that the delegate was called at
that point (unless you interface with the IAsyncResult instance passed back
from BeginInvoke).

Calling the Invoke method circumvents this, as it will wait until the UI
thread processes the delegate, and in this situation, is the better option,
IMO.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Mufaka said:
You need to use BeginInvoke to marshal back to the ui thread.

Something like this (haven't compiled / typed in ide)

private delegate void AddItemDelegate(string text);

private void AddItem(string itemText)
{
if (lbList.InvokeRequired)
{
lbList.BeginInvoke(new AddItemDelegate(AddItem, new object[] {
itemText }));
}
else
{
lbList.Items.Add(itemText);
}
}

Your thread will call AddItem
I am confused, I come from Win32 and am now trying to learn C#
threading

I have a simple winform with a button, in the button's eventhandler I
create a thread, I want the thread to report progress to the form i.e.
writing a line in a list box, but the app throws an exception
complaining about the listbox being in another thread. Fine, but how
do solve this in the simplest manner?

Here is some of the code:

in the button event handler I start the thread
...
Thread workerThread = new Thread(SimulatedClient);
workerThread.IsBackground = true;
workerThread.Name = "My Thread";
workerThread.Start(this); // the form instance passed
as argument
...

in the form I have a listbox say 'lbList'

the thread function is declared as (not sure if using static is needed
here)

private static void SimulatedClient(Object objParent)
{
MyFormClass mfc = (MyFormClass)objParent; // getting the
form instance
... do some stuff ...
mfc.Items.Add("Some Msg"); <-- gives the exception
}

All of the above is in the same form class.

I have looked at delegates and events a bit but the coin hasn't fallen
down yet :) In Win32 I would for instance send a message from the
thread to the main window, how is this done in C#/.NET?

Thanks in advance.
Anders.
 
R

Richard Blewett

Hmmm, not sure if I agree with this Nicholas.

<inline>

----- Original Message -----
From: "Nicholas Paldino [.NET/C# MVP]" <[email protected]>
Newsgroups: microsoft.public.dotnet.languages.csharp
Sent: Friday, February 22, 2008 1:27 PM
Subject: Re: Threading WinForm

There are a few things missing from this example. The first is that if
you are calling BeginInvoke, then you should have a corresponding call to
EndInvoke (as per the documentation in regards to this particular
asynchronous pattern).

The only case in the API that am aware of where you call BeginXXX and do
*not* have to call EndXXX is in the case of Control.BeginInvoke. This was
confirmed by the winforms team some time ago (although exactly where escapes
me for now)
BeginInvoke will make the posting of the windows message which causes
the call in the UI thread asynchronous. Execution will return immediately
after the call, and you can ^not^ assume that the delegate was called at
that point (unless you interface with the IAsyncResult instance passed
back from BeginInvoke).

The question here is why does the back ground thread care if the UI update
has taken place of not at this point. There may be examples where it does
but I can;t think of one off the top of my head.
Calling the Invoke method circumvents this, as it will wait until the
UI thread processes the delegate, and in this situation, is the better
option, IMO.

The only case where Control.Invoke was preferential that I came across was
with the tablet Ink API that meant you could end up with unresolvable
synchronization issues if you didn;t serialize the UI update with background
thread work. In most cases you potentially leave yourself unecessarily open
to deadlocks as you are wait for other threads to do things that you're not
dependent on.

Just my $0,02

Regards

Richard Blewett
DevelopMentor
http://www.dotnetconsult.co.uk/weblog2

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Mufaka said:
You need to use BeginInvoke to marshal back to the ui thread.

Something like this (haven't compiled / typed in ide)

private delegate void AddItemDelegate(string text);

private void AddItem(string itemText)
{
if (lbList.InvokeRequired)
{
lbList.BeginInvoke(new AddItemDelegate(AddItem, new object[] {
itemText }));
}
else
{
lbList.Items.Add(itemText);
}
}

Your thread will call AddItem
I am confused, I come from Win32 and am now trying to learn C#
threading

I have a simple winform with a button, in the button's eventhandler I
create a thread, I want the thread to report progress to the form i.e.
writing a line in a list box, but the app throws an exception
complaining about the listbox being in another thread. Fine, but how
do solve this in the simplest manner?

Here is some of the code:

in the button event handler I start the thread
...
Thread workerThread = new Thread(SimulatedClient);
workerThread.IsBackground = true;
workerThread.Name = "My Thread";
workerThread.Start(this); // the form instance passed
as argument
...

in the form I have a listbox say 'lbList'

the thread function is declared as (not sure if using static is needed
here)

private static void SimulatedClient(Object objParent)
{
MyFormClass mfc = (MyFormClass)objParent; // getting the
form instance
... do some stuff ...
mfc.Items.Add("Some Msg"); <-- gives the exception
}

All of the above is in the same form class.

I have looked at delegates and events a bit but the coin hasn't fallen
down yet :) In Win32 I would for instance send a message from the
thread to the main window, how is this done in C#/.NET?

Thanks in advance.
Anders.
 
N

Nicholas Paldino [.NET/C# MVP]

Richard,

See inline:

Richard Blewett said:
Hmmm, not sure if I agree with this Nicholas.

<inline>

----- Original Message -----
From: "Nicholas Paldino [.NET/C# MVP]" <[email protected]>
Newsgroups: microsoft.public.dotnet.languages.csharp
Sent: Friday, February 22, 2008 1:27 PM
Subject: Re: Threading WinForm

There are a few things missing from this example. The first is that
if you are calling BeginInvoke, then you should have a corresponding call
to EndInvoke (as per the documentation in regards to this particular
asynchronous pattern).

The only case in the API that am aware of where you call BeginXXX and do
*not* have to call EndXXX is in the case of Control.BeginInvoke. This was
confirmed by the winforms team some time ago (although exactly where
escapes me for now)

You are right here. I haven't seen this before, but I'll acknowledge my
error here. This is the thread that you are referring to:

http://discuss.develop.com/archives/wa.exe?A2=ind0311b&L=dotnet-clr&P=9244
The question here is why does the back ground thread care if the UI update
has taken place of not at this point. There may be examples where it does
but I can;t think of one off the top of my head.

If the order of the UI updates is important, then you need to use
Invoke. BeginInvoke can not guarantee the order that the messages will get
processed in. If you have two successive calls to BeginInvoke one after
another, it can't be guaranteed that the first call to BeginInvoke will
necessarily process before the second call to BeginInvoke. While it is
^most likely^ that will be the case when processing the successive calls, it
is not guaranteed.

So depending on what your program is doing, and the information it is
displaying (and the order it displays it in), it might or might not be a
good idea.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)
Calling the Invoke method circumvents this, as it will wait until the
UI thread processes the delegate, and in this situation, is the better
option, IMO.

The only case where Control.Invoke was preferential that I came across was
with the tablet Ink API that meant you could end up with unresolvable
synchronization issues if you didn;t serialize the UI update with
background thread work. In most cases you potentially leave yourself
unecessarily open to deadlocks as you are wait for other threads to do
things that you're not dependent on.

Just my $0,02

Regards

Richard Blewett
DevelopMentor
http://www.dotnetconsult.co.uk/weblog2

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Mufaka said:
You need to use BeginInvoke to marshal back to the ui thread.

Something like this (haven't compiled / typed in ide)

private delegate void AddItemDelegate(string text);

private void AddItem(string itemText)
{
if (lbList.InvokeRequired)
{
lbList.BeginInvoke(new AddItemDelegate(AddItem, new object[] {
itemText }));
}
else
{
lbList.Items.Add(itemText);
}
}

Your thread will call AddItem

ajk wrote:
I am confused, I come from Win32 and am now trying to learn C#
threading

I have a simple winform with a button, in the button's eventhandler I
create a thread, I want the thread to report progress to the form i.e.
writing a line in a list box, but the app throws an exception
complaining about the listbox being in another thread. Fine, but how
do solve this in the simplest manner?

Here is some of the code:

in the button event handler I start the thread
...
Thread workerThread = new Thread(SimulatedClient);
workerThread.IsBackground = true;
workerThread.Name = "My Thread";
workerThread.Start(this); // the form instance passed
as argument
...

in the form I have a listbox say 'lbList'

the thread function is declared as (not sure if using static is needed
here)

private static void SimulatedClient(Object objParent)
{
MyFormClass mfc = (MyFormClass)objParent; // getting the
form instance
... do some stuff ...
mfc.Items.Add("Some Msg"); <-- gives the exception
}

All of the above is in the same form class.

I have looked at delegates and events a bit but the coin hasn't fallen
down yet :) In Win32 I would for instance send a message from the
thread to the main window, how is this done in C#/.NET?

Thanks in advance.
Anders.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top