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

DataGridView - TextBoxColumn - background update to data source

P: n/a
I have a DataGridView with a TextBoxColumn. I setting the data source to a
List<stringvalue in a static class. The list is filled from a background
thread. So far all is fine and it works great, at least on my system.

The reason I am doing this is some customers are pulling from VPN
connections which are slow. This allows the list of rows in the data grid
to appear a little quicker while the list which are not used as soon load in
the background.

Oh so with a LAN connection there is no problem since everything loads too
quick to notice. But on the slower connections which I simulate with a
sleep command in the list fill the data grid's text box column comes up
empty as expected. When the list is filled the main window needs to update
the cell to display the data.

So to fill the cell I have tried a couple things.

First doing a refresh on the binding that holds the data source. This works
on drop down list but not on the data grid text boxes.

((CurrencyManager)this.BindingContext[this.ratesDataGridViewTextBoxColumn.DataSource]).Refresh();

Second replacing the data source with the same data source. This refreshes
all the displayed cell except the selected one and when you scroll up there
are still empty cell that may or may not in the course of time fill.

this.ratesDataGridViewTextBoxColumn.DataSource =
Data.clsCacheData.CacheHolder.DialingProperties;

Third attempt was doing a refresh on the data grid itself. Looks bad
(flicker) and does not update all the cells.

this.DataGridView1.Refresh().

Does anyone have another suggestion?

Regards,
John
Nov 10 '06 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Hi John,

Make sure that you are updating the data source on the UI thread only.

If you're using the 2.0 framework use the BackgroundWorker class to run the
async process but don't load the data directly into the data source from
within the DoWork event handler. Instead, save a copy of the data and make
sure the copy is accessible to the RunWorkerCompleted event handler. The
BackgroundWorker class makes sure that the RunWorkerCompleted event handler is
invoked on the UI thread, where you can update the real data source with the
downloaded data:

private void RunProcessAsync()
{
BackgroundWorker worker = new BackgroundWorker();

string asyncData = null;

// use an anonymous method to do the async work
worker.DoWork += delegate(object sender1, DoWorkEventArgs e1)
{
asyncData = "Async Data From BackgroundWorker";
};

// use an anonymous method to process completion
worker.RunWorkerCompleted += delegate(object sender2,
RunWorkerCompletedEventArgs e2)
{
// update data source
realDataSource = asyncData;
};

worker.RunWorkerAsync();
}

If you're using an early framework version then you should call Invoke on the
Form to marshal the call to the UI thread yourself. This can be done from
within the background thread after the download operation has completed.
Again, you shouldn't update the real data source in the background thread, but
save a copy of the downloaded data and update the data source from within the
method executed by the Invoke method:

private void RunProcessAsync()
{
string asyncData = null;

ThreadPool.QueueUserWorkItem(new WaitCallback(RunProcess), asyncData);
}

private void RunProcess(object state)
{
string asyncData = (string) state;

asyncData = "Async Data From ThreadPool";

// marshal a call back to the UI thread to update the data source
Invoke(new ProcessCompleteInvoker(ProcessComplete), asyncData);
}

private delegate void ProcessCompleteInvoker(string asyncData);

private void ProcessComplete(string asyncData)
{
// update data source
realDataSource = asyncData;
}

In my examples I'm simply setting a string value to the "realDataSource"
variable, but you can perform any operation that is required by your
application, such as updating a DataTable or calling Refresh on a Binding.

If this doesn't work for you then I suspect your bindings might have been
setup incorrectly or you're not updating the appropriate data source.

--
Dave Sexton

"John J. Hughes II" <no@invalid.comwrote in message
news:%2****************@TK2MSFTNGP04.phx.gbl...
>I have a DataGridView with a TextBoxColumn. I setting the data source to a
List<stringvalue in a static class. The list is filled from a background
thread. So far all is fine and it works great, at least on my system.

The reason I am doing this is some customers are pulling from VPN
connections which are slow. This allows the list of rows in the data grid
to appear a little quicker while the list which are not used as soon load in
the background.

Oh so with a LAN connection there is no problem since everything loads too
quick to notice. But on the slower connections which I simulate with a
sleep command in the list fill the data grid's text box column comes up
empty as expected. When the list is filled the main window needs to update
the cell to display the data.

So to fill the cell I have tried a couple things.

First doing a refresh on the binding that holds the data source. This works
on drop down list but not on the data grid text boxes.
((CurrencyManager)this.BindingContext[this.ratesDataGridViewTextBoxColumn.DataSource]).Refresh();

Second replacing the data source with the same data source. This refreshes
all the displayed cell except the selected one and when you scroll up there
are still empty cell that may or may not in the course of time fill.

this.ratesDataGridViewTextBoxColumn.DataSource =
Data.clsCacheData.CacheHolder.DialingProperties;

