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

BackgroundWorker "Cross-thread operation not valid..."

P: n/a
I'm using a BackgroundWorker to perform a file download from an ftp site.
Per good code design practices where I separate my UI code from my core
logic code (in this case my Download file method in my FileIO class) I've
established Public Event in my core logic classes along with RaiseEvents
(that will updated a progress bar on the UI side). This all works great
when I'm NOT using Threading (BackgroundWorker), however, as soon as I
introduce threading and fire off the download via a BackgroundWorker
control, I get the above error whenever I issue an RaiseEvents in my core
code.

I've gone thru the many samples and noticed that none of them separate UI
code from logic code (perhaps to save time for purpose of demonstration).
So it appears that the simple approach of using BackGroundWorker is once
again not very useful for anyone implementing more professional code
design/solutions.

It would appear to me that if I want this to work correctly, I'd have to
pass to my core logic the background worker control? Not an option. Or,
setup a public event for the BackgroundWorker control and change my raise
event to reference the event that will trigger the background worker?

I must admit, I'm not sure why this limitation exists?
Rob
Jun 18 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
See here: http://weblogs.asp.net/justin_rogers...es/126345.aspx

Short answer, use InvokeRequired

"Rob R. Ainscough" <ro*****@pacbell.net> wrote in message
news:eU**************@TK2MSFTNGP04.phx.gbl...
I'm using a BackgroundWorker to perform a file download from an ftp site.
Per good code design practices where I separate my UI code from my core
logic code (in this case my Download file method in my FileIO class) I've
established Public Event in my core logic classes along with RaiseEvents
(that will updated a progress bar on the UI side). This all works great
when I'm NOT using Threading (BackgroundWorker), however, as soon as I
introduce threading and fire off the download via a BackgroundWorker
control, I get the above error whenever I issue an RaiseEvents in my core
code.

I've gone thru the many samples and noticed that none of them separate UI
code from logic code (perhaps to save time for purpose of demonstration).
So it appears that the simple approach of using BackGroundWorker is once
again not very useful for anyone implementing more professional code
design/solutions.

It would appear to me that if I want this to work correctly, I'd have to
pass to my core logic the background worker control? Not an option. Or,
setup a public event for the BackgroundWorker control and change my raise
event to reference the event that will trigger the background worker?

I must admit, I'm not sure why this limitation exists?
Rob

Jun 19 '06 #2

P: n/a
Brendan,

Good article, but it was written before .NET 2.0 was released. I'm using
the new BackgroundWork approach (in .NET 2.0) to threading as it implements
much cleaner and more manageable code than Invoke approach.

Still testing out some solutions, but I suspect I might be able to use
WithEvents on the BackgroudWorker defined in my class modules -- it also
appears that BackgroundWorker is part of system.componentmodel so I can
conceptually use it in my non-UI classes effectively retaining separation of
UI code.

Rob.

"Brendan Green" <bg****@nospam.nospam> wrote in message
news:Oh*************@TK2MSFTNGP04.phx.gbl...
See here: http://weblogs.asp.net/justin_rogers...es/126345.aspx

Short answer, use InvokeRequired

"Rob R. Ainscough" <ro*****@pacbell.net> wrote in message
news:eU**************@TK2MSFTNGP04.phx.gbl...
I'm using a BackgroundWorker to perform a file download from an ftp site.
Per good code design practices where I separate my UI code from my core
logic code (in this case my Download file method in my FileIO class) I've
established Public Event in my core logic classes along with RaiseEvents
(that will updated a progress bar on the UI side). This all works great
when I'm NOT using Threading (BackgroundWorker), however, as soon as I
introduce threading and fire off the download via a BackgroundWorker
control, I get the above error whenever I issue an RaiseEvents in my core
code.

I've gone thru the many samples and noticed that none of them separate UI
code from logic code (perhaps to save time for purpose of demonstration).
So it appears that the simple approach of using BackGroundWorker is once
again not very useful for anyone implementing more professional code
design/solutions.

It would appear to me that if I want this to work correctly, I'd have to
pass to my core logic the background worker control? Not an option. Or,
setup a public event for the BackgroundWorker control and change my raise
event to reference the event that will trigger the background worker?

I must admit, I'm not sure why this limitation exists?
Rob


