Change value type of bound datagridview - vb.net

I am binding data to a datagridview from a MSSQL database, there are mixed datatypes and I think vb.net by default sets the valuetype of the column/cell based on the data.
My requirement is that I want all the columns to have the value type of string.
I tried doing the following, before & after binding the data.
datagridview1.AutoGenerateColumns = False
colQty.ValueType = GetType(String)

You can set the ColumnType when the column is created. You can do this in code, or using the Designer in Visual Studio. It is worth noting that once a column is created [at run time] the ColumnType cannot be changed. You can of course add new columns as needed at run-time:
Dim col as New DataGridViewTextBoxColumn
datagridview1.Columns.Add(col)
Changing a ColumnType in the designer can be accomplished From the DataGridView Tasks fly-out menu as shown below:

Related

Question About Datagridview Format Styling

i want to Show Thousand Separator in Datagridview Column
So i added One Column in datagridview so i Run this code But It's not working with me
You need to explicitly specify the column's ValueType if you don't have a DataSource to bind (ex. DataTable) which is the source of the data types as well. Here, you need a column of a numeric type such as Decimal.
So, before you populate the grid or add new rows, do:
With DataGridView2.Columns(0)
.ValueType = GetType(Decimal)
.DefaultCellStyle.Format = "#,#.##"
End With
In case the control is bound to DataSource, make sure that the type of the data field/property in question is numeric.

VB.Net Windows Form Databinding

I am trying (novice) to create a simple app that users can update a data table in a sql database via by adding, deleting or updating current records. So I have created the form and have combo box in there that is connected to a data table in my database. I want to load the value of the record selected into that combo box, but also have the list of options available to update that record in the database. the problem with my code is, it has the correct corresponding value for the record, but it is not showing. Also, when I select the combo box, the other values in the table are not there. the value is duplicated 2 times.
Here is how the combo box is bound:
How it Loads:
When I select the combo box:
Public Sub FillDriverDataSet()
Dim sql As String
Dim dt As New DataTable
Dim ds As New DataSet
Dim dv = New DataView(ds.Tables("Drivers"))
Dim bs As New BindingSource
Dim cm As CurrencyManager
sql = "SELECT * FROM tCommercialDrivers where id = 23"
OpenConnection()
Dim adapter As New SqlDataAdapter(sql, connection)
Dim drivers As New SqlDataAdapter(sql, connection)
adapter.Fill(dt)
drivers.Fill(ds, "Drivers")
dv = New DataView(ds.Tables("Drivers"))
cm = CType(Me.BindingContext(dv), CurrencyManager)
bs.DataSource = dt
adapter.Fill(dt)
drpRouteType.DataSource = dt
drpRouteType.DisplayMember = "RouteType"
drpRouteType.ValueMember = "RouteType"
txtRoute.DataBindings.Clear()
txtRoute.DataBindings.Add("text", dv, "RouteID")
End Sub
As an overview of how this is supposed to work ( and bearing in mind that I can't see your database structure so I'm guessing at it a bit)
open connection manager
add a connection to sql server
create a new DataSet type item in the project
open the DataSet
drag eg the CommercialDrivers table out of connection manager and into the DataSet then right click the table adapter and choose configure , or
right click the DataSet and choose add tableadapter, configure the connection, choose "select that retrieves rows.."
add or modify (depending what you did above) the sql so it's SELECT * FROM commercialDrivers WHERE iD = #DriverId
call your method FillById and GetDataById
finish
repeat true above process for the table that holds the RouteTypes but because we don't be selecting them singly, do not add a where clause and leave the default names of Fill and GetData
you should now have a DataSet with two tables and possibly a datarelation line between them. The relation isn't strictly necessary for our needs and can be removed
make a new form and open it
open the datasources window on the view menu (other windows)
from datasources drag the routetypes node to the form, then delete the grid view and bindingnavigator that appeared - keep the other stuff that appeared as it will be useful
rename the DataSet in the bottom tray so that it's called something else (anything; we just want the instance name to be different from the type name as it can cause confusion to have a variable named the same as a type. I prefix the name with an underscore, tableadapters too)
in the data sources window click the drop down next to CommercialDrivers and change it to Details mode, expand the node, change RouteType to a combobox
drag the CommercialDrivers parent node to the form, a bunch of controls will appear, with data bindings already set to the DataSet on the form
for the route type combo get its properties:
change dropdownstyle to dropdownlist
change DataSource to be routetypesbindingsource
change displaymember to be whatever is the route type text column
change valuemember to be whatever column holds the route type id
in the (data bindings) node at the top of the properties grid check that selectedvalue is bound to CommercialDrivers.RouteTypeId (CommercialDrivers binding source, datamember route type id), and remove the binding from the text property. Combos with a backing list should have selectedvalue bound, not text
That's it; the one line of code you have to write or sort out is filling the CommercialDriver table with the relevant ID. Technically it's probably zero lines; Visual studio probably already did that for you by putting a bindingnavigator complete with textbox and fill Button when you dragged the details into the form but you might want to change how it's done. The route types table in the DataSet is filled in form load, with all the different route types, the combo will read eg commercial drivers table's routetypeid value of 4, look up that value in the column set in its value member (in the route types table set in its DataSource) and show the value it finds in the column set in its displaymember. If you change the combo to something else it gets the value from the new row (From the column set in the valuemember) and writes that value into the commercialdrivers table routetypeid hence changing the routetype for that driver
It looks a lot when written down (and if you get stuck at any point let me know; I wrote this from memory, without a visual studio in front of me, on a cellphone so there may be some detail I forgot) but in reality when you're used to the process it probably takes about a minute to do this. VS writes all the code you did - you can see it in the various .Designer files if you're interested
So I cleaned it up a bit, and it works now. Let me know if you still see something I could have done better. Thank you for your reply!
Public Sub FillDriverDataSet()
Dim sql As String
Dim ds As New DataSet
Dim dv = New DataView(ds.Tables("Drivers"))
Dim bs As New BindingSource
Dim cm As CurrencyManager
sql = "SELECT * FROM tCommercialDrivers where id = 26"
OpenConnection()
Dim drivers As New SqlDataAdapter(sql, connection)
drivers.Fill(ds, "Drivers")
dv = New DataView(ds.Tables("Drivers"))
cm = CType(Me.BindingContext(dv), CurrencyManager)
drpRouteType.DataBindings.Clear()
drpRouteType.DataBindings.Add("text", dv, "RouteType")
txtRoute.DataBindings.Clear()
txtRoute.DataBindings.Add("text", dv, "RouteID")
txtDriverID.DataBindings.Clear()
txtDriverID.DataBindings.Add("text", dv, "DriverID")
txtEmailAddress.DataBindings.Clear()
txtEmailAddress.DataBindings.Add("text", dv, "EmailAddress")
txtDriverName.DataBindings.Clear()
txtDriverName.DataBindings.Add("text", dv, "DriverName")
txtDollYd.DataBindings.Clear()
txtDollYd.DataBindings.Add("text", dv, "YardageAmt")
txtDayRate.DataBindings.Clear()
txtDayRate.DataBindings.Add("text", dv, "DayRate")
cbxActive.DataBindings.Clear()
cbxActive.DataBindings.Add("Checked", dv, "IsActive")
cbxIncentive.DataBindings.Clear()
cbxIncentive.DataBindings.Add("Checked", dv, "IncentivePay")
' dteExpDate.DataBindings.Clear()
'dteExpDate.DataBindings.Add("text", dv, "ExperienceDate")
End Sub