Third attempt was doing a refresh on the data grid itself. Looks bad
(flicker) and does not update all the cells.

this.DataGridView1.Refresh().

Does anyone have another suggestion?

Regards,
John

Nov 11 '06 #2

P: n/a
Dave,

Thanks for the response.

I have the data sources set as static to the application and then being
accessed via MDI forms, I am tying to use them as read only by the data
grids on several forms. The static class is using the back ground worker in
2.0 and sending a copy of the list back to the static class.

Should I assume that this static class is not on the same thread as the MDI
forms?

Regards,
John

"Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
news:eR**************@TK2MSFTNGP02.phx.gbl...
Hi John,

Make sure that you are updating the data source on the UI thread only.

If you're using the 2.0 framework use the BackgroundWorker class to run
the async process but don't load the data directly into the data source
from within the DoWork event handler. Instead, save a copy of the data
and make sure the copy is accessible to the RunWorkerCompleted event
handler. The BackgroundWorker class makes sure that the
RunWorkerCompleted event handler is invoked on the UI thread, where you
can update the real data source with the downloaded data:

private void RunProcessAsync()
{
BackgroundWorker worker = new BackgroundWorker();

string asyncData = null;

// use an anonymous method to do the async work
worker.DoWork += delegate(object sender1, DoWorkEventArgs e1)
{
asyncData = "Async Data From BackgroundWorker";
};

// use an anonymous method to process completion
worker.RunWorkerCompleted += delegate(object sender2,
RunWorkerCompletedEventArgs e2)
{
// update data source
realDataSource = asyncData;
};

worker.RunWorkerAsync();
}

If you're using an early framework version then you should call Invoke on
the Form to marshal the call to the UI thread yourself. This can be done
from within the background thread after the download operation has
completed. Again, you shouldn't update the real data source in the
background thread, but save a copy of the downloaded data and update the
data source from within the method executed by the Invoke method:

private void RunProcessAsync()
{
string asyncData = null;

ThreadPool.QueueUserWorkItem(new WaitCallback(RunProcess), asyncData);
}

private void RunProcess(object state)
{
string asyncData = (string) state;

asyncData = "Async Data From ThreadPool";

// marshal a call back to the UI thread to update the data source
Invoke(new ProcessCompleteInvoker(ProcessComplete), asyncData);
}

private delegate void ProcessCompleteInvoker(string asyncData);

private void ProcessComplete(string asyncData)
{
// update data source
realDataSource = asyncData;
}

In my examples I'm simply setting a string value to the "realDataSource"
variable, but you can perform any operation that is required by your
application, such as updating a DataTable or calling Refresh on a Binding.

If this doesn't work for you then I suspect your bindings might have been
setup incorrectly or you're not updating the appropriate data source.

--
Dave Sexton

"John J. Hughes II" <no@invalid.comwrote in message
news:%2****************@TK2MSFTNGP04.phx.gbl...
>>I have a DataGridView with a TextBoxColumn. I setting the data source to
a List<stringvalue in a static class. The list is filled from a
background thread. So far all is fine and it works great, at least on my
system.

The reason I am doing this is some customers are pulling from VPN
connections which are slow. This allows the list of rows in the data
grid to appear a little quicker while the list which are not used as soon
load in the background.

Oh so with a LAN connection there is no problem since everything loads
too quick to notice. But on the slower connections which I simulate
with a sleep command in the list fill the data grid's text box column
comes up empty as expected. When the list is filled the main window
needs to update the cell to display the data.

So to fill the cell I have tried a couple things.

First doing a refresh on the binding that holds the data source. This
works on drop down list but not on the data grid text boxes.
((CurrencyManager)this.BindingContext[this.ratesDataGridViewTextBoxColumn.DataSource]).Refresh();

Second replacing the data source with the same data source. This
refreshes all the displayed cell except the selected one and when you
scroll up there are still empty cell that may or may not in the course of
time fill.

this.ratesDataGridViewTextBoxColumn.DataSource =
Data.clsCacheData.CacheHolder.DialingProperties ;

Third attempt was doing a refresh on the data grid itself. Looks bad
(flicker) and does not update all the cells.

this.DataGridView1.Refresh().

Does anyone have another suggestion?

Regards,
John


Nov 13 '06 #3

P: n/a
Well, a class is not on any specific thread without going to a lot of
trouble... all operations (including events raised) will happen in the
thread of the causing code - so if your background worker does something it
will execute on the background thread, and if your UI does something it will
execute on the UI thread. Hopefully not at the same time ;-p

If receiving events from this class in an MDI scenario, you should check
InvokeRequired and react accordingly. Unfortunately, data-binding may also
attempt to hook up events, and send itself in circles in trying.

Marc
Nov 13 '06 #4

P: n/a
Marc,

Hum, guess I need to have two copies then, the static global copy and then a
local copy to the form that gets invoked when changes to the static copy
changes.