Jun 19 '06 #3

P: n/a
Hi Rob,

You must use Control.Invoke to invoke code on the UI thread, which is the
thread that is running the message-loop, when you want to update the display
such as a progress bar. If you call a method on a Control from a different
Thread you will get an exception in the 2.0 framework.
Control.InvokeRequired is used to determine whether the code is calling from
another Thread, and if so Control.Invoke should be used. Control invocation
on the UI thread has nothing to do with the BackgroundWorker and is required
no matter the type of asynchronous architecture you implement.

// ctrl is assumed to be an instance of a Control or a derived Type

private void AsyncMethod()
{
if (ctrl.InvokeRequired)
{
ctrl.Invoke(new MethodInvoker(ctrl.Invalidate));
}
else
{
ctrl.Invalidate();
}
}

HTH

"Rob R. Ainscough" <ro*****@pacbell.net> wrote in message
news:eU**************@TK2MSFTNGP04.phx.gbl...
I'm using a BackgroundWorker to perform a file download from an ftp site.
Per good code design practices where I separate my UI code from my core
logic code (in this case my Download file method in my FileIO class) I've
established Public Event in my core logic classes along with RaiseEvents
(that will updated a progress bar on the UI side). This all works great
when I'm NOT using Threading (BackgroundWorker), however, as soon as I
introduce threading and fire off the download via a BackgroundWorker
control, I get the above error whenever I issue an RaiseEvents in my core
code.

I've gone thru the many samples and noticed that none of them separate UI
code from logic code (perhaps to save time for purpose of demonstration).
So it appears that the simple approach of using BackGroundWorker is once
again not very useful for anyone implementing more professional code
design/solutions.

It would appear to me that if I want this to work correctly, I'd have to
pass to my core logic the background worker control? Not an option. Or,
setup a public event for the BackgroundWorker control and change my raise
event to reference the event that will trigger the background worker?

I must admit, I'm not sure why this limitation exists?
Rob

Jun 19 '06 #4

P: n/a
Dave,

I've discovered that I can't access any controls from within the thread --
at first this tossed me for a loop (and I'm still not convinced this is a
good implementation by .NET 2.0 since the thread is still under the scope of
the calling source -- I'm using BackgroundWorker). However, I was
determine to keep my non-UI core classes (i.e. FileIO.Download) working for
any usage that might be tossed at it.

I was able to come up with a WithEvents and RaiseEvent approach in my non-UI
classes that would eventually make it to the UI handler which would call the
BackgroundWorker.ReportProgress. I created my own userState object class
(again non-UI) that could be used to provide any additional information to
the ProgressChanged.

In the core of the file download code I issue a raise event (using a ByRef
on boolean) after each byte stream is received that checks the state of the
BackgroundWorker.CancellationPending which is return in my local method's
boolean variable. I check to see if true and then exit and close the
stream, if not continues processing. So the class can handle both being
threaded and non-thread implementations.

Rob.
"Dave Sexton" <dave@jwa[remove.this]online.com> wrote in message
news:%2****************@TK2MSFTNGP04.phx.gbl...
Hi Rob,

You must use Control.Invoke to invoke code on the UI thread, which is the
thread that is running the message-loop, when you want to update the
display such as a progress bar. If you call a method on a Control from a
different Thread you will get an exception in the 2.0 framework.
Control.InvokeRequired is used to determine whether the code is calling
from another Thread, and if so Control.Invoke should be used. Control
invocation on the UI thread has nothing to do with the BackgroundWorker
and is required no matter the type of asynchronous architecture you
implement.

// ctrl is assumed to be an instance of a Control or a derived Type

private void AsyncMethod()
{
if (ctrl.InvokeRequired)
{
ctrl.Invoke(new MethodInvoker(ctrl.Invalidate));
}
else
{
ctrl.Invalidate();
}
}

HTH

"Rob R. Ainscough" <ro*****@pacbell.net> wrote in message
news:eU**************@TK2MSFTNGP04.phx.gbl...
I'm using a BackgroundWorker to perform a file download from an ftp site.
Per good code design practices where I separate my UI code from my core
logic code (in this case my Download file method in my FileIO class) I've
established Public Event in my core logic classes along with RaiseEvents
(that will updated a progress bar on the UI side). This all works great
when I'm NOT using Threading (BackgroundWorker), however, as soon as I
introduce threading and fire off the download via a BackgroundWorker
control, I get the above error whenever I issue an RaiseEvents in my core
code.

I've gone thru the many samples and noticed that none of them separate UI
code from logic code (perhaps to save time for purpose of demonstration).
So it appears that the simple approach of using BackGroundWorker is once
again not very useful for anyone implementing more professional code
design/solutions.

It would appear to me that if I want this to work correctly, I'd have to
pass to my core logic the background worker control? Not an option. Or,
setup a public event for the BackgroundWorker control and change my raise
event to reference the event that will trigger the background worker?

I must admit, I'm not sure why this limitation exists?
Rob


Jun 19 '06 #5

P: n/a
Hmmm...

Here is some sample code that I'm using right now (uses
BackgroundWorkerThread and populates a listview for event logging):