DataList object has no method DataBind()

I am trying to get the results of a SQL Server stored procedure in VB.NET, parse them into a DataSet, then use the DataSet to fill a Windows Forms ListBox.
I have found many, many tutorials. The only ones that have gotten me close to a solution are ones that depend on the ListBox's DataBind() method. However:
myListBox.DataBind()
' ERROR: 'DataBind' is not a member of 'ListBox'
This is contrary to every tutorial I've found on the topic (approx a dozen so far).
Here is more code context:
Dim connection As New SqlConnection(myConnectionSecret)
Dim command As New SqlCommand("myStoredProcedureName")
command.Parameters().Add("#myParam", SqlDbType.Int).Value = myParamValue
command.Connection = connection
command.CommandType = CommandType.StoredProcedure
Dim adapter As New SqlDataAdapter(command)
adapter.SelectCommand.CommandTimeout = 300
'Fill the dataset
Dim dataSet As New DataSet
adapter.Fill(dataSet)
connection.Close()
myListBox.DataSource = dataSet
myListBox.DataBind() ' This method not found
A dataset is a collection of datatables. Typically you would bind your listbox to only one datatable. You can set the DataSource property to a dataset but you'll then also need to set the DataMember property to the name of the table in the dataset so the binding knows which table to rummage in
myListBox.DataSource = dataSet
myListBox.DataMember = "Person" 'whatever your table name is
Or set it to refer to the table directly:
myListBox.DataSource = dataSet.Tables("Person")
As other answers have commented you should then set the DisplayMember (chooses what text appears in the control) and ValueMember (chooses what value is emitted by the listbox.SelectedValue property) properties to strings representing the column names. If I want to show my persons name in the list but have their email be the selected value:
myListBox.DisplayMember = "FullName" 'fullname is a column in the datatable
myListBox.ValueMember = "Email"
If you don't set a ValueMember the whole DataRow of the selected person is returned from SelectedValue. (Clarification: Actually, it's a DataRowView because binding to a datatable actually happens to a DataView exported by the .DefaultView property - more on this later)
So, we've bound our list.DataSource to a datatable, and set the diplay/valuemember properties. How to we get the details of what Person is selected currently? Put a button on the form that has this handler code:
MessageBox.Show(DirectCast(listbox.SelectedValue, string)) 'shows e.g. john.smith#hotmail.com
Run the program, click "John Smith" in the list then click the button. The messagebox will show the selected person's email address
I mentioned earlier that databinding happens to a DataView object exported by the table's .DefaultView property. A DataView is a collection of DataRowView objects, and a DataRowView is a thin wrapper around a DataRow. DataRows exist in various versions such as original or updated values. A DataRowView is a way of selecting one of these versions for presentation, by default the Current version. You can address it like you would a DataRow:
'accessing the email address of a datatable row
Dim myDataRow = myPersonTable.Rows(0)
Dim email as String = DirectCast(myDataRow("EmailAddress"), string)
'accessing the email address of the dataview exported by the table defaultview
Dim myDataRowView = myPersonTable.DefaultView(0)
Dim email as String = DirectCast(myDataRowView("EmailAddress"), string)
As you can see, there isn't a lot of difference - as noted, the view just shows one of the various versions a datarow can exist in. If you want to get access to the underlying row you can do it via the Row property:
Dim myDataRowView = myPersonTable.DefaultView(0) 'or however you ended up holding a DataRowView object
Dim dr as DataRow = myDataRowView.Row
If you're using strongly typed datatables (discussed below), and want the strongly typed row:
Dim dr as PersonDataRow = DirectCast(myDataRowView.Row, PersonDataRow)
A useful aspect of the list binding to the .DefaultView DataView is that it can have its own filtering and sorting setup:
Dim dv = dataSet.Tables("Person").DefaultView
dv.Sort = "[FullName] ASC"
dv.RowFilter = "[FullName] LIKE 'J*'"
For more info on these see the documentation for dataview
Now, sea change: you don't have to do any of this by hand. All this can be linked up and done by visual studio and there are compelling reasons for doing so. For the same reason you don't write your form codes by hand, manually laying out all your controls etc, you can visually design and maintain your data access layer
Add a new dataSet file to your project, open it, right click the design surface and choose to add a tableadapter, go through the wizard setting your connection string and choosing that it's a stored procedure that gives you the data. At the end of it you'll see a datatable representation and all the columns returned by your stored procedure
If you now show the data sources window when you're in your forms designer you'll see a node representing your table from your dataSet, and you can either drag that node onto the form to create a DataGridview that is hooked up leafy, or you can expand the node in the data sources window to see individual columns, you can change the type of control to create for that property and you can drop them on the form. (I can't remember if listbox is one of them, but I know that ComboBox is). Dropping them on the form simply creates a control, already named and wired up with the right DataSource, Member and DisplayMember properties set, and you can change these and other properties like the value member in the properties grid.
Most critically of a difference, the controls the designer creates are all bound through a device called a bindingsource - this tracks the row in the datatable you're currently looking at, and keeps data bound controls in sync. If one control such as a grid or list is capable of showing multiple rows, clicking on different rows changes the Current property of the binding source, causing other controls (that only render one data row's data) such as textboxes to update to the new Current row values
Thus list controls may operate in one or two modes: they either serve as a device that can navigate a datatable's rows allowing you to pick one of a few rows so that you can edit the values using other textboxes etc, or lists serve as a way of showing a set of values for the user to cope from and cause another datarow's property to update to that chosen value. The differentiation in these two modes comes from whether the selectedvalue property is bound to something else or not. As a simple example in the context I've been discussing already, we could have a dataSet with two tables; person and gender; the person table has a gender column single char M or F, and the gender table has two columns one is a single char M or F and the other a text column of Male or Female (I won't get into the cases for other genders right now but the system is easy to extend by adding more rows). You could then have a form where the person table plus its binding source is causing a list of people to show in the first list box and click in different items in the list causes all the other textboxes (FullName) on the form to change so you can edit those details. You can also have a second listbox bound to the gender table via its own bindingsource (or direct, doesn't matter) that has its DisplayMember set to the "Male/female" column, its value member set to the "m/f" column and it's SelectedValue property bound to the main Person bindingsource's Person.gender column. When you choose a person from the first list, the current char value of their Gender will be used to set the current item selected in the gender list but if you change the value in the gender combo/list then it will write the new selectedvalue back into the person.gender column
That's the 101 of Windows forms binding; I recommend adding a dataset to your project because it then gives you datatables that are specifically typed with named properties. Your code looks like this:
ForEach PersonDataRow r in myDataset.Person
r.Age += 1
Instead of this:
ForEach DataRow r in myDataset.Tables("Person").Rows
r("Age") = DirectCast(r("Age"), Integer) +1
I was mid-answer when jmcilhinney commented: DataBind() is specific to ASP.Net Web Forms server controls.
Therefore, the DataBind() call isn't necessary, simply setting the DataSource property on a Windows Forms ListBox is enough.
As for parsing your results from your SQL Server, don't forget to set the ListBox's DisplayMember and ValueMember properties to correctly display your data to the user.
Here's the documentation on the DataSource property. It has a very decent example.
For filling a list box, you usually don't need DataSets or DataAdapters. Just a DataTable table will do.
The Using...End Using blocks ensure that your database objects are closed and disposed.
You can pass the connection directly to the constructor of the command.
Set the list box data source to the DataTable. Then you can use the names of the fields in the Select statement to set the .DisplayMember and .ValueMember. The display and value can be the same.
Private Sub FillListBox(myParamValue As Integer)
Dim dt As New DataTable
Using connection As New SqlConnection("myConnectionSecret")
'Pretend your stored procedure has a statement like "Select DeptarmentID, DepartmentName From Departments Where SupervisorID = #myParam;"
Using command As New SqlCommand("myStoredProcedureName", connection)
command.CommandType = CommandType.StoredProcedure
command.Parameters().Add("#myParam", SqlDbType.Int).Value = myParamValue
connection.Open()
dt.Load(command.ExecuteReader)
End Using
End Using 'Closes and disposes the connection
ListBox1.DataSource = dt
ListBox1.DisplayMember = "DepartmentName"
ListBox1.ValueMember = "DepartmentID"
End Sub

Value Retrieve from Datagridview's Columns

I am working on VB in Visual Studio 2010. And I've seen errors of greatness in which when I double click on a line of datagridview, I get the values of its columns in such a way.
Datagridview1.SelectedRows(0).Cells(1).Value
But the most surprising thing is that with this same code I get the values ​​of different columns each time without changing the index value in Cells(). I also put the name of the column inside the Cells(), but I did not get any value from this too.
Datagridview1.SelectedRows(0).Cells("name").Value
And the first column of this datagridview Cells(0) always returns the null value itself. I do not know how.
I have also used some column formating. like
With Datagridview1
.ColumnCount =2
.Columns(0).HeaderText ="Name"
.Columns(0).DataPropertyName = "pname"
.Columns(0).Width =100
.Column(1).HeaderText = "Son of"
.Column(1). DataPropertyName = "fname"
The big problem here is that it gives value to different columns each time with a single code
Is there any solution available for this?

combobox binding - show field names in bindingsource

I am trying to use a bindingsource as the datasource for a combobox. The display and value members of the combobox will be the field names in my bindingsource's datasource.
Currently I use a process of populating a datatable and assigning it to the datasource of the combobox. Because I already have the bindingsource populated with data it would make sense to just set the binding up rather than continue to use this code below:
Dim dtfields As New DataTable
dtfields = mySqlref.sqlobj.SelectData(String.Format("select column_name from information_schema.columns where table_name = '{0}' order by ordinal_position", mydata.Table), SqlLibrary.SqlLibrary.SelectType.datatable)
cboField.DataSource = dtfields
cboField.ValueMember = "column_name"
cboField.DisplayMember = "column_name"
Can someone point me in the right direction? Thanks for reading.
The sort of answer I was looking for here was:
if your fieldnames are already in your bindingsource then you can use linq to create an array of those fieldnames instead of using a seperate query to call the database for field names
Here's the code I ended up using:
Dim arraynames = (From x As DataColumn In mydata.Table.Columns Select x.ColumnName).ToArray()
cboField.DataSource = arraynames
in this example "mydata" is a dataview. It is the object upon which my binding source is created. I extract column names into an array using the datatable object inside that dataview.