Will try that, see if it flys.

Regards,
John

"Marc Gravell" <ma**********@gmail.comwrote in message
news:e6**************@TK2MSFTNGP03.phx.gbl...
Well, a class is not on any specific thread without going to a lot of
trouble... all operations (including events raised) will happen in the
thread of the causing code - so if your background worker does something
it will execute on the background thread, and if your UI does something it
will execute on the UI thread. Hopefully not at the same time ;-p

If receiving events from this class in an MDI scenario, you should check
InvokeRequired and react accordingly. Unfortunately, data-binding may also
attempt to hook up events, and send itself in circles in trying.

Marc

Nov 13 '06 #5

P: n/a
Hi John,
I have the data sources set as static to the application and then being
accessed via MDI forms, I am tying to use them as read only by the data
grids on several forms. The static class is using the back ground worker in
2.0 and sending a copy of the list back to the static class.

Should I assume that this static class is not on the same thread as the MDI
forms?
Classes aren't on threads. Class members (instance and static) are always
executed within a thread. Multiple threads may execute the same instance
member or static member, simultaneously. This is where thread synchronization
using the "lock" keyword becomes useful, for example.

If you have bound the UI controls to your static data source then you have to
make sure that you don't modify the data source from within your
BackgroundWorker.DoWork event handler because it will be running on a
ThreadPool thread - not the UI thread.

Unfortunately, you won't get any errors when manipulating the data source on a
ThreadPool thread because, technically, it's a valid operation. So you'll
have to be smarter than the controls to which the data is bound by making sure
that you manipulate the data source from the UI thread only - the controls
aren't going to do that for you.

My code examples should help you with that.

--
Dave Sexton
Nov 13 '06 #6

P: n/a
Dave,

My code looks very similar to your which was why I was asking if because it
was static made a difference. The static class is created by the main
frame and not the MDI. Oh well will review your code some more, I now have
someplace to look if nothing else.

Regards,
John

"Dave Sexton" <dave@jwa[remove.this]online.comwrote in message
news:%2****************@TK2MSFTNGP03.phx.gbl...
Hi John,
>I have the data sources set as static to the application and then being
accessed via MDI forms, I am tying to use them as read only by the data
grids on several forms. The static class is using the back ground worker
in 2.0 and sending a copy of the list back to the static class.

Should I assume that this static class is not on the same thread as the
MDI forms?

Classes aren't on threads. Class members (instance and static) are always
executed within a thread. Multiple threads may execute the same instance
member or static member, simultaneously. This is where thread
synchronization using the "lock" keyword becomes useful, for example.

If you have bound the UI controls to your static data source then you have
to make sure that you don't modify the data source from within your
BackgroundWorker.DoWork event handler because it will be running on a
ThreadPool thread - not the UI thread.

Unfortunately, you won't get any errors when manipulating the data source
on a ThreadPool thread because, technically, it's a valid operation. So
you'll have to be smarter than the controls to which the data is bound by
making sure that you manipulate the data source from the UI thread only -
the controls aren't going to do that for you.

My code examples should help you with that.

--
Dave Sexton


Nov 13 '06 #7

P: n/a
Ok, the problem was I was setting the data source to an empty list and then
trying to fill it. If I leave the data source unset and then set it when
the list is filled the update occurs correctly.

Thanks all for the help.

Regards,
John
"John J. Hughes II" <no@invalid.comwrote in message
news:%2****************@TK2MSFTNGP04.phx.gbl...
>I have a DataGridView with a TextBoxColumn. I setting the data source to
a List<stringvalue in a static class. The list is filled from a
background thread. So far all is fine and it works great, at least on my
system.

The reason I am doing this is some customers are pulling from VPN
connections which are slow. This allows the list of rows in the data grid
to appear a little quicker while the list which are not used as soon load
in the background.

Oh so with a LAN connection there is no problem since everything loads too
quick to notice. But on the slower connections which I simulate with a
sleep command in the list fill the data grid's text box column comes up
empty as expected. When the list is filled the main window needs to
update the cell to display the data.

So to fill the cell I have tried a couple things.

First doing a refresh on the binding that holds the data source. This
works on drop down list but not on the data grid text boxes.
((CurrencyManager)this.BindingContext[this.ratesDataGridViewTextBoxColumn.DataSource]).Refresh();

Second replacing the data source with the same data source. This
refreshes all the displayed cell except the selected one and when you
scroll up there are still empty cell that may or may not in the course of
time fill.

this.ratesDataGridViewTextBoxColumn.DataSource =
Data.clsCacheData.CacheHolder.DialingProperties;

Third attempt was doing a refresh on the data grid itself. Looks bad
(flicker) and does not update all the cells.

this.DataGridView1.Refresh().

Does anyone have another suggestion?

Regards,
John

Nov 13 '06 #8

This discussion thread is closed

Replies have been disabled for this discussion.