Displaying a checkbox in a databound DataGridView - vb.net

I am unable to correctly populate a DataGridView checkbox column from a boolean column from a database.
First form_load code:
Me.DataGridView1.DataSource = Me.bindingSource1
GetData("SELECT myInt, myBool, myString " & _
"FROM " & myFavTable & " " & _
"WHERE (myInt > 100) ORDER BY myString")
formatGrid()
In GetData I fill myTable with data:
Me.dataAdapter.Fill(myTable)
Me.bindingSource1.DataSource = myTable
And finally I format grid the before showing.
I format it manually because loading is much faster than with automatic formatting.
With DataGridView1
.AllowUserToAddRows = False
.AllowDrop = False
.AllowUserToOrderColumns = False
.AllowUserToResizeRows = False
.SelectionMode = DataGridViewSelectionMode.FullRowSelect
.MultiSelect = False
.Dock = DockStyle.Fill
.EditMode = DataGridViewEditMode.EditProgrammatically
With .Columns(0)
.Name = "postN"
.HeaderText = "Postal"
.Width = 55
End With
With .Columns(1) 'here should be a checkbox
.Width = 20
End With
With .Columns(2)
.Name = "colCity"
.HeaderText = "City"
.Width = 180
End With
End With
But with this code, in my column that should show checkboxes the string value 0 is displayed when in database is FALSE.
How in this situation can I get checkboxes in the middle column instead of text?
I try with .Columns.Add... before and after binding but with no wanted results.
That way I can get checkboxes, but in the new column.

In design-time add the columns to the DataGridView and set the middle column as a CheckBoxColumn.
Then set:
With DataGridView1
.AutoGenerateColumns = False
Edit:
I see the problem now. You need to set the DataPropertyName to be the same as the column.
When you add columns to the DataGridView, in that dialog set the DataPropertyName to match the DataTable (myTable) column Names. That's the magic behind the mapping.
Here is the code:
DataTable dt = new DataTable();
dt.Columns.Add("TextBoxCol");
dt.Columns.Add("CheckBoxCol");
DataRow dr = dt.NewRow();
dr[0] = "Hello";
dr[1] = false;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr[0] = "World";
dr[1] = true;
dt.Rows.Add(dr);
dataGridView1.DataSource = dt;

I had the same problem.
I had a DataSet that it was filling with this SQL:
"SELECT nombre, CASE WHEN fecha IS NULL THEN 0 ELSE 1 END AS baja"
Assignment
dtgEmpleado.DataSource = ds.Tables(0)
With dtgEmpleado
.Columns(0).HeaderText = "Nombre"
.Columns(0).DataPropertyName = "nombre"
.Columns(0).Name = "nombre"
.Columns(0).Width = 100
.Columns(1).HeaderText = "Baja"
.Columns(1).DataPropertyName = "baja"
.Columns(1).Name = "baja"
.Columns(1).Width = 70
End With
I wanted that the column "Baja" it was displaying as a "Checkbox".
I could do it with:
AutoGenerateColumns = False
But an easier way, changing the SQL sentence:
"SELECT nombre, CAST(CASE WHEN fecha IS NULL THEN 0 ELSE 1 END AS BIT) AS baja"

Dim cell As DataGridViewCell = New DataGridViewCheckBoxCell()
With DataGridView1
With .Columns(1)
.CellTemplate = cell
End With
End With
EDIT:
This a suggestion, don't try to add columns at design-time in your DataGridView because you query itself it will generate a DataGridViewCheckBoxCell
GetData("SELECT myInt AS Id, myBool AS Bool, myString AS String " & _
"FROM " & myFavTable & " " & _
"WHERE (myInt > 100) ORDER BY myString")
Me.dataAdapter.Fill(myTable)
Me.bindingSource1.DataSource = myTable
DataGridView1.DataSource = bindingSource1;

Related

Search data in DataGridView using FilterDataRow VB.Net

