How to display default values in bound form? - vb.net

I have a VB.Net form bound to a datatable.
Let's assume the following datatable:
Dim DataTable As New DataTable
DataTable.Columns.Add(New DataColumn("ID"))
DataTable.Columns.Add(New DataColumn("NAME"))
DataTable.Columns("ID").AllowDBNull = False
DataTable.Columns("NAME").AllowDBNull = False
The form has two textboxes bound to the datatable :
Me.TextBox1.DataBindings.Add("text", DataTable, "ID")
Me.TextBox2.DataBindings.Add("text", DataTable, "NAME")
Now I want to add a new row to the datatable with a default value in the ID. I have two ways to do it.
1st method
Me.DataTable.Rows.Add()
This method doesn't work. It raises the error : Column 'ID' does not allow nulls.
2nd method
Dim NewRow As DataRow
NewRow = DataTable.NewRow
'Add ID default value
NewRow.Item("ID") = 1
.
.
.
'Once the user filled the field Name
NewRow.Item("NAME") = TextBox2.text
DataTable.Rows.add(NewRow)
The problem with this second method is that, the default value affected doesn't appear in the ID text box which is quite normal since this row has not yet been added the Datatable. And I can not neither add it to the datatable if the Column "NAME" has not yet been filled.
Does it mean that I can never have the default value displayed in the form ?
Does anyone have an idea on how to display default values on the form with respect to AllowDBNull property ?

Try setting the DefaultValue property of the DataColumn:
DataTable.Columns("ID").DefaultValue = 0
DataTable.Columns("NAME").DefaultValue = "Test"

Related

Bound datagrid not showing values

I have a datagrid which is bound to a binding source which itself is populated from a list.
I can see that the binding source is populated and I can see that the datagrid has the expected number of rows to match the data in the list but i can not get the columns to populate with the data. I have tried setting the datapropertyname for the columns but to no avail. I know this is probably dead simple but I'm going round in circles.
Please can anyone help
Dim cE As New ClsEmail
Dim bs As New BindingSource
Dim dgv = Me.DataGridView1
dgv.AutoGenerateColumns = False
bs.DataSource = cE.GetMail("team#xxxx.xxxx")
With dgv.Columns(0)
.DataPropertyName = "ID"
.HeaderText = "ID"
End With
With dgv.Columns(1)
.DataPropertyName = "Subject"
.HeaderText = "Subject"
End With
dgv.DataSource = bs
When i press the button to populate the datagrid I get four rows but no values in the columns. Clearly I'm not binding the columns correctly but i can't see what I'm missing.
List(Of T) is already bindable. Rearrange your properties in your Email class like this, as the DataGridView will create the columns in property order:
Public Class Email
Public Property ID As Integer
Public Property Subject As String
Public Property DateReceived As DateTime
End Class
Then, just set the datasource like this:
With DataGridView1
.AutoGenerateColumns = True
.DataSource = cE.GetMail("team#xxxx.xxxx")
.Columns(2).Visible = False ' DataReceived (if you really intended to hide this)
End With

In VB.NET I am having problems populating a DataGridView combobox using a datatable

I have a datatable (dsBrands) that I want to display in a datagridview. The combobox in the datagridview gets its selections from a different table(dsGroups). How do I show in the combobox the value that is currently stored in the dsBrands table? Below is my code that works except that the combobox is left blank. The combobox collection does populate correctly from dsGroups. The value that needs to be displayed in the combobox from dsBrands is in the collection. The --> is just to make the line stand out and not in the actual code.
Private Sub FillBrands()
Dim TransCount As Integer
Dim Group As String
If Not ds.Tables.Contains("dsBrands") Then Else ds.Tables("dsBrands").Clear()
conn.Open()
daBrands = New OleDbDataAdapter("Select * from Brands", conn)
daBrands.FillSchema(ds.Tables("dsBrands"), SchemaType.Source)
daBrands.Fill(ds, "dsBrands")
conn.Close()
dgv1.AutoGenerateColumns = False
bs1.DataSource = ds.Tables("dsBrands")
dgv1.DataSource = bs1
Dim colDisplay As New DataGridViewCheckBoxColumn
colDisplay.DataPropertyName = "Display"
colDisplay.HeaderText = "Include?"
colDisplay.Name = "Display"
colDisplay.Visible = True
Dim colGroupList As New DataGridViewComboBoxColumn
colGroupList.HeaderText = "Add to Group"
colGroupList.Name = "GroupList"
colGroupList.Visible = True
colGroupList.DataSource = ds.Tables("dsGroups")
--> colGroupList.DataPropertyName = "BGroup" 'BGroup is a field in dsBrands table.
dgv1.Columns.Add(colDisplay)
dgv1.Columns.Add(colBrand)
dgv1.Columns.Add(colGroup)
dgv1.Columns.Add(colGroupList)
End Sub
Just as when binding a regular ComboBox, you need to set the DisplayMember and ValueMember properties of your column. The DisplayMember specifies the column whose values get displayed and the ValueMember specifies the column whose values correspond to the grid data. ValueMember should specify the PK column of the table bound to the column that corresponds to the FK column of the table bound to the grid.

