Can I safely add rows to a DataTable in non UI thread?

W

wackyphill

If I have the datasource of a datagrid set to a dataTable, can I add
rows to that table in a non UI thread w/o causing problems?

Or do I really need to invoke a method running on the UI thread?

Note the datagrid is readonly. Records can be selected from it but not
modified.
 
M

MuZZy

If I have the datasource of a datagrid set to a dataTable, can I add
rows to that table in a non UI thread w/o causing problems?

Or do I really need to invoke a method running on the UI thread?

Note the datagrid is readonly. Records can be selected from it but not
modified.

Well, if a datagrid is readonly and theer is no other way for a user to modify it's datasource, it
should be safe to use a separate thread to update the table. The multithreading issues only happen
when two threads access the same table at the same time, which is not your case

BR,
Andrey
 
D

darek

MuZZy said:
Well, if a datagrid is readonly and theer is no other way for a user to
modify it's datasource, it should be safe to use a separate thread to
update the table. The multithreading issues only happen when two threads
access the same table at the same time, which is not your case

I think that DataView (DefaultDataView of DataGrid) is accessing this
table at the same time.

Phill, You shoud try this. I haven't tried it, but maybe it will work.

// call this code from non UI thread
Form1Reference.Invoke(new SafeInsertRowDelegate(SafeInsertRow),
new object[] {drow});

// Form1 code
public delegate void SafeInsertRowDelegate(DataRow drow);
private void SafeInsertRow(DataRow drow)
{
DataRow dataRow1 = dataTable1.NewRow;
dataRow1.ItemArray = drow.ItemArray;
dataTable1.Rows.Add(dataRow1);
dataRow1 = null;
}
 
J

Jon Skeet [C# MVP]

MuZZy said:
Well, if a datagrid is readonly and theer is no other way for a user
to modify it's datasource, it should be safe to use a separate thread
to update the table. The multithreading issues only happen when two
threads access the same table at the same time, which is not your
case

No, it's not concurrent access to the data table which is the problem
here - it's the fact that changes to the table will trigger UI events,
which will run on the thread which causes the change. That means that
you can only change the table on the UI thread, unfortunately.
 
U

Uchiha Jax

It's in a datagrid, right?

Try this:

public void SomeMethod(obj args)
if(this.dataGrid1.InvokeRequired)
{
object[] objArr = new object[1];
objArr[0] = args;
IAsyncResult result = this.dataGrid1.BeginInvoke(new
SomeDelegate(ShowMethod), objArr);
result.AsyncWaitHandle.WaitOne(10, true);
if(result.IsCompleted)
this.dataGrid1.EndInvoke(result);
}
else
{
///// put the code you want to run in here
}
 
W

wackyphill

Yeah, I think I'll have to do it like that. Why do you recreate the
passed datarow though?
 
I

Ignacio Machin \( .NET/ C# MVP \)

hi,

yes, you can add it, just be careful as usual with accesing an object from
more than one thread.

when you refresh the grid you DO have to do it from the UI thread though.

now, I think to remember that I read somewhere a suggestion to use a
DataView instead of the DataTable , to avoid some problem when binding, not
sure the context though. let me google for it to see if it's relevent for
you.

cheers,
 
D

darek

Yeah, I think I'll have to do it like that. Why do you recreate the
passed datarow though?

One datarow cannot belongs to more than one datatable. If you create
datarow in datatable and want add this same datarow to another
datatable, exception will be thrown. The only way (i think) is to copy
values frow datarow to datarow, the simplest way is to use ItemArray
property.

darek
 
R

Richard Blewett [DevelopMentor]

Note, there is no need for the code that calls EndInvoke on the datagrid.

Control.EndInvoke is the one exception to the rule that if you call BeginXXX you must call EndXXX

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

It's in a datagrid, right?

Try this:

public void SomeMethod(obj args)
if(this.dataGrid1.InvokeRequired)
{
object[] objArr = new object[1];
objArr[0] = args;
IAsyncResult result = this.dataGrid1.BeginInvoke(new
SomeDelegate(ShowMethod), objArr);
result.AsyncWaitHandle.WaitOne(10, true);
if(result.IsCompleted)
this.dataGrid1.EndInvoke(result);
}
else
{
///// put the code you want to run in here
}
 
R

Richard Blewett [DevelopMentor]

The problem is, as Jon points out, that adding the row to a datatable that has a datagrid bound to it will fire an event in the datagrid code on the thread that adds the row - in other words on the non-UI thread. This will cause bad things to happen

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

hi,

yes, you can add it, just be careful as usual with accesing an object from
more than one thread.

when you refresh the grid you DO have to do it from the UI thread though.

now, I think to remember that I read somewhere a suggestion to use a
DataView instead of the DataTable , to avoid some problem when binding, not
sure the context though. let me google for it to see if it's relevent for
you.

cheers,
 
J

Jon Skeet [C# MVP]

Uchiha Jax said:
It's in a datagrid, right?

Try this:

public void SomeMethod(obj args)
if(this.dataGrid1.InvokeRequired)
{
object[] objArr = new object[1];
objArr[0] = args;
IAsyncResult result = this.dataGrid1.BeginInvoke(new
SomeDelegate(ShowMethod), objArr);
result.AsyncWaitHandle.WaitOne(10, true);
if(result.IsCompleted)
this.dataGrid1.EndInvoke(result);
}
else
{
///// put the code you want to run in here
}

Why bother calling EndInvoke, and only doing it conditionally? Why not
just ignore it entirely?
 

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