BackgroundWorker m_eventWorker = new BackgroundWorker();

// This delegate enables asynchronous calls for adding items
// to a ListView control.
delegate void AddEventToListCallback(ListViewItem lvi);

....

public frmConsole()
{
InitializeComponent();
Helper.RunRemotingServices();

m_eventWorker.DoWork += new DoWorkEventHandler(m_eventWorker_DoWork);
}

private void frmConsole_Load(object sender, EventArgs e)
{
m_eventWorker.RunWorkerAsync();
}

void m_eventWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
if (Fenestra.Foundation.Core.EventQueue.Events.Count > 0)
{
Fenestra.Foundation.Core.Event et =
Fenestra.Foundation.Core.EventQueue.Events.Dequeue ();
ListViewItem i = new ListViewItem(new string[] {
et.Timestamp.ToString("dd/MM @ HH:mm:ss.mm"), et.Data });
i.Tag = et;

this.AddEventToList(i);
}

System.Threading.Thread.Sleep(new TimeSpan(0, 0, 5));
}
}
private void AddEventToList(ListViewItem lvi)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.lvEvents.InvokeRequired)
{
AddEventToListCallback d = new AddEventToListCallback(AddEventToList);
this.Invoke(d, new object[] { lvi });
}
else
{
this.lvEvents.Items.Add(lvi);
}
}

"Rob R. Ainscough" <ro*****@pacbell.net> wrote in message
news:eL**************@TK2MSFTNGP05.phx.gbl...
Brendan,

Good article, but it was written before .NET 2.0 was released. I'm using
the new BackgroundWork approach (in .NET 2.0) to threading as it
implements much cleaner and more manageable code than Invoke approach.

Still testing out some solutions, but I suspect I might be able to use
WithEvents on the BackgroudWorker defined in my class modules -- it also
appears that BackgroundWorker is part of system.componentmodel so I can
conceptually use it in my non-UI classes effectively retaining separation
of UI code.

Rob.

"Brendan Green" <bg****@nospam.nospam> wrote in message
news:Oh*************@TK2MSFTNGP04.phx.gbl...
See here: http://weblogs.asp.net/justin_rogers...es/126345.aspx

Short answer, use InvokeRequired

"Rob R. Ainscough" <ro*****@pacbell.net> wrote in message
news:eU**************@TK2MSFTNGP04.phx.gbl...
I'm using a BackgroundWorker to perform a file download from an ftp
site. Per good code design practices where I separate my UI code from my
core logic code (in this case my Download file method in my FileIO
class) I've established Public Event in my core logic classes along with
RaiseEvents (that will updated a progress bar on the UI side). This all
works great when I'm NOT using Threading (BackgroundWorker), however, as
soon as I introduce threading and fire off the download via a
BackgroundWorker control, I get the above error whenever I issue an
RaiseEvents in my core code.

I've gone thru the many samples and noticed that none of them separate
UI code from logic code (perhaps to save time for purpose of
demonstration). So it appears that the simple approach of using
BackGroundWorker is once again not very useful for anyone implementing
more professional code design/solutions.

It would appear to me that if I want this to work correctly, I'd have to
pass to my core logic the background worker control? Not an option.
Or, setup a public event for the BackgroundWorker control and change my
raise event to reference the event that will trigger the background
worker?

I must admit, I'm not sure why this limitation exists?
Rob



Jun 19 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.