How to set a data grid column to be a drop down when binding to a table

I am able to create a data table and bind it to a datagridview. If possible I want something more sophisticated. I want to limit the first column to values 1 to 12 and the 2nd column to either AM or PM.
Thanks in advance.
mDataTable = GetTable()
DataGridView1.DataSource = mDataTable
Function GetTable() As DataTable
' Create new DataTable instance.
Dim table As New DataTable
' Create four typed columns in the DataTable.
table.Columns.Add("Hour", GetType(Integer))
table.Columns.Add("AM/PM", GetType(String))
table.Columns.Add("Delete", GetType(Boolean))
For i = 1 To mSchedules.Count
table.Rows.Add(SetAMPMHour(mSchedules(i - 1).ScheduleINetHour), SetAMPM(mSchedules(i - 1).ScheduleINetHour), False)
Next
Return table
End Function
If the combobox column is going to have fixed values, you can manually define those values either at design time or at runtime (althought both ways require you to set AutoGenerateColumns property to False before you bind your data to your grid).
If you want to do it by code, try this:
DataGridView1.AutoGenerateColumns = False
Dim hoursCol, timeOfDayCol As New DataGridViewComboBoxColumn
Dim deleteCol As New DataGridViewCheckBoxColumn
For i As Integer = 1 To 12
hoursCol.Items.Add(i)
Next
timeOfDayCol.Items.Add("AM")
timeOfDayCol.Items.Add("PM")
hoursCol.DataPropertyName = "Hour"
timeOfDayCol.DataPropertyName = "AM/PM"
deleteCol.DataPropertyName = "Delete"
DataGridView1.Columns.Add(hoursCol)
DataGridView1.Columns.Add(timeOfDayCol)
DataGridView1.Columns.Add(deleteCol)
mDataTable = GetTable()
DataGridView1.DataSource = mDataTable
If you want to do it in design time:
Create your Combobox Column...
...set DataPropertyName to the name of the column of the DataTable that will be binded to that GridView column, and in Collection define the values that will populate the ComboBox
Remember that, even if you define the values in design time, you have to programatically set AutoGenerateColumns to False before you set the data source. Also, if you create a ComboBox Column in design time, you'll have to fill it with String values.

Unable to set valuemember/display member to bind combobox