DV = New DataView(ds.Tables("CustomerList"))
FlxCustomerList.DataSource = ds.Tables("CustomerList").DefaultView
myDataTable = CType(FlxCustomerList.DataSource, DataView).ToTable
drToAdd = myDataTable.NewRow()
drToAdd("Customer Account") = ""
drToAdd("Customer Name") = ""
drToAdd("Customer Group") = ""
drToAdd("City") = ""
drToAdd("Mobile No") = ""
drToAdd("Status") = ""
myDataTable.Rows.InsertAt(drToAdd, 0)
myDataTable.AcceptChanges()
FlxCustomerList.DataSource = myDataTable.DefaultView
For Each dtrow As DataGridViewRow In FlxCustomerList.Rows
If dtrow.Index = 0 Then
dtrow.Frozen = True
Else
dtrow.ReadOnly = True
End If
Next
To achieve the search in Datagridview functionality, I'm getting the first row by this, on search enter, key-down function call this
CustomerAccountFilterStr = CStr(Me.DataGridView1.Rows(0).Cells("CustomerAccount").Value)
sStr = sStr & " [Customer Account] like '%" & CustomerAccountFilterStr & "%'"
ds.Tables("CustAcc").DefaultView.RowFilter = sStr
This is how I binding Data to DataGridView
myDataView.RowFilter = sStr
FlxCustomerList.DataSource = myDataView
And Then The DataGridView which is bound to the DefaultView of DataSet. I froze the first row but now, couldn't understand how to put back filtered values from the second-row onwards to the grid.
The example output should resemble like below.
I'm stuck to implement this functionality. please guide How to implement this functionality?

DataGridView Yes No ComboBox Column

