Bug in .NET Tab Control? Help!

G

Guest

I have an app written in C# (obviously). Here is my dilemma:

The form loads, instantiates a bunch of worker threads that execute one at a
time. When one finishes, it starts the next one in line. I have about 5
datagrids on 5 different tab pages in a tab control. What I'm using the
Threads for is pretty basic: get data from a database and fill a datagrid. I
use delegates throughout to allow the worker thread to call the
'FillDataGrid' method in the main thread (the form thread). I've had
problems before with threads not accessing other threads controls which is
why I use the delegates. But still it crashes with the following:

An unhandled exception of type 'System.ArgumentException' occurred in
system.windows.forms.dll

Additional information: Controls created on one thread cannot be parented to
a control on a different thread.

I decided to add another tab page (out of pure imagination) as the first tab
page in the control. voila! now everything loads properly (without changing
any code whatsoever). Problem is, I try to programmatically remove the
temporary page (with a generic "please wait while loading" message). It
removes the page fine, but on the next page in line, all the controls
dissappear. If I don't change or remove tab pages programmatically, all the
controls stay intact. I'm not sure what I am missing, and leaving the temp
page intact is just ugly. Anybody know what I'm missing?
 
J

Jon Skeet [C# MVP]

slylos said:
I have an app written in C# (obviously). Here is my dilemma:

The form loads, instantiates a bunch of worker threads that execute one at a
time. When one finishes, it starts the next one in line. I have about 5
datagrids on 5 different tab pages in a tab control. What I'm using the
Threads for is pretty basic: get data from a database and fill a datagrid. I
use delegates throughout to allow the worker thread to call the
'FillDataGrid' method in the main thread (the form thread). I've had
problems before with threads not accessing other threads controls which is
why I use the delegates. But still it crashes with the following:

An unhandled exception of type 'System.ArgumentException' occurred in
system.windows.forms.dll

Additional information: Controls created on one thread cannot be parented to
a control on a different thread.

That suggests your threading isn't what you think it is. Are you sure
you're using Control.Invoke rather than calling Invoke or BeginInvoke
directly on the delegate?

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
G

Guest

I'll try to give you more of my code without running out of space here:

I've got a Windows form where the tabcontrol is located
(frmScheduleRequestsAdmin)
I've got a db layer that connects to a web service that I built to retreive
the records from the database (tsClientWebServiceConnection.dll)
the db layer has a method 'GetPendingScheduleRequests'. here is the
delegates in the db layer:

------------------------------------>db layer
code<----------------------------------------
public delegate void PendingScheduleRequestsComplete(DataSet dsPending);
public static PendingScheduleRequestsComplete PendingRequestsComplete;

//here is the method that retrieves the pending requests

public void GetPendingScheduleRequests()
{
MyWebServiceObject obj = new MyWebServiceObject();//name changed =^)
DataSet dsPending;

try
{
dsPending = obj.GetPendingRequests();
}
catch(System.Net.WebException we)
{
//save error info to file
}

if (PendingRequestsComplete != null) //invoke delegate
{
PendingRequestsComplete(dsPending);
}
}
------------------------------------>db layer
code<----------------------------------------

and here is the delegate connection and thread start
------------------------------------>Form
code<------------------------------------------
//form_load
private void frmScheduleRequestAdmin_Load(object sender, System.EventArgs e)
{
tsClientWebServiceConnection ts = new tsClientWebServiceConnection;
tsClientWebServiceConnection.PendingRequestsComplete = new
tsClientWebServiceConnection.PendingScheduleRequestsComplete(LoadPendingScheduleRequests);
Thread tGetPending = new Thread(new
ThreadStart(ts.GetPendingScheduleRequests));

tGetPending.Start();
}


//target for delegate
private void LoadPendingScheduleRequests(DataSet dsPending)
{
dsLocalPendingCopy = dsPending.Copy();
dgPending.DataSource = dsLocalPendingCopy.Tables[0];
ProgressComplete();
}
//progress complete handles tab removal
private void ProgressComplete()
{
tcTabs.TabPages.Remove(tpLoadingPage);
}

------------------------------------->Form
code<-------------------------------------------

when ProgressComplete executes, thats when the next tab in line loses its
controls ... please help!!
 
J

Jon Skeet [C# MVP]

slylos said:
I'll try to give you more of my code without running out of space here:

I've got a Windows form where the tabcontrol is located
(frmScheduleRequestsAdmin)
I've got a db layer that connects to a web service that I built to retreive
the records from the database (tsClientWebServiceConnection.dll)
the db layer has a method 'GetPendingScheduleRequests'. here is the
delegates in the db layer:

It looks like you're doing exactly what the error message is
complaining about - updating a control from a non-UI thread.

See http://www.pobox.com/~skeet/csharp/threads/winforms.shtml

Just "using delegates" doesn't do everything automatically - you need
to call Control.Invoke/BeginInvoke appropriately.
 
G

Guest

Well I'm not having a problem with the error message; that went away as soon
as I added a tabpage in front of the first tabpage with the datagrid. The
problem I'm having is when I programmatically remove that first (temp)
tabpage to expose the tabpage with the datagrid, all the controls on the tab
with the datagrid disappear(including the datagrid, but not their tabpage
parent).

Like I said, I do the same exact thing in another form (with different data,
same controls i.e. tab pages/datagrids) and I never have problems. The
difference between that form and this form is the tabpage on that form is 3rd
in the tabpage order, and on the new form, its the first tabpage in the
order. The problem I'm having is controls mysteriously disappearing . . .
 
J

Jon Skeet [C# MVP]

slylos said:
Well I'm not having a problem with the error message; that went away
as soon as I added a tabpage in front of the first tabpage with the
datagrid. The problem I'm having is when I programmatically remove
that first (temp) tabpage to expose the tabpage with the datagrid,
all the controls on the tab with the datagrid disappear(including the
datagrid, but not their tabpage parent).

Just adding a tabpage hasn't fixed your threading error though. I'm not
sure why the error message went away, but the problem hasn't.
Like I said, I do the same exact thing in another form (with
different data, same controls i.e. tab pages/datagrids) and I never
have problems. The difference between that form and this form is the
tabpage on that form is 3rd in the tabpage order, and on the new
form, its the first tabpage in the order. The problem I'm having is
controls mysteriously disappearing . . .

Just because something has worked in the past doesn't mean it was
guaranteed to work, or that you weren't doing things wrong. If you
access the UI from a different thread, you shouldn't be doing that.
Your code appears to be doing that. Fix it (everywhere you're doing it,
not just in the place where you're seeing problems), and then if it
still doesn't work, we'll look again.
 

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