Link to home
Start Free TrialLog in
Avatar of NeilJohnGrant
NeilJohnGrant

asked on

Binding records NOT updating properly, a bug maybe?

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.
Avatar of theGhost_k8
theGhost_k8
Flag of India image

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
Avatar of Sancler
Sancler

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
Avatar of NeilJohnGrant

ASKER

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
ASKER CERTIFIED SOLUTION
Avatar of Sancler
Sancler

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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
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