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("MyTe mpSort") = 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.
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("MyTe
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.
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
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
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
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
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
ASKER
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
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
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
conform with following steps
http://www.informit.com/articles/article.asp?p=26956&rl=1