G
Guest
I have an interesting scenario involving CF 2.0, data sources, threading and
the UI thread. I might be doing this completely wrong.
** The current state:
I have a datasource class that wraps a DataSet - which looks something like
this:
public class myDataSource : IListSource
{
DataTable dt = new DataTable();
public void Update()
{
...
dt.Rows.Add(...);
...
}
public IList IListSource.GetList()
{
return ((IListSource)dt).GetList();
}
}
and this class is bound to a DataGridView:
MyDataSource src = new MyDataSource();
this.dataGridView.DataSource = src;
void Button_Click(object sender, EventArgs e)
{
((MyDataSource)this.dataGridView.DataSource)src).Update();
}
Calling Update() works correctly in a Button_Click handler for example (as
long as it's called from the UI thread) and the databinding logic (through
IBindingList) works fine. When the button is clicked the DataTable changes
and the GridView updates itself automatically.
My problem is that I need to be able to call it on a timer (using a
different thread):
TimerCallback callback = new
TimerCallback(((MyDataSource)(this.dataGridView.DataSource)).Update);
System.Threading.Timer timer = new System.Threading.Timer(callback, null,
2*1000, Timeout.Infinite);
[Note: The example above is just academic, the callback will be calling the
update method through a global singleton instance of the MyDataSource]
When this version of Update() is called the DataTable gets updated but the
DataGridView is not updated/redrawn (probably because the databinding stuff
now happens on a different thread from the UI-thread). When the DataGridView
is invalidated it redraws itself with the newly added rows.
All the examples of this suggest using the Invoke method of the DataGridView
(or any other control in the UI-thread basically). But neither the
MyDataSource or the Timer knows about any UI-controls (which are in a
separate dll).
The MyDataSource.Update() method needs to be able to sync itself to the
UI-thread in order for the DataBinding to work correctly. But how does it go
around doing that? The MyDataSource could be bound to more than one control.
** Random thoughts:
Doing (new Form()).Invoke() doesn't seem to work.
Using a class that inherits IBindingList directly works across threads.
There might be a problem with the wrapping-datatable-class-solution itself.
The Update() method makes an HttpRequest call which returns a DataTable and
then does dt.Merge(newDataTable). This works fine when called on the
UI-thread.
Having a "public static Form mainForm" variable in the Program class to use
for Program.mainForm.Invoke is not a nice way of solving this. Also the dll
containing the myDataSource would be too coupled with the actual application.
** The problem (if anyone has a better way of achieving the desired result):
I have a WebService that returns a DataTable (DataSet with one DataTable
actually). This data is to be displayed in a DataGridView. The data needs to
be updated periodically.
What I'm trying to do is use the DataBinding mechanism in the .NET framework
to solve this for me. The idea was to bind the DataGridView to a DataTable
and then update the DataTable. The DataBinding mechanism was supposed to take
care of the rest and cause the DataGridView to update accordingly.
This completely brakes down when threads are involved as the DataBinding
stuff needs to happen on the UI-thread for the DataGridView to properly
redraw itself.
I thought this would be the most elegant way of doing this. Just do:
myDataGridView.DataSource = myDataSource;
and the rest would happen autmagically
Any comments or suggestions are welcome!
With regards,
the UI thread. I might be doing this completely wrong.
** The current state:
I have a datasource class that wraps a DataSet - which looks something like
this:
public class myDataSource : IListSource
{
DataTable dt = new DataTable();
public void Update()
{
...
dt.Rows.Add(...);
...
}
public IList IListSource.GetList()
{
return ((IListSource)dt).GetList();
}
}
and this class is bound to a DataGridView:
MyDataSource src = new MyDataSource();
this.dataGridView.DataSource = src;
void Button_Click(object sender, EventArgs e)
{
((MyDataSource)this.dataGridView.DataSource)src).Update();
}
Calling Update() works correctly in a Button_Click handler for example (as
long as it's called from the UI thread) and the databinding logic (through
IBindingList) works fine. When the button is clicked the DataTable changes
and the GridView updates itself automatically.
My problem is that I need to be able to call it on a timer (using a
different thread):
TimerCallback callback = new
TimerCallback(((MyDataSource)(this.dataGridView.DataSource)).Update);
System.Threading.Timer timer = new System.Threading.Timer(callback, null,
2*1000, Timeout.Infinite);
[Note: The example above is just academic, the callback will be calling the
update method through a global singleton instance of the MyDataSource]
When this version of Update() is called the DataTable gets updated but the
DataGridView is not updated/redrawn (probably because the databinding stuff
now happens on a different thread from the UI-thread). When the DataGridView
is invalidated it redraws itself with the newly added rows.
All the examples of this suggest using the Invoke method of the DataGridView
(or any other control in the UI-thread basically). But neither the
MyDataSource or the Timer knows about any UI-controls (which are in a
separate dll).
The MyDataSource.Update() method needs to be able to sync itself to the
UI-thread in order for the DataBinding to work correctly. But how does it go
around doing that? The MyDataSource could be bound to more than one control.
** Random thoughts:
Doing (new Form()).Invoke() doesn't seem to work.
Using a class that inherits IBindingList directly works across threads.
There might be a problem with the wrapping-datatable-class-solution itself.
The Update() method makes an HttpRequest call which returns a DataTable and
then does dt.Merge(newDataTable). This works fine when called on the
UI-thread.
Having a "public static Form mainForm" variable in the Program class to use
for Program.mainForm.Invoke is not a nice way of solving this. Also the dll
containing the myDataSource would be too coupled with the actual application.
** The problem (if anyone has a better way of achieving the desired result):
I have a WebService that returns a DataTable (DataSet with one DataTable
actually). This data is to be displayed in a DataGridView. The data needs to
be updated periodically.
What I'm trying to do is use the DataBinding mechanism in the .NET framework
to solve this for me. The idea was to bind the DataGridView to a DataTable
and then update the DataTable. The DataBinding mechanism was supposed to take
care of the rest and cause the DataGridView to update accordingly.
This completely brakes down when threads are involved as the DataBinding
stuff needs to happen on the UI-thread for the DataGridView to properly
redraw itself.
I thought this would be the most elegant way of doing this. Just do:
myDataGridView.DataSource = myDataSource;
and the rest would happen autmagically
Any comments or suggestions are welcome!
With regards,