I have what on the face of it seems a pretty simple requirement, I need an unbound combobox column to hold an option list of 'Yes' and 'No'. In combobox parlance Yes and No are the DisplayMembers corresponding to ValueMembers 1 and 0 respectively which in turn are the values held in the field of the database table. I use bound combobox columns in the application extensively and am very familiar with building them, but can't for the hell of me work out how to incorporate this simple list functionality in the datagridview application. Could somebody please put me out of my misery with some sample code.
Thanks for your feedback Plutonix. The DGV is bound to an underlying table. Hopefully, the following code should give you some idea of what I am attempting to acheive. The code specifically relevant to this post is in the call to PopulateUnboundComboBox(comboBoxCol, {"Yes", "No"}).
Private Sub GetData()
Const procName As String = "GetData()"
Dim myValue As String = ""
Dim myDataSource As Integer = 0
Try
'First clear the existing grid
With Me.uxGrid
If .ColumnCount > 0 Then
'clear the grid
ClearGrid(Me.uxGrid)
End If
End With
_Logger.SendLog(Me.Name & "." & procName & " - Fetching device data.", NLog.LogLevel.Trace)
'Get the data from the database
If Not _dataSourceID = 0 Then
_sqlStatement = "SELECT ID, TEXT, CATEGORY, MOUNTING, DATASOURCEID, TANALYSIS" & _
" FROM P_TBL_DEVICE WHERE DATASOURCEID = " & _dataSourceID
_criteria = "WHERE DATASOURCEID = " & _dataSourceID
Else
_sqlStatement = ""
_criteria = ""
End If
_myDeviceMngr = New DeviceManager(_currentDB, _userName, _myPwd)
'Now get the latest data
_myDataSet = _myDeviceMngr.GetData(_sqlStatement)
_Logger.SendLog(Me.Name & "." & procName & " - Device data fetch completed.", NLog.LogLevel.Trace)
'Update the display
Call BuildGrid(_myDataSet, uxGrid)
Catch ex As Exception
Beep()
MsgBox(ex.Message, MsgBoxStyle.Exclamation, System.Windows.Forms.Application.ProductName)
_Logger.SendLog(ex.Message & ". Thrown in module " & Me.Name.ToString & "." & procName, NLog.LogLevel.Error, ex)
Finally
Call System.GC.Collect()
End Try
End Sub
Private Sub BuildGrid(ByVal myDataSet As DataSet, ByVal myGrid As DataGridView)
Dim myTable As New System.Data.DataTable
Dim myColCount As Integer
Dim comboBoxCol As DataGridViewComboBoxColumn
Dim readOnlyCellStyle As New DataGridViewCellStyle
Dim textBoxCol As DataGridViewTextBoxColumn
Dim gridObject As Object = Nothing
Const procName As String = "BuildGrid"
readOnlyCellStyle.ForeColor = Color.Gray
Try
_Logger.SendLog(Me.Name & "." & procName & " - Building device data grid.", NLog.LogLevel.Trace, Nothing)
myTable = myDataSet.Tables(0)
With myGrid
'Now add the columns to the grid
Dim column As System.Data.DataColumn
For Each column In myDataSet.Tables(0).Columns
'We dont want to include the changedon and changedby fields in the grid build
If column.ColumnName.IndexOf("CHANGED") = -1 Then
Select Case column.ColumnName
Case "DATASOURCEID"
gridObject = New Object
comboBoxCol = New DataGridViewComboBoxColumn
'First create the comboboxcolumn for the column
'Populate combobox
PopulateScadaSourceComboBoxCol(comboBoxCol)
comboBoxCol.DataPropertyName = "DATASOURCEID"
comboBoxCol.HeaderText = "SCADA SOURCE"
comboBoxCol.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
comboBoxCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing
gridObject = comboBoxCol
Case "TEXT"
textBoxCol = New DataGridViewTextBoxColumn
gridObject = textBoxCol
'Now add the columns to the grid
gridObject.DataPropertyName = column.ColumnName.ToString
gridObject.HeaderText = column.ColumnName.Replace("TEXT", "DEVICE")
gridObject.name = column.ColumnName.Replace("TEXT", "DEVICE")
gridObject.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
Case "CATEGORY"
textBoxCol = New DataGridViewTextBoxColumn
gridObject = textBoxCol
'Now add the columns to the grid
gridObject.DataPropertyName = column.ColumnName.ToString
gridObject.HeaderText = "CATEGORY"
gridObject.name = "CATEGORY"
gridObject.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
Case "MOUNTING"
textBoxCol = New DataGridViewTextBoxColumn
gridObject = textBoxCol
'Now add the columns to the grid
gridObject.DataPropertyName = column.ColumnName.ToString
gridObject.HeaderText = "MOUNTING"
gridObject.name = "MOUNTING"
gridObject.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
Case "TANALYSIS"
comboBoxCol = New DataGridViewComboBoxColumn
'First create the comboboxcolumn for the column
'Populate combobox
PopulateUnboundComboBox(comboBoxCol, {"Yes", "No"})
comboBoxCol.DataPropertyName = "TANALYSIS"
comboBoxCol.HeaderText = "TELECONTROL ANALYSIS"
comboBoxCol.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
comboBoxCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing
gridObject = comboBoxCol
Case Else
textBoxCol = New DataGridViewTextBoxColumn
gridObject = textBoxCol
'Now add the columns to the grid
gridObject.DataPropertyName = column.ColumnName.ToString
gridObject.HeaderText = "ID"
gridObject.name = "ID"
gridObject.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
End Select
'Now add the textbox columns to the grid
'gridObject.DataPropertyName = column.ColumnName.ToString
'gridObject.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
.Columns.Add(gridObject)
End If
Next
'Set grid default styles/values
.Font = New System.Drawing.Font("Arial", 10, FontStyle.Regular)
.AllowUserToResizeColumns = True
.AllowUserToResizeRows = True
.AllowUserToAddRows = True
.ReadOnly = True
.AutoResizeRows()
.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText
'Now bind the datatable to the DGV datasource property
.DataSource = myTable
End With
_Logger.SendLog(Me.Name & "." & procName & " - Building of device data grid has been completed.", NLog.LogLevel.Trace, Nothing)
Catch ex As Exception
Throw
Finally
textBoxCol = Nothing
comboBoxCol = Nothing
readOnlyCellStyle = Nothing
GC.Collect()
End Try
End Sub
Private Sub PopulateUnboundComboBox(ByVal comboBoxCol As DataGridViewComboBoxColumn, byval valList() as string)
comboBoxCol.Name = "TANALYSIS"
comboBoxCol.DataSource = valList
comboBoxCol.ValueMember = ???
comboBoxCol.DisplayMember = ???
End Sub
EDITED//
Ok, I've made some progress and seem to have almost solved my issue. The one remaining bug is that the column in the DGV is displaying the 'ValueMember' (1 or 0) rather than the 'DisplayMember' (Yes or No). I've checked the valuemember and displaymember properties in the comboboxcolumn definition and and they appear to be set correctly. Here is the associated code:
Excerpt from original code posting listed above
...
Case "TANALYSIS"
gridObject = New Object
comboBoxCol = New DataGridViewComboBoxColumn
'First create the comboboxcolumn for the column
'Populate combobox
Dim item As New CBOItem
Dim itemList As New CBOItemList
item.ValueMember = 0
item.DisplayMember = "No"
itemList.Add(item)
item = New CBOItem
item.ValueMember = 1
item.DisplayMember = "Yes"
itemList.Add(item)
PopulateComboBox(comboBoxCol, itemList)
comboBoxCol.DataPropertyName = "TANALYSIS"
comboBoxCol.HeaderText = "TELECONTROL ANALYSIS"
comboBoxCol.AutoSizeMode = DataGridViewAutoSizeColumnsMode.AllCells
comboBoxCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing
gridObject = comboBoxCol
...
Private Sub PopulateComboBox(ByRef comboBoxCol As DataGridViewComboBoxColumn, ByVal itemList As CBOItemList)
Dim tbl As DataTable = New DataTable
Dim row As DataRow
tbl.Columns.Add("ValueMember")
tbl.Columns.Add("DisplayMember")
row = tbl.NewRow
row.Item("ValueMember") = itemList(0).ValueMember
row.Item("DisplayMember") = itemList(0).DisplayMember
tbl.Rows.Add(row)
row = tbl.NewRow
row.Item("ValueMember") = itemList(1).ValueMember
row.Item("DisplayMember") = itemList(1).DisplayMember
tbl.Rows.Add(row)
comboBoxCol.ValueMember = tbl.Columns("ValueMember").ToString
comboBoxCol.DisplayMember = tbl.Columns("DisplayMember").ToString
comboBoxCol.DataSource = tbl
End Sub
Kind Regards
Paul J.

