Click here to Skip to main content
15,881,139 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have a datagridview that will typically have 100 rows of data (15 columns - small text < 10 characters, 3 digit integers); I am updating this from an Event - that every second or 2 sends updates which I use to update the DataGridview . I am using a binding source bound to a List<myowntype> .

I am getting the Scroll position before update and setting it after update.
Even though I do this - the scroll bar remains in position (as it should), but my DataGridview Rows are shifted to the beginning after a few updates(which it should not). The scroll position might be at the very bottom, yet my DataGridview is showing from the beginning row.

I also have an issue with being able to use the control with so many updates coming in - seems being so small a data set this should not be an issue, but it is - I would like a more seamless user experience.

1: How to ensure the DataGridView Rows stay in Sync with the Scroll position ?
2: How can I increase the User Experience performance and still update the data ?

CODE:



C#
void UpdateBayGridview(System.Collections.Generic.List<BAY> bay)
{
    int vscroll = dgBinContent.FirstDisplayedScrollingRowIndex;
    int hscroll = dgBinContent.FirstDisplayedScrollingColumnIndex;

    this.BayTable.BeginLoadData();

    DataTable dtupdates = bay.ToDataTable<BAY>();
    DataColumn[] pkUPdateColumn = { dtupdates.Columns["ID"] };
    dtupdates.PrimaryKey = pkUPdateColumn;

    DataColumn[] pkColumn = { this.BayTable.Columns["ID"] };
    this.BayTable.PrimaryKey = pkColumn;
    this.BayTable.Merge(dtupdates);
    this.BayTable.EndLoadData();
    schemachange = false;

    bsBays.ResetBindings(schemachange);

    // Set the scroll positions
    if (vscroll < 0)
        vscroll = 0;

    if (hscroll < 0)
        hscroll = 0;

    dgBinContent.FirstDisplayedScrollingRowIndex = vscroll;
    dgBinContent.FirstDisplayedScrollingColumnIndex = hscroll;

}
Posted
Updated 14-Aug-15 10:28am
v2
Comments
Patrice T 14-Aug-15 17:06pm    
Are you resetting the timer before or after the update ?
stixoffire 14-Aug-15 21:00pm    
The event comes from a WCF service pushing the data. So I do not have any timers. The data event occurs every 1 to seconds and can be faster, I need to be able to manage the DataGridView updates and manage the User Experience. Just not sure how to do it , with out interfering with the user being able to scroll - since I cannot display all rows at once , maybe I should just page it.

1 solution

Since you don't own the timer, you must guard you code against being run again before finishing actual run.

Declare a global variable that persist between calls to the routine.
then change your code this way.
C#
void UpdateBayGridview(System.Collections.Generic.List<bay> bay)
{
    if (updating) return;
    updating = 1;
    int vscroll = dgBinContent.FirstDisplayedScrollingRowIndex;
    int hscroll = dgBinContent.FirstDisplayedScrollingColumnIndex;
 
    this.BayTable.BeginLoadData();
 
    DataTable dtupdates = bay.ToDataTable<bay>();
    DataColumn[] pkUPdateColumn = { dtupdates.Columns["ID"] };
    dtupdates.PrimaryKey = pkUPdateColumn;
 
    DataColumn[] pkColumn = { this.BayTable.Columns["ID"] };
    this.BayTable.PrimaryKey = pkColumn;
    this.BayTable.Merge(dtupdates);
    this.BayTable.EndLoadData();
    schemachange = false;
 
    bsBays.ResetBindings(schemachange);
 
    // Set the scroll positions
    if (vscroll < 0)
        vscroll = 0;
 
    if (hscroll < 0)
        hscroll = 0;
 
    dgBinContent.FirstDisplayedScrollingRowIndex = vscroll;
    dgBinContent.FirstDisplayedScrollingColumnIndex = hscroll;
    updating = 0;
 
}

This can solve the problem of moving cursor while updating.

You also have potential conflict if you move the cursor while the update routine is active.
 
Share this answer
 
v4
Comments
stixoffire 17-Aug-15 9:14am    
There is no timer - it is driven by an event. The event fires and I handle the event. The problem is the datagridview does not maintain position even though I maintain the vscroll and hscroll positions the grid resets back to showing row 1 through visble row x. Instead it should show only the rows in that are visible and not change that unless the user scrolls. Also the user needs to be able to interact with the grid without being locked out. How can I accomplish user interactivity and frequent grid updates?
Patrice T 17-Aug-15 14:41pm    
Events are like timers and you get the same problems.
You never know if previous update is finished when new event is triggered. It can lead to run the update before the end of previous one, this lead to conflicts.
If GUI try to move the cursor while update is running, you get conflicts.
You have to change your code to prevent conflicts.
Have look at MutEx (mutual exclusion), it is a technic to prevent conflicts.
stixoffire 17-Aug-15 17:11pm    
Ok I am getting the first part updating data - may not have finished and so it runs the code again (or tries to). To handle this I think maybe I will do this: Run a background worker , if it is busy no need to continue just skip and wait for next push of data . I know in the run worker complete event I can then update the bindingsource.resetbinding(false) and set my values for the scroll position on datagridview.

As for the users ability to scroll the data while it is being updated - how in the world is this accomplished to make it appear seemless (do people cache this and go virtual mode?), my laptop has 8 cores in it an 24GB - the code I have going is consuming 25% of the CPU cycle time. - I only have 30 rows with minimum data.
Patrice T 17-Aug-15 19:46pm    
There is something wrong in your routine, it consume too much CPU.
You need to run a profiler on the routine to see where it spend time.
I am not specialist in C#, you describe something too long for display of 30 rows.

-You can certainly fix the cursor problem.
-I think you should ask another question about how to speed up the routine.
Advice comment what your code is doing, give hints about the size of the tables/databases involved in the routine.
There is certainly another way.
stixoffire 1-Sep-15 15:34pm    
I had a race condition with WCF. Seems checking state ICommunication obj is not a good thing , yet the examples show this.
I am able to update the UI now I use a threaded binding list, which has it's own SynchronizationContext with send or post back methods ..it works pretty nicely and I was able to transform it into a RollingQueue. My updates take general about 14ms for merging the data initially it was 0 but I had to add some logical checks and handle those so the time went up.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900