I have a form that saves to an order data table. A few of the fields in the form are linked to a table that contains customer names and address details. The shippername field in my order data table is a combobox - you select the name and the corresponding address information for that name is displayed in textboxes that belong to the address, city and phone number fields for my order datatable. For that, I am using the databinding property of the combobox control for that field, and using the Text property for the textboxes (binding to the source table, which I call shipperdata.) When I run the form, it displays the information I want.
The problem: when I save the form, the names of the shippers are saved fine. However, the other fields related to the shipper name are not. I realized that the binding property would not let me bind the contents of the textbox to my order datatable.
I went into the designer and thought I'd try an experiment, thinking that if the combobox can bind to a source and bind the text to the order datatable, I should be able to do that with a textbox. Right? Apparently not so much. Here's what I tried:
'Shipper1address1TextBox
'
Me.Shipper1address1TextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.ShippersBindingSource, "SHIPPERADDRESS1", True))
Me.Shipper1address1TextBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", Me.OrdersBindingSource, "shipper1address1", True))
Me.Shipper1address1TextBox.Location = New System.Drawing.Point(188, 429)
Me.Shipper1address1TextBox.Name = "Shipper1address1TextBox"
Me.Shipper1address1TextBox.Size = New System.Drawing.Size(200, 20)
Me.Shipper1address1TextBox.TabIndex = 32
I got an error saying that I couldn't bind 2 properties.
The funny part: the form is actually 'details' so I decided to drag a datagridview next to what I already had set up to see how it looked. In detail view, you'd think the data was being saved correctly to the orders data table. But, when I looked at the table in gridview, the values for the address and phone, etc were not written there. Then i reminded myself that it's only bound to the shipper data table.
My question: how can I save the corresponding address and phone information to the order table while still binding to the source so it displays? If I make the binding property to the orders data table, that's great...except now it doesn't display address information. Is there a method to accomplish this with a textbox? I'm also guessing at this point that messing with the designer is probably not a great idea. Maybe an alternative? It just seems odd that the value contained in a textbox from a data table isn't saved.
Thanks for having a look.
You can only add one databinding to each text box.
You are adding two in your code.......
Me.Shipper1address1TextBox.DataBindings.Add
ArronG.
Related
I have set a combobox to be visible in column1 of my Datagridview. Now I'm trying to fill same row of Datagridview where Combobox appears, from Combobox_Key_Down event. This is my code for showing combobox:
Private Sub My_DGV_CellMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles MY_DGV.CellMouseClick
If e.RowIndex >= 0 Then
With My_DGV
If .Columns(.Rows(e.RowIndex).Cells(e.ColumnIndex).ColumnIndex).Name = "Column1" Then
.CurrentCell = .Rows(.CurrentRow.Index).Cells(.CurrentCell.ColumnIndex)
Show_Combobox(.CurrentRow.Index, .CurrentCell.ColumnIndex) 'function that shows my Combobox in that cells
Combo.Visible = True
Else
Combo.Visible = False
End If
End With
End If
End Sub
I tried many things, but I don't know how to determine in which row Combobox appears and how give that Datagridview row my Combobox values. Someone please give me a clue of what should I do. Thanks in advance !
The first problem with your approach is that the DGV can have only one DataSource: it can either show the m:m association table or the related elements. If you include columns from one of the tables into the query for display, the table becomes non updatable and users can be confused why they cannot edit something they can see. It seems of little value they way you describe it, since they cannot see the detail data until after they make a selection.
Next, it requires another datatable to supply the details for CboColB. Since you want the DGV bound to a DataTable easy updates, you end up having to poke data into cells over and over.
Finally, consider what the user is confronted with. Using a Country table (200+ countries/locales with ISO code and name) and a list of flag colors, a table for CountryFlagColors will have hundreds and hundreds of rows (at just 2 colors per flag).
A better display might be to filter the m:m table (flagcolor) to a selected item so the user is only confronted with the data subset they are currently interested in:
The datatable used in the DGV is built from the m:m table:
The Country column is hidden.
When they choose from the CBO at the top, that is used as a RowFilter to limit the rows to the relevant ones.
In the RowValidating event, when the country cell is DBNull, copy the SelectedValue from the country combo to the DGV cell to fill in the blank
I would probably really make the user click a button and manually add a row so I could seed the country value then rather than depend on events.
It uses a DataAdapter and after adding X number of flag definitions, da.Update(dtFlagColors) applies/saves all the changes.
Ok, so that provides the core functionality to assign N color selections to define the flag colors for a country. The missing element is the 'details' for the Color item.
I added a meaningless int and string item to the Color table, one way to display these would be to create an alias in the SQL with the important details. Displaying them as discrete elements can either make the query non updatable or invites the user to edit things they cannot edit here. My silly SQL:
"SELECT Id, Name, Concat(Name , ' (' , intItem , ' ' , stritem,')') As Info from FColor"
Then use 'Info' as the display member on the CBO column in the dgv:
dc = DirectCast(dgvCF.Columns(0), DataGridViewComboBoxColumn)
dc.DataSource = dtFlagColors
dc.DisplayMember = "info"
dc.ValueMember = "id"
dgvCF.DataSource = dtSample
The combo column has its own datasource of course, in order to display one thing and use another for as the Value to give back to you. Result (the values are silly):
It is not exactly what you want, but comes close and is much simpler. It also requires almost no code for driving the associative entity. Another alternative would be to use a DGV as the second picker so you can show the extended data and manually add rows to a DGV:
If you set the dropdown style to Nothing, it looks like a text column.
I have populated a dataagridview using an SqlDataAdapter dataset and manually assigned fields from the dataset to manually created columns in the datagridview. I'm experiencing something odd, in that for DatagridView.Columns(1), which I assigned as DatagridView.Columns(1).DataPropertyName = "Description", when the grid populates the value from DatagridView.Columns(2).DataPropertyName = "Vers", as so:
Even more perplexing is that datagridview has a SelectionChanged event which populates a textbox with Me.SelectedDescription.Text = DatagridView.SelectedRows(0).Cells(1).Value.ToString, which correctly displays the description:
I'm perplexed as to why the Versvalue is showing in the Description column in the datagridview therefore? This looks like a bug to me or do I need some form of workaround?
Sorry, solved:
I had a hidden column between columns 0 and 1, viewable in the Edit Columns dialog. I needed to move this down to the correct location in the list.
I have a database that I am using in a VB 2010 project. What I did was removed a textbox for a database field that I dragged onto the form and replaced it with a combobox. The field name was orderstatus.
The problem is this: since I removed the textbox field from the form, I can't seem to bind the combobox value to the field in the active record. In other words, orderstatus textbox doesn't exist anymore. I want to let the user pick a status from the combobox and store that value to orderstatus so that it's saved to the current record my database.
I want to do something like this:
Private Sub Button16_Click_1(sender As System.Object, e As System.EventArgs) Handles Button16.Click
orderstatus = ComboBox13.SelectedValue
Me.OrdersDataSet.orders(0).orderstatus = orderstatus
Me.Validate()
Me.OrdersBindingSource.EndEdit()
Me.TableAdapterManager12.UpdateAll(Me.OrdersDataSet)
End Sub
but it doesn't like my second line where I try to assign the value to the field, saying there is no row 0. All I want to do is put the selected value of the combobox into the orderstatus field of the record being created (or updated).
I've also tried using:
Me.OrdersDataSet.orders.orderstatusColumn = orderstatus
and I get a message saying that the property of the column is ReadOnly. I'm not sure how that's possible because I configured the dataset to update, etc.
I should probably mention that I'm not using a datagridview but a details view, if that makes a difference. I've seen some talk about how to do this using datagridview and don't know if that would work in my case.
What am I doing wrong? What should I use to update just the column I want in the current row?
Ugh, turns out I had forgot to set the databinding properties of the field in question to save directly to the binding source and also select the selecteditem to bind. It was right there and I didn't realize. Ya live and learn. :)
I have a simple VB.NET 2008 app that helps users to edit fields in the database. Simple enough as a first "real" project in .NET, right?
For one table, I am currently using a DataGridView so it can be edited straight up. However, instead of offering the user the entire table, I'd like to group the data by the 'CompanyNumber' column and use a navigator to page through. In other words, I'd like the DataGridView to show me all the lines related to one company, then click the "next" arrow to show the next company, etc.
(I know I could do this with Xceed DataGrid, but I'm using Windows Forms not WPF, and I'd really prefer to do this with "pure" ADO.NET for this project.)
Update 2009-09-28:
So I have created a ComboBox filled from the same BindingSource, and configured its SelectedIndexChanged to change the Filter value on the DataGridView.
But still, filling the ComboBox--which should be easy!--continues to be a problem. I can either:
(a) fill it from the BindingSource, in which case I see multiples of each 'CompanyNumber' and I can't figure out a way to show only distinct values, or
(b) create another TableAdapter in the data source which is just a "Select DISTINCT CompanyNumber..." query, which mostly works, except that that first value of the list changes when I change the selection (e.g. if the ComboBox shows "100, 101, 102, 103" and I pick "102", then the list will show as "102, 101, 102, 103").
Any recommendations?
(Also, bonus if you can suggest how to make the BindingNavigator's arrows page through the 'CompanyNumber' filters instead of the items in the DataGridView... which is what I'd really like to see.)
What you could do is just force the DataGridView to sort CompanyName, this way all rows with the same company name are next to each other and the user can navigate the data grids with the paging that comes with it.
Alternatly, you could follow through with your combobox/DropDownList idea, which would be best. From what I understand when you select an item in the combobox everything in it changes?
Another way is to create two separate buttons, "Previous" "Next", that when clicked, will change the DataGridView's binding source to only show a certain company. You would need to store an array of company names, then store what the current DataGridView's binding source is displaying.
I ended up figuring it out myself, and the solution is clean and simple. Here are the basic steps:
create a DataView off of the table out of the DataSet
use the DataView.ToTable() method to create a new table filtered to only distinct values from the needed column ('CompanyNumber')
create a BindingSource which uses the new DataTable as its DataSource
bind the ComboBox to the new BindingSource
bind the BindingNavigator to the new BindingSource
Because the ComboBox and the BindingNavigator use the same BindingSource, they will update each other with the changes automagically.
Here's the rough code:
Private Sub CoNumsComboxBox_LoadData()
Dim dvCoNums As DataView, dtCoNums As DataTable
dvCoNums = New DataView(Me.ODBCDataSet.Tables("CompanyFundProfile"))
dvCoNums.Sort = "CompanyNumber ASC, FundNumber ASC"
dtCoNums = dvCoNums.ToTable("CompanyFundProfile", True, "CompanyNumber")
CoNums_BindingSource.DataSource = dtCoNums
CoNumsComboBox.DataSource = CoNums_BindingSource
CoNumsComboBox.DisplayMember = "CompanyNumber"
CoNumsComboBox.ValueMember = "CompanyNumber"
'attach handler which changes DataGridView1's filter when this changes
AddHandler ToolStripComboBox1.SelectedIndexChanged, AddressOf CoNumsComboBox_SelectedIndexChanged
CompanyFundProfile_BindingNavigator.BindingSource = CoNums_BindingSource
End Sub
I'm currently creating a WinForm in VB.NET bound to an access database.
Basically what i have are two forms: one is a search form used to search the database, and the other is a details form. You run a search on the searchForm and it returns a list of Primary Keys and a few other identifying values. You then double click on the entry you want to view, and it loads the details form.
The Details form has a collection of databound controls to display the data: mostly text boxes and checkboxs. The way i've set it up is i used the UI to build the form and then set the DataBindings Property of each control to "TblPropertiesBindingSource - " where value name is one of the values in the table (such as PropertyID or HasWoodFloor).
Then, when you double click an entry in the searchform, I handle the event by parsing the Primary Key (PropertyID) out of the selected row and then storing this to the details form:
Note: Detail is the details form that is opened to display the info
Private Sub propView_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles propView.CellDoubleClick
Dim detail As frmPropertiesDetail = New frmPropertiesDetail
detail.id = propView.Rows(e.RowIndex).Cells(0).Value
detail.Show()
End Sub
Then, upon loading the details form, it set's the filter on the BindSource as such:
TblPropertiesBindingSource.Filter() = "PropertyID=" & id
This works great so far. All the controls on the details form will display the correct info. The problem is updating changes.
Scenario:
If i have the user load the details for say, property 10001, it will show a description in a textBox named descriptionBox which is identical to the value of the description value of for that entry in the database. I want the user to then be able to change the text of the text box (which they can currently do) and click the save button (saveBut) and have the form update all the values in the controls to the database.
Theorectically, it should do this as the controls are DataBound, thus i can avoid writing code that tells each entry in the database row to take the value of the aligned control.
I've tried calleding PropertiesTableAdapter.Update(PropertiesBindingSource.DataSource), but that doesnt seem to do it.
Ok, I was able to figure this out picking apart some code I pillaged from a friend.
Everything was ok, the problem was the updating
When I was saving the data, i was calling just:
Me.TblProptertiesTableAdapter.Update(Me.TblPropertiesBindingSource.DataSource)
The correct code, without changing anything else is:
Me.Validate()
Me.TblPropertiesBindingSource.EndEdit()
Me.TblPropertiesTableAdapter.Update(Me.RentalPropertiesDataSet.tblProperties)
Me.RentalPropertiesDataSet.AcceptChanges()
Where RentalPropertiesDataSet is the database where TblProperties comes from. Inorder for this to work, make sure TblPropertiesBindingSource.DataSource is RentalPropertiesDataSet.Properties This was autosetup for me by VS08 when it created the BindingSource.
Basically, I needed to tell teh BindingSource to stop allowing the fields to be edited. Then we save the changes to the database, and lastly we tell the DataBase to accept the changes.