vb.net GridView store value but display text from datatable

Please I want to store the value of address in the gridview or datatable but display it's name, so when saving data to database I will insert the value.
dtCust_dtls.DefaultView.RowFilter = String.Format("SR_ID = '{0}'", SrLookup.GetSelectedItem("SR_ID"))
GCCustList.DataSource = dtCust_dtls.DefaultView
GVCustList.Columns("CUSTOMER_CODE").VisibleIndex = 0
GVCustList.Columns("ADDRESS_ID").VisibleIndex = 1
GVCustList.Columns("CUSTOMER_CODE").Caption = "Customer Code"
GVCustList.Columns("ADDRESS_ID").Caption = "Address"
on button add
dtCust_dtls.DefaultView.RowFilter = String.Format("SR_ID = '{0}' and CUSTOMER_CODE = '{1}'", SrLookup.GetSelectedItem("SR_ID"), txtCust_Code.Text.Trim)
If (dtCust_dtls.DefaultView.Count = 0) Then
Dim dr As DataRow = dtCust_dtls.NewRow()
dr("SR_ID") = SrLookup.GetSelectedItem("SR_ID")
dr("CUSTOMER_ID") = DataRowSelectedCust("CUSTOMER_ID")
dr("ADDRESS_ID") = cmbCustAdd.SelectedValue
dr("CUSTOMER_CODE") = txtCust_Code.Text.Trim
dr("CUSTOMER_BARCODE") = DataRowSelectedCust("CUSTOMER_ID") & "." & cmbCustAdd.SelectedValue 'custId + . + addID
dr("STAMP_DATE") = Now
dtCust_dtls.Rows.Add(dr)
Else
MsgBox("The Customer code '" & txtCust_Code.Text & "' already exist for " & txtSrName.Text)
End If
on save btn I am saving the datatable dtCust_dtls as it is.
I had an idea to add one column : Address Name and leave the column Address ID but I don't have any idea how to do it !
USING THE RepositoryItemLookUpEdit
Dim xCust_Code As New DevExpress.XtraEditors.Repository.RepositoryItemLookUpEdit
With xCust_Code
.ForceInitialize()
.DataSource = dtCustList.DefaultView
.DisplayMember = "Customer_Description"
.ValueMember = "Customer_Code"
.PopulateColumns()
.NullText = String.Empty
End With
GVCustDUE.Columns("CUSTOMER_CODE").ColumnEdit = xCust_Code

ComboBoxCell Not Displaying Correctly

I have a DataGridView, which has a ComboBoxColumn. This column is binded to a DataTable:
With dtYesOrNo
.Rows.Clear()
.Columns.Clear()
.Columns.Add("Description")
.Columns.Add("Code")
Dim statusRow = dtYesOrNo.NewRow
statusRow("Description") = ""
statusRow("Code") = 101
dtYesOrNo.Rows.Add(statusRow)
statusRow = dtYesOrNo.NewRow
statusRow("Description") = "Yes"
statusRow("Code") = 102
dtYesOrNo.Rows.Add(statusRow)
statusRow = dtYesOrNo.NewRow
statusRow("Description") = "No"
statusRow("Code") = 103
dtYesOrNo.Rows.Add(statusRow)
End With
Then I set DisplayMember to "Description", and ValueMember to "Code".
Dim colUECStatus As New DataGridViewComboBoxColumn
With colUECStatus
.DataSource = dtYesOrNo
.DataPropertyName = "StatusChk"
.Name = "StatusChk"
.DisplayMember = "Description"
.ValueMember = "Code"
'Combobox Formatting
.HeaderText = "Status"
.DisplayStyle = DataGridViewComboBoxDisplayStyle.ComboBox
.FlatStyle = FlatStyle.Flat
.DefaultCellStyle.BackColor = Color.FromArgb(255, 255, 192)
UECgrid.Columns.Insert(0, colUECStatus)
End With
But my problem is that when I actually load the form, it is giving me an exception for not having a valid value in my combox. For example, if the selection is "", the combo box would display 101, instead of "".
And here's the code where I load my grid (Note: please ignore the grid names -- UECgrid and dgvUEC1 are the same grid):
Dim row = 0
For Each checklist In USEFileChecklistUSChecklist.GetGeneralChecklist
objEFile.dgvUEC1.Rows(row).Cells("StatusChk").Value = checklist.statusCode
row += 1
Next