I'm having trouble adding dynamically a combo box column to my datagridview (before you ask, yes it must be dynamic and not done in editor).
The main feature is that the combobox cell is different for each row, so it must be done using combo box cell. checkedRows is a datatable.
Name of the datagridview is editCameraTable. It already has a few columns at this point:
'create new column
Dim resComboColumn As New DataGridViewComboBoxColumn _
With {.HeaderText = "Resolution", .ReadOnly = False, .DisplayIndex = 7, .Name = "Resolution", _
.DisplayMember = "Name", .ValueMember = "ID", .DataPropertyName = "ID"}
'add combo box column
EditCameras.editCameraTable.Columns.Insert(17, resComboColumn)
addResCmbBox(checkedRows, resComboColumn)
Pretty straight forward. You'll notice I have the value member, dataproperty name, etc. Here's the addResCmbBox definition:
Public Function addResCmbBox(ByRef DT As DataTable, column As DataGridViewComboBoxColumn)
Dim resolutions As String()
'for each camera
For i As Integer = 0 To DT.Rows.Count - 1
Dim camera As camera = convertDTtoCam(DT, i)
'get the resarray
Select Case DT.Rows(i).Item("Maker").ToString.ToLower
Case "acti"
resolutions = ACTi.GetResArray(camera)
Case Else
resolutions = ACTi.GetResArray(camera)
End Select
'add items to combobox list
Dim comboCell As New DataGridViewComboBoxCell
comboCell.DataSource = resolutions
For j As Integer = 0 To resolutions.Length - 1
'set to current resolution value
If resolutions(j).TrimStart("N") = camera.res Then
comboCell.Value = resolutions(j)
End If
Next
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
EditCameras.editCameraTable("Resolution", i) = comboCell
Next
Return Nothing
End Function
camera is a structure. I have no problems until I get to the displayMember and value member problem, i.e. the last line starting with "editcameras.editcameratable...".
When doing so, the exception of "The Field Name does not exist" pops up. If I don't assign the displayMember and valueMember, I have no problems. But, I can't get the value selected in the comboBox (it comes back as Null). At runtime, the combobox column has the valuemember and display name as "ID" and "Name".
How can I bind this comboboxcell to the row so that I can later get it's selected value?
UPDATE:
I did as was commented, and created a struct/class that was meant to be the resolution property:
Public Class ResolutionStruct
Property Name As String
Property ID As String
End Class
And within the loop I create a list of this class, and assign the values to it:
Dim resolutionList As New List(Of ACTi.ResolutionStruct)
For j As Integer = 0 To resolutions.Length - 1
Dim resClass As New ACTi.ResolutionStruct
resClass.Name = resolutions(j)
resClass.ID = resolutions(j)
resolutionList.Add(resClass)
Next
'set combocell values
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
comboCell.DataSource = resolutionList
EditCameras.editCameraTable("Resolution", i) = comboCell
However, the comboboxCell doesn't show any value when it drops down. So, now I've bound the values but it shows nothing. Is there anything else I should be doing so that I get both the holy combo of seeing the values I'm picking AND having them be bound to the data grid view? :D
UPDATE 2
So, mea culpa. I was adding the combobox cell to the wrong column!
So now, it is showing the values. I click a value, and try to grab the selected value as as string:
Dim cmbbox2 As DataGridViewComboBoxCell = editCameraTable("Resolution", i)
resolution(i) = cmbbox2.Selected.ToString()
But it still says it's a null value! Mid build I checked the combobox props. IN fact "selected" is a boolean as false. It has no value, says it has no items as well. Any ideas on why it says it is null?
UPDATE3:
I recently resorted a different column in the table, and the values from the combo box are cleared! I guess it's really never being attached/bound in the first place.
UPDATE4:
Fixed it!!
Apparently this line:
editCameraTable.Sort(editCameraTable.Columns("ID"), System.ComponentModel.ListSortDirection.Ascending)
Caused the table to freak out! I can now get the value (woohoo!)
Right, I'll try to explain this shortly:
DisplayMember and ValueMember are supposed to be set using properties. For example you create a class containing Name and ID
Public Class Test
Property Name as String
Property ID as String
End Class
Create a few of these objects and put them in a list. Set the list as the datasource to the combobox. Now you can access the DisplayMember and ValueMember as you have written it in your code. Value would be the ID and SelectedItem would be the entire class.
What you are doing now is that you are adding a list of strings to the combobox. A String does not contain the Property Name nor ID, so naturally you can't fetch them. See it like this:
To be able to use Value and/or DisplayMember you need to be able to fetch the Property by yourself. In this case:
resolutions(j).Name
or
resolutions(j).ID
This does not work.
But for example you would be able to do this:
resolutions(j).Length
So You would be able to do this, which would display the Length in the combobox:
Combobox.DisplayMember = "Length"
To currently get the value you would have to do:
Combobox.SelectedItem.ToString()
But since you have it in a combobox column My guess is that this won't cut it since you can't fetch the value from the DataGridView.
EDIT: You are still doing this right?
<DataGridView>.Item("Resolution", i) = comboCell
Otherwise you will have empty comboboxes.
EDIT2: No need to fetch value from Combobox, get it from Grid cell instead:
<DataGridView>.Item("Resolution", i).Value
When creating the columns don't forget to set a defaultvalue to the combobox, otherwise it might be Nothing:
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
comboCell.Value = resolutions(0)

Filling Value to ListBox in Vb.Net

I need a simple way to fill the value from database of the current item being added so that I can use it later :
'Filling the MAIN Categories part
Dim DataAdapterCatm As New MySqlDataAdapter("SELECT id,title From catM;", MySqlConnection)
Dim dsMc As New DataTable
DataAdapterCatm.Fill(dsMc)
For counter = 0 To dsMc.Rows.Count - 1
LbMCat.Items.Add(dsMc.Rows(counter).Item("title").ToString)
'LbMCat.ValueMember = dsMc.Rows(counter).Item("id").ToString
'The above line don't work, I need something to replace it
Next
You are misunderstanding what ValueMember means. ValueMember is a string which represents the property that you wish to use as the value. In your case it would be just "id". Notice that it is a property of the ListBox - it is not different for each time.
ValueMember and the related DisplayMember are only valid when using DataBinding with the DataSource property and it not valid when manually adding items to the ListBox via Items.Add. What you want is the following:
Dim DataAdapterCatm As New MySqlDataAdapter("SELECT id,title From catM;", MySqlConnection)
Dim dsMc As New DataTable
DataAdapterCatm.Fill(dsMc)
LbmCat.DataSource = dsMc;
LbMCat.ValueMember = "id";
LbmCat.DisplayMember = "title";
try this in place of both lines in your for loop:
LbMCat.Items.Add(New ListItem(dsMc.Rows(counter).Item("title").ToString(), dsMc.Rows(counter).Item("id").ToString())
In the constructor for ListItem you can specifiy both the value and the text for the ListItem