Solved

Binding records NOT updating properly, a bug maybe?

Posted on 2006-10-25
7
235 Views
Last Modified: 2010-04-23
Hi,

I am having trouble getting changes to a binding to update properly.  I am programmatically filling a column with an integer from 1 to the number of records.  Then I am applying a filter to the binding on the column I have filled with value > 0.  
When I do this I “lose” a record from the filtered list of the binding.  If I remove the filter, the record IS there.  The missing record is not always the same depending on the existing records in the binding.

The code I am using is …

        For locLoop = 1 To bndMain.Count
            bndMain.Item(locLoop - 1).Item("MyTempSort") = locLoop
        Next

        bndMain.EndEdit()

        bndMain.Filter = "MyTempSort > 0"


If I step through the binding and move to each record to make the change it works.  That code is …

        For locLoop = 1 To bndMain.Count
            bndMain.Position = locLoop - 1
            bndMain.Current.Item("MyTempSort") = locLoop
        Next

        bndMain.EndEdit()

        bndMain.Filter = "MyTempSort > 0"

However it takes 6 to 8 times longer to do this even if I hide controls, remove control bindings etc..

So does anybody know how to ensure the binding values get updated so the binding filter responds correctly.


Further information:
If I test and find out which record is missing for a given set of records, I can fill the binding using the fast .Item reference method, then move only to the record before the “missing” record, the “missing” record and the record after the “missing” record and then the filter works.  This test is repeatable.

There always only seems to be one record missing in the filter.  It is not the first, last or current record before I start the filling ie no pattern I can find.

Why Am I Doing This:
For the lateral thinkers out there who may have a totally different way of doing what I am trying to achieve, here is why I am doing this.
I am presenting the user with a DataGridView to which they can apply a complex sort order and complex filter.  Then they are allowed to edit records.  Of course if they change a value that means the record no longer matches the filter the record disappears which is disconcerting to the users even when explained.  Similarly if they change the record so that its position in the sort changes then moving forward or back get crazy.  They can move to the next record to find it is either the record they have just edited or two records away, not one.
My solution works well, apart from the glitch above, and that is to:
- preserve the users filter and sort values
- create a temporary hidden column in the underlying table, fill it as describe above.  
- filter on that temporary column > 0 and sort on it ascending
- let the user edit what they want
- remove the temporary column and restore their filter and sort.
0
Comment
Question by:NeilJohnGrant
  • 3
  • 3
7 Comments
 
LVL 21

Expert Comment

by:theGhost_k8
ID: 17809808
check if u have done enough with dataadapter while binding?? insert/update/delete command???
conform with following steps
http://www.informit.com/articles/article.asp?p=26956&rl=1
0
 
LVL 34

Expert Comment

by:Sancler
ID: 17810499
In my tests simply moving the line

            bndMain.EndEdit()

inside the loop like this

        For locLoop As Integer = 1 To bndMain.Count
            bndMain.Item(locLoop - 1).Item("MyTempSort") = locLoop
            bndMain.EndEdit()
        Next


        bndMain.Filter = "MyTempSort > 0"

seems to solve the problem.

I haven't properly worked out the "why"s and "wherefore"s.  There's a number of links in the chain - DataGridView to BindingSource, BindingSource to CurrencyManager, CurrencyManager to DataTable.  But what made me try the above approach first is that the changing of the BindingSource's .Position, as in your alternative approach, would force an .EndEdit down that chain at each step.  As that worked, I thought it worth bringing over that effect into your faster sub.  And, as I say, it seemed to work on my dummy test set up.

See if it works for you.

Roger
0
 

Author Comment

by:NeilJohnGrant
ID: 17811146
theGhost_k8,
I am pretty confident I have the bindings, data adapters, update commands all correct.  General editing and updating from the Datagrid View, combo boxes and text boxes with text properties bound to the main binding all work.  All my data connections and bindings are done at run time as this is much more flexible for what I am doing.  I see the problem as "why does traversing the binding work but referencing its entries doesn't completely work".  There's something about updating I think.  The database currently has about 10500 records and needs to grow.  The filterered list I have randomly tested return from 50 to 8000 records and they all end up "missing" just one record.  Strangely for some tests (not all), if I repeat the test immediately, ie add back the column do the fill, then filter; it all works.
But if I fire up the application from scratch it always fails the first time.  I don't know what to make of this.
But thanks for the thought.

Sacler,
I had tried this before and there was no improvement.  I tried it again to be sure and unfortunately it did not cure the problem.  I left one more EndEdit outside the loop for luck to no effect.