Select N records statement not returning correct amount

I am using a sql statement to connect to an access db and retrieve only 100 records. However, this is returning ALL records and not 100. How do I limit the records I want to fetch. If I run this statement in access directly as a query, it works fine.
I am using winforms in vb.Net.Thanks
sql = "Select top 100 * from Requests ORDER BY [Date-time received] DESC"
vb.Net code
Dim lvcount As Integer = 0
'Dim tmpColor As Color = Color.Green
Sub fillRequests()
Try
DBConnection.connect()
sql = "Select top 100 * from Requests ORDER BY [Date-time received] DESC"
Debug.Print(sql)
Dim oledbCmd As OleDbCommand = New OleDbCommand(sql, oledbCnn)
Using dr = oledbCmd.ExecuteReader()
While dr.Read()
If dr.HasRows Then
Dim LVI As New ListViewItem
With LVI
.UseItemStyleForSubItems = False
.Text = dr(0).ToString()
.SubItems.Add(CDate(dr(5)).ToShortDateString)
.SubItems.Add(dr(1).ToString())
.SubItems.Add(dr(3).ToString())
If dr(3).ToString = "D" Then
.SubItems(3).Text = "Destruction"
ElseIf dr(3).ToString = "O" Then
.SubItems(3).Text = "Retrieval"
ElseIf dr(3).ToString = "I" Then
.SubItems(3).Text = "Intake"
ElseIf dr(3).ToString = "B" Then
.SubItems(3).Text = "Return"
ElseIf dr(3).ToString = "X" Then
.SubItems(3).Text = "Other"
ElseIf dr(3).ToString = "1" Then
.SubItems(3).Text = "Supply std boxes"
ElseIf dr(3).ToString = "G" Then
.SubItems(3).Text = "File Return"
ElseIf dr(3).ToString = "F" Then
.SubItems(3).Text = "File Retrieval"
ElseIf dr(3).ToString = "2" Then
.SubItems(3).Text = "Supply prt boxes"
End If
.SubItems.Add(dr(9).ToString())
If IsDBNull(dr(9)) Then
.SubItems(4).Text = "O/S"
.SubItems(4).ForeColor = Color.Red
'MessageBox.Show(.SubItems(4).Text)
ElseIf dr(9) IsNot "DEMO" Then
.SubItems(4).Text = "Done"
End If
End With
lvRequests.Items.Add(LVI)
lvcount += 1
End If
End While
End Using
'autosize each column in listview
For Each col As ColumnHeader In lvRequests.Columns
col.Width = -2
Next col
'refresh the list with new data
'lvRequests.Refresh()
'Enable the posting previous button
btnPreviousPostings.Enabled = False
btnPreviousPostings.Text = "No data to show"
oledbCnn.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
'dr.Close()
'oledbCnn.Close()
End Try
'btnNextPostings.Enabled = ListView1.Items.Count > 100
If (lvRequests.Items.Count < 100) Then
btnNextPostings.Enabled = False
btnNextPostings.Text = "No data to show"
Else
btnNextPostings.Enabled = True
btnNextPostings.Text = "Next " & CStr(lvRequests.Items.Count - 1) & " Postings"
End If
'RESET LVCOUNT TO 0
lvcount = 0
End Sub
From office.microsoft.access.help
The TOP predicate does not choose between equal values.
So if all your records have same value in [Date-time received], then query return all rows.
Workaround:
If you have for example ID-field(or some another field, but with unique values) in your table Requests then use it in ORDER
SELECT TOP 100 * FROM Requests ORDER BY [Date-time received] DESC, [ID] DESC
Just a workaround: If it is not huge data you can get the result into some collection and then get the top 100 items from that collection(I suppose it would be easy using vb.NET) and dispose others off.