Advice requested: Windows Forms Binding:
I have been trying to get the following Windows Forms binding working, without success.
The following Code, successfully populates the GridControl, and both combo boxes with data. The two comboBoxes represent: SalesOrderType, and SalesOrderStatus. There six SalesOrderTypes, and five SalesOrderStatus values.
The GridControl contains all of the Sales Orders.
My Problem:
I want the comboBoxes to display the same value that is in the DataGrid, each time a user clicks on a different DataGrid Row. I want the comboboxes synchronized with the dataGrid control.
I am using:
VS2005 Beta 2 C#.
1 DataGridView
2 ComboBoxes
| | SqlConnection con =new SqlConnection("data source = usaws69; initial catalog=MiniCim6;integrated security = sspi"); SqlDataAdapter daOrders =new SqlDataAdapter("SELECT * FROM SNMaster", con); SqlDataAdapter daOrderType =new SqlDataAdapter("SELECT * FROM SNTY", con); SqlDataAdapter daOrderStatus =new SqlDataAdapter("SELECT * FROM SNST", con);ds =new DataSet("Orders"); daOrders.Fill(ds, "SNMaster"); daOrderType.Fill(ds, "SNTY"); daOrderStatus.Fill(ds, "SNST"); ds.Relations.Add("OrderTypeRelation", ds.Tables["SNTY"].Columns["typID"], ds.Tables["SNMaster"].Columns["typID"]); ds.Relations.Add("OrderStatusRelation", ds.Tables["SNST"].Columns["staID"], ds.Tables["SNMaster"].Columns["staID"]); comboBox1.DataSource = ds.Tables["SNTY"]; comboBox1.DisplayMember = "rType"; comboBox1.ValueMember = "typID"; comboBox2.DataSource = ds.Tables["SNST"]; comboBox2.DisplayMember = "stats"; comboBox2.ValueMember = "staID"; dataGridView1.DataSource = ds.Tables["SNMaster"];
|
You'll need to bind the ComboBox SelectedValue to the appropriate key in the SNMaster table:
| | comboBox1.DataBindings.Add("SelectedValue", ds.Tables["SNMaster"], "typID", true); comboBox2.DataBindings.Add("SelectedValue", ds.Tables["SNMaster"], "staID", true); |
This will force the SelectedValue of the ComboBox (the currently selected item's ValueMember value) to match the value of the given column in the given table. For example, this will cause comboBox1's selected item to be the item that has a "staID" (this is comboBox1's ValueMember) equal to the "staID" of the currently selected item in the ds.Tables["SNMaster"] table.
Joe
Okay, that makes the comboBoxes work, thank you.
Now that you solved that problem...is it possible to update the datagrid with the values that the user may select/change in the comboxBoxes by using binding, or will I have to resort to manually updating the gridcontrols datasource?
I realize that this is an unusual request, but then I am trying to duplicate the behavior of an application written years ago, yuck.
This old application basically uses a gridcontrol as a naviagtor, so most of the data is duplicated from the gridControl to controls located elsewhere on the form in ComboBoxes, TextEditors, DateEditors, etc.
Here is a typical session using the old application:
== Edit Session Begin
User does a search and gets 15 Orders in gridControl.
User then selects a dataGridRow (an Order), he wishes to change, and all the data for that row is then placed in various Controls located elsewhere on the form. (I have the app working to this point, thanks to your help.).
The user is then allowed to change one or all of the controls.
The user then must press F6 "Save", and changes are written to database, and the gridControl is also updated with changes.
== Edit session completed
So now I must update the DataBase, and DataGrid with the changes from these various controls, (there are 17 of them).
Can you offer a suggestion on how to do this?
Thanks
Russell Mangel
Las Vegas, NV
"I just hate duplicating old (Unstructured) software."
The Binding code I sent in my previous post sets up two-way binding and this will cause the data source to be updated however, as you've discovered, it will not cause the DataGridView to update. There are a couple of reasons for this: first, the Binding is only sending its changes to the data source when it loses focus. The second issue is that the data source (DataRowView) has a row based commit model so you'll need to make a change to force it to commit whenever the bound value changes.
To do this, change the Bindings to update on property change:
| | Binding b = new Binding("SelectedValue", ds.Tables["SNMaster"], "typID", true, DataSourceUpdateMode.OnPropertyChanged); comboBox1.DataBindings.Add(b); b.BindingComplete += new BindingCompleteEventHandler(AutoCommmitBindingHandler); b = new Binding("SelectedValue", ds.Tables["SNMaster"], "staID", true, DataSourceUpdateMode.OnPropertyChanged); comboBox2.DataBindings.Add(b); b.BindingComplete += new BindingCompleteEventHandler(AutoCommmitBindingHandler); |
Then add a handler that forces the Binding to update the data source when the control value changes:
| | private bool _inCommit = false; void AutoCommmitBindingHandler(object sender, BindingCompleteEventArgs e) { if (!_inCommit && (e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate) && (e.BindingCompleteState == BindingCompleteState.Success)) { try { _inCommit = true; e.Binding.BindingManagerBase.EndCurrentEdit(); } finally { _inCommit = false; } } } |
Joe
Joe,
Thanks for taking the time to help me with my binding problem, I am now testing the code that I produced from your samples, everything seems to be working good.
I also was quite amazed at getting responses to my messages on Saturday, and Sunday... Thanks.
Russell Mangel
Las Vegas, NV
I am struggling with this very problem on a current project.
Would you have a Northwind VB.NET 2005 sample of how this could be configured?
1. Use Datagrid as a navigator (in additon to the Binding Navigator)
2. Keep Detail controls and Datagrid controls synchronized when the Detail controls are updated.
3. Provide default values (separate from DataSet defaults) for controls when AddNew is called via Binding Navigator or other Button Click code
Yes - I'll generate a VB.NET sample. Could you provide some more information on what you're looking for in item 2? Are you referring to master/details (e.g. Customers/Orders) or are you referring to changing column data in details controls (e.g. Customers grid and change Customer.Name using a TextBox)?
Joe Stegman
The Windows Forms Team
Microsoft Corp.
This posting is provided "AS IS" with no warranties, and confers no rights.
Thanks for your efforts.
Regarding #2
Customer Navigation Grid (show only selected fields that would be useful for selection) and Customer Details. It would be great to expand and detail how another related Details section with a one-to-one mapping to Customers could be added.
I sent you a sample. The majority is designer generated with some custom code for the AddNew handling:
| | Dim m_rand As New System.Random Private Sub CustomersBindingSource_AddingNew(ByVal sender As System.Object, ByVal e As System.ComponentModel.AddingNewEventArgs) Handles CustomersBindingSource.AddingNew Dim bSource As BindingSource = CType(sender, BindingSource) Dim view As System.Data.DataView = CType(bSource.List, System.Data.DataView) If (Not view Is Nothing) Then Dim drv As System.Data.DataRowView = CType(view.AddNew(), System.Data.DataRowView) If (Not drv Is Nothing) Then Dim row As NorthwindDataSet.CustomersRow = CType(drv.Row, NorthwindDataSet.CustomersRow) ' Provide default values - in this case, just the CustomerID row.CustomerID = m_rand.Next(99999).ToString() row.CompanyName = "<Enter Company Name>" ' Set net object e.NewObject = drv ' Set position bSource.MoveLast() End If End If End Sub |
Joe Stegman
The Windows Forms Team
Microsoft Corp.
This posting is provided "AS IS" with no warranties, and confers no rights.
The above code will cause two rows to be added to the bindingsource. This is caused by the following line:
Dim drv As System.Data.DataRowView = CType(view.AddNew(), System.Data.DataRowView)
Is there another way?