This situation is so weird as I can alter the filter and/or change the sort and when I finally clear the filter.  The "missing record" appears.
When I identify the particular "missing record" for a give filter, let's say number 2345, I can apply a filter of ...
bndMain.Filter = "MyTempSort = 2344 OR MyTempSort = 2345 OR MyTempSort = 2346" and you guessed it, I get two records, 2344 and 2346.
See also comments in the response to theGhost_k8 above for more information.

Neil
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 34

Accepted Solution

by:
Sancler earned 500 total points
ID: 17811449
OK, try this instead.

        For locLoop As Integer = 1 To bndMain.Count
            Dim drv As DataRowView = bndMain(locLoop - 1)
            Dim dr As DataRow = drv.Row
            dr("MyTempSort") = locLoop
        Next

        bndMain.Filter = "MyTempSort > 0"

The idea here is that (with the exception of identifying the row concerned) we "cut out the middleman".  That is, we use the BindingSource to locate the datatable row that we want to change but then we actually make the change in the row itself.

In the light of your response I went back and re-rested with my dummy set up.  I agree that my original test was not thorough enough.  Although it worked OK provided I had not already re-ordered any of the columns, it produced the same symptoms as you report once I had done so.

I've tested this one more thoroughly, and not so far been able to break it.

Roger
0
 

Author Comment

by:NeilJohnGrant
ID: 17817155
Roger,

Firstly isn't it great when someone else can reproduce the problem that is driving you crazy?  So thanks for the continued interest.

Better news still, you idea works and I have given up trying to break it.  It is not discernibly slower than my original method which is a bonus.

For your interest, I am always fiddling with code to get it faster or slicker and in this case found some results that may interest you.

I did response time tests on the same 10500 or so records and here are the results.

Your suggested code below was 7-8 seconds
        For locLoop As Integer = 1 To bndMain.Count
            Dim drv As DataRowView = bndMain(locLoop - 1)
            Dim dr As DataRow = drv.Row
            dr("MyTempSort") = locLoop
        Next


Slightly shortened version below was also 7-8 seconds
        Dim drv As DataRowView
        For locLoop As Integer = 1 To bndMain.Count
            drv = bndMain(locLoop - 1)              
            drv.Row("MyTempSort") = locLoop
        Next


Slickest version below was surprisingly 10-11 seconds (I can’t explain this, my experience is that normally code with the least steps runs quicker or at least at the same speed as code with more steps)
        For locLoop As Integer = 1 To bndMain.Count
            bndMain(locLoop - 1).Row("MyTempSort") = locLoop
        Next

Of great intrigue to me is the last version which DOES work without any temporary objects.  Yet my original version below does not.
        bndMain.Item(locLoop - 1).Item("MyTempSort") = locLoop

After all the testing I even swapped between these last two a few times, so as to confirm the problem was reproducible as was the cure.  They both were reproducible.


So how’s that for crazy.  There IS a problem if you address the “field” via
      Binding.Item( ).Item( )

There is NO PROBLEM if you address the “field” via
      Binding( ).Row( )

That sure is one to remember.


Thanks again, the points are all yours.

Neil
0
 

Author Comment

by:NeilJohnGrant
ID: 17817201
Roger,

See previous comment.
I couldn't remember if I could add comments after I accepted your answer.

By the way Cymru rocks (I hope I got that right).

My wife and I have visited from Australia three times each for serveral weeks at a time and we love it.  Especially the West and North West.


Neil
0
 
LVL 34

Expert Comment

by:Sancler
ID: 17817795
Neil

Thanks for the points.  Glad it's sorted.

I think the relative slowness of

        For locLoop As Integer = 1 To bndMain.Count
            bndMain(locLoop - 1).Row("MyTempSort") = locLoop
        Next

compared with the other two, despite it being shorter, is probably because the .Item property of the BindingSource, which is what is explicitly referenced by the bndMain(locLoop - 1) part, is of datatype Object, not DataRowView.  So there has to be an internal cast.  That includes some "thinking time" for working out precisely what the cast should be.  By declaring and making a specific refrence to a DataRowView that "thinking time" is eliminated (or at least reduced).

The difference between

     Binding.Item( ).Item( )

and

     Binding( ).Row( )

again arises, I think, because of the intervention of the DataRowView in the chain.  I don't claim to understand it completely - I've never found any practical need to dig deep enough to work it all out - but that general thought arises from this

    https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=92087

And, yes, Cymru is right.  Glad you liked it.

Roger
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
I think the Typed DataTable and Typed DataSet are very good options when working with data, but I don't like auto-generated code. First, I create an Abstract Class for my DataTables Common Code.  This class Inherits from DataTable. Also, it can …
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now