-
Nov 1st, 2014, 01:20 PM
#1
Thread Starter
Hyperactive Member
[RESOLVED] BindingSource/BindingNavigator mysteries?
I have a form that has a BindingNavigator control that is bound to a BindingSource component (bsTypes). In the form Designer, the BindingNavigator has an AddNewItem property and a DeleteItem property. These define the ToolStripItems on the BindingNavigator that raise the "AddNew" action and the "Delete" action.
I have created the Insert, Update, and Delete commands for the DataAdapter that communicates with my database file (a Microsoft Access database) and the MissingSchemaAction property of the DataAdapter is set to MissingSchemaAction.AddWithKey.
Can someone please answer the following 3 questions?
1) It appears that these ToolStripItems raise their respective events implicitly (I haven't added any code to either add or delete a row in the BindingSource). How does this mechanism work?
2) When a new row is added to the BindingSource the primary key value in the BindingSource's current item is populated. It appears that this is also done implicitly (probably because of the MissingSchemaAction property mentioned previously). Using Debug statements and the Immediate window I monitor the BindingSource's events that are raised when I click on the BindingNavigator's BindingNavigatorAddNewItem button. At what point in the cascade of these events is the primary key value populated in the current item of the BindingSource? The event cascade sequence is:
bsTypes_AddingNew (Position = 0)
bsTypes_ListChanged (ListChangedType = ItemAdded, Old index = -1, New index = 10, PropertyDescriptor = ItemAdded)
bsTypes_PositionChanged (Position = 10, RowState = Detached) When the AddingNew event fires, the primary key value has not been populated, but it is available when the PositionChanged event fires. It appears to be populated via the ListChanged event.
3) Is it possible to get the name of the BindingSource property that has changed when the BindingSource's CurrentItemChanged event is raised? I can cast the BindingSource's current item's row to a DataRow object and then loop through the row's ItemArray to see the values of each of the array items, but I would like to also be able to get the name of the bound item that has changed.
I have my form working but would like to better understand these operations and would appreciate some help with these questions.
Last edited by Mark@SF; Nov 1st, 2014 at 06:14 PM.
-
Nov 1st, 2014, 07:07 PM
#2
Re: BindingSource/BindingNavigator mysteries?
Originally Posted by Mark@SF
I have a form that has a BindingNavigator control that is bound to a BindingSource component (bsTypes).
Hallelujah! Finally someone who knows the difference between a control and a component.
Originally Posted by Mark@SF
1) It appears that these ToolStripItems raise their respective events implicitly (I haven't added any code to either add or delete a row in the BindingSource). How does this mechanism work?
You'll note that the BindingNavigator has a BindingSource property. When you set the AddNewItem property of the BindingNavigator, that item is assign to a variable whose Click event has a registered event handler. When that event is raised, the BindingNavigator tests its BindingSource property and, if it's not Nothing, calls the AddNew method of that BindingSource.
Originally Posted by Mark@SF
2) When a new row is added to the BindingSource the primary key value in the BindingSource's current item is populated. It appears that this is also done implicitly (probably because of the MissingSchemaAction property mentioned previously). Using Debug statements and the Immediate window I monitor the BindingSource's events that are raised when I click on the BindingNavigator's BindingNavigatorAddNewItem button. At what point in the cascade of these events is the primary key value populated in the current item of the BindingSource? The event cascade sequence is:
bsTypes_AddingNew (Position = 0)
bsTypes_ListChanged (ListChangedType = ItemAdded, Old index = -1, New index = 10, PropertyDescriptor = ItemAdded)
bsTypes_PositionChanged (Position = 10, RowState = Detached) When the AddingNew event fires, the primary key value has not been populated, but it is available when the PositionChanged event fires. It appears to be populated via the ListChanged event.
That's actually nothing to do with the BindingSource but rather the DataTable. Because you set the MissingSchemaAction property of your data adapter to AddWithKey, when you called Fill, all the primary key information was retrieved from the database table and propagated to the Datatable that you populated. In your Access database, you must have the primary key column defined as an AutoNumber. That means that the AutoIncrement property of the corresponding DataColumn will be set to True and the AutoIncrementSeed and AutoIncrementStep properties will also be set.
When the AddNew method of the BindingSource is called, the DataTable creates a new DataRow with a RowState of Detached. When the EndEdit method of the BindingSource is called, that DataRow is added to the Rows collection of the DataTable and its RowState is changed to Added. It's at that point that the DataTable generates the PK value based on the AutoIncrement properties.
Originally Posted by Mark@SF
3) Is it possible to get the name of the BindingSource property that has changed when the BindingSource's CurrentItemChanged event is raised? I can cast the BindingSource's current item's row to a DataRow object and then loop through the row's ItemArray to see the values of each of the array items, but I would like to also be able to get the name of the bound item that has changed.
You can't actually cast the Current property of the BindingSource as type DataRow because it's not a DataRow. It's a DataRowView from the DataTable's DefaultView. That DataRowView object has a Row property that exposes the DataRow that it views.
The BindingSource and even the DataTable or DataRow don't know what column has changed at that point. If you want that fine a level of control then you'd have to track it yourself, as it appears that you are.
-
Nov 1st, 2014, 08:15 PM
#3
Thread Starter
Hyperactive Member
Re: BindingSource/BindingNavigator mysteries?
jmcilhinney -
Thank you for your answers to my questions. As you have done for me on a couple of previous occasions, you have once again greatly expanded my understanding of VB.Net.
You can't actually cast the Current property of the BindingSource as type DataRow because it's not a DataRow. It's a DataRowView from the DataTable's DefaultView. That DataRowView object has a Row property that exposes the DataRow that it views.
I misspoke regarding the casting of the Current property (as usual, you are right). For the record, here's how I'm looping through the items in the current row of the BindingSource:
Code:
row = DirectCast(bsTypes.Current, DataRowView).Row
For i As Integer = 0 To UBound(row.ItemArray)
Debug.WriteLine(vbTab & Chr(149) & " Item #{0}: {1}", i, row.ItemArray(i))
Next
Somewhere in my Internet searching I came across an example of how to see the name of the BindingSource property that has changed when the CurrentItemChanged event is raised. For example, if I've bound the "RecID" field in the Microsoft Access table then I'd like to see the bound field's name (as well as it's current value) when the CurrentItemChanged event is raised. I've dug through all my old notes, but unfortunately I cannot find it. If I manage to stumble back upon the example I'll be sure to post back to this thread.
One last question...you have spoken about how the BindingSource keeps track of the current and the previous "versions" of each row of data. I know how to view the Current property of the BindingSource. How can I view the previous "version" of the row's data?
In the meantime, thank you again for your very helpful, thorough, and concise response to this and all my previous questions!
All the best to you...
-
Nov 1st, 2014, 09:20 PM
#4
Re: BindingSource/BindingNavigator mysteries?
It's important to understand that the BindingSource is really just a way to aggregate all the binding-related functionality from other places into one object. It really just acts as a pass-through for properties, methods and events defined elsewhere.
Originally Posted by Mark@SF
Somewhere in my Internet searching I came across an example of how to see the name of the BindingSource property that has changed when the CurrentItemChanged event is raised. For example, if I've bound the "RecID" field in the Microsoft Access table then I'd like to see the bound field's name (as well as it's current value) when the CurrentItemChanged event is raised. I've dug through all my old notes, but unfortunately I cannot find it. If I manage to stumble back upon the example I'll be sure to post back to this thread.
I've never had to do that myself so I've never looked but I just looked now and I believe that I've determined how it would be done, at least when the data source is a DataTable. In the case where you edit data, the CurrentItemChanged event of the BindingSource is raised in response to the ListChanged event of the DataView expised by the DefaultView property of the DataTable. That ListChanged event provides e.ListChangedType and e.PropertyDescriptor properties to tell you what type of changed prompted the event and the column in which the change occurred, if indeed it was a column in which the change occurred. Handle that event rather than CurrentItemChanged and you should be able to get what you want.
The BindingSource has a ListChanged event too, which may well be raised in direct response to the same event of the DataView, so maybe that's the best option for handling to get the information you want.
Originally Posted by Mark@SF
One last question...you have spoken about how the BindingSource keeps track of the current and the previous "versions" of each row of data. I know how to view the Current property of the BindingSource. How can I view the previous "version" of the row's data?
Again, this doesn't really have anything to do with the BindingSource. It's the DataRow that stores the two versions of the data. Normally, you simply index a DataRow to get the data in the field. You can also specify a DataRowVersion value to determine which version of the data the field value is drawn from. Specifying a version of Default is equivalent to not specifying a version at all.
-
Nov 2nd, 2014, 07:40 AM
#5
Thread Starter
Hyperactive Member
Re: BindingSource/BindingNavigator mysteries?
Thanks again for your help. I'm going to mark this thread "resolved".
-
Nov 2nd, 2014, 12:01 PM
#6
Thread Starter
Hyperactive Member
Re: BindingSource/BindingNavigator mysteries?
OK, so here's how to show the name of the item that has changed, and jmcilhinney is correct that it comes via the ListChanged event of the BindingSource. Note the "e.PropertyDescriptor.Name" in the code snippet below:
Code:
Debug.WriteLine(vbCrLf & strMethodName & " has fired (" & Date.Now.ToString("dd-MMM-yyyy hh\:mm\:ss\:fff tt") & "): " & vbCrLf & _
vbTab & Chr(149) & " List count = " & bsTypes.Count & vbCrLf & _
vbTab & Chr(149) & " ListChangedType = " & e.ListChangedType.ToString & vbCrLf & _
vbTab & Chr(149) & " Old index = " & e.OldIndex.ToString & ", New index = " & e.NewIndex.ToString)
If Not e.PropertyDescriptor Is Nothing Then
Debug.WriteLine(vbTab & Chr(149) & " Name = " & e.PropertyDescriptor.Name)
End If
Here is an example of the Immediate window's results:
Code:
bsTypes_ListChanged has fired (02-Nov-2014 08:49:14:243 AM):
• List count = 2
• ListChangedType = ItemChanged
• Old index = 0, New index = 0
• Name = EditorName
The e.PropertyDescriptor.Name value is "EditorName" which is the field name from the underlying Microsoft Access database table.
Thanks again to jmcilhinney for all his help answering my questions.
Last edited by Mark@SF; Nov 2nd, 2014 at 12:04 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|