I am after a little bit of help:
I have a datagridview control where I add another couple of columns (as check boxes) in order to select multiple rows. When I select the first checkbox column I want the second to be selected automatically, but can then be de-selected if required. And if the first checkbox is deselected, the 2nd is auto deselected too.
I have this working with the following code:
Private Sub dgvBikeAvailability_CellContentClick(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvBikeAvailability.CellContentClick
Debug.Print("Row index = " + e.RowIndex.ToString + ". Column index = " + e.ColumnIndex.ToString + ". Column Name = ")
'Debug.Print()
'when a bike is selected, a helmet is automatically selected, but can be deselected if the customer requires
If e.ColumnIndex = 0 Then
dgvBikeAvailability.Rows(e.RowIndex).Cells(0).Value = Not dgvBikeAvailability.Rows(e.RowIndex).Cells(0).Value
dgvBikeAvailability.Rows(e.RowIndex).Cells(1).Value = dgvBikeAvailability.Rows(e.RowIndex).Cells(0).Value
End If
End Sub
Unfortunately, wen the datagridview is refreshed, the column indexes are incremented, and the column indexes for the 2 check box columns are now 2 and 3.
I would like to be able to refer to them by name. They are declared in the sub that refreshes the datagridview:
colBikeSelectionCheckBox.HeaderText = "Select Bike"
colBikeSelectionCheckBox.Name = "colSelectBike")
colHelmetCheckBox.Name = "colSelectHelmet"
dgvBikeAvailability.Columns.Add(colHelmetCheckBox)
but the System.Windows.Forms.DataGridViewCellEventArgs class does not allow me to select column name.
Any ideas and suggestions will be greatly appreciated!
Edit: More in depth code segment:
Private Sub frmBikeHire_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
refreshGrid()
getStaffMember()
End Sub
'loads and refreshes the dgv
Private Sub refreshGrid()
Dim i As Integer
'initially fill in the rental dates for current day
txtDateFrom.Text = CStr(MonthCalendar1.SelectionRange.Start)
txtDateTo.Text = CStr(MonthCalendar1.SelectionRange.End)
'grab data from DB, set as dgv datasource
startDate = CStr(MonthCalendar1.SelectionRange.Start)
endDate = CStr(MonthCalendar1.SelectionRange.End)
dtBikeAvailability = sqlFuncDB_getDataTable("SELECT * FROM tb_bikeDetail WHERE bikeid NOT IN (SELECT DISTINCT bikeid FROM tb_bikemovements WHERE bikeMovementDate BETWEEN '" + func_convertDateSQLSERVER(startDate) + "' AND '" + func_convertDateSQLSERVER(endDate) + "') AND bikeid NOT IN (SELECT tb_bikemovements.bikeid FROM tb_bikemovements JOIN (SELECT bikeid, max(bikemovementdate) bmd FROM tb_bikemovements WHERE bikemovementdate < '" + func_convertDateSQLSERVER(startDate) + "' group by bikeid) lastmove ON lastmove.bikeid=tb_bikemovements.bikeid AND lastmove.bmd=tb_bikemovements.bikemovementdate WHERE bikeMovementType = '0')")
dvBikeAvailability = New DataView(dtBikeAvailability)
dgvBikeAvailability.DataSource = dvBikeAvailability
'switch off all columns
For i = 0 To dgvBikeAvailability.Columns.Count - 1
dgvBikeAvailability.Columns(i).Visible = False
Next
'displays only relevant column(s)
dgvBikeAvailability.Columns("bikeName").Visible = True
dgvBikeAvailability.Columns("bikeName").HeaderText = "Bike Name"
dgvBikeAvailability.Columns("bikeStyle").Visible = True
dgvBikeAvailability.Columns("bikeStyle").HeaderText = "Bike Style"
dgvBikeAvailability.Columns("bikeColour").Visible = True
dgvBikeAvailability.Columns("bikeColour").HeaderText = "Bike Colour"
'remove this line for program deployment
dgvBikeAvailability.Columns("bikeID").Visible = True
dgvBikeAvailability.Columns("bikeID").HeaderText = "Bike Number"
'add new check box column for selecting the bike
Dim colBikeSelectionCheckBox As New DataGridViewCheckBoxColumn
colBikeSelectionCheckBox.DataPropertyName = "PropertyName"
colBikeSelectionCheckBox.HeaderText = "Select Bike"
colBikeSelectionCheckBox.Name = "colSelectBike"
dgvBikeAvailability.Columns.Add(colBikeSelectionCheckBox)
'add new column for selecting helmet - consider adding as default setting
Dim colHelmetCheckBox As New DataGridViewCheckBoxColumn
colHelmetCheckBox.DataPropertyName = "PropertyName"
colHelmetCheckBox.HeaderText = "Helmet?"
colHelmetCheckBox.Name = "colSelectHelmet"
dgvBikeAvailability.Columns.Add(colHelmetCheckBox)
dgvBikeAvailability.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
End Sub
Private Sub MonthCalendar1_DateChanged(sender As System.Object, e As System.Windows.Forms.DateRangeEventArgs) Handles MonthCalendar1.DateChanged
refreshGrid()
End Sub
Private Sub dgvBikeAvailability_CellClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvBikeAvailability.CellClick
Debug.Print("Row index = " + e.RowIndex.ToString + ". Column index = " + e.ColumnIndex.ToString + ". Column Name = " + dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").OwningColumn.ToString)
If dgvBikeAvailability.Columns(e.ColumnIndex).Name = "colSelectBike" Then
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value = Not dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectHelmet").Value = dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
End If
End Sub
I am unsure why that doesn't work. Each time the calendar control is changed it refreshes the datagridview, which is increasing the column index.
You can use the column index provided by the DataGridViewCellEventArgs class to retrieve the column and from that get the name to compare.
So something like:
If dgvBikeAvailability.Columns(e.ColumnIndex).Name == "colSelectBike" Then
' Your logic here
End If
For referencing the columns within your code to toggle the CheckBoxes, you can very happily use the names, and in fact do not need the index provided by the event args. The event args index appears to only be used to check that one of your desired columns was selected.
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value = Not dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectHelmet").Value = dgvBikeAvailability.Rows(e.RowIndex).Cells("colSelectBike").Value
Although the code above should work it appears that something odd is happening with your grid. A quick solution is to instead of using the .Add() to use the .Insert() method of the DataGridView, which provided an index parameter, allowing you to directly control where your column goes.
Related
I am trying to add a search function to a DataGridView in vb.net using this code
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I'm seeing the MsgBox show when the value matches, but the rows are not showing, it just hides all rows
Another possible option is to load data into a DataTable, create a BindingSource, set the BindingSource DataSource property to the DataTable. Set the DataGridView DataSource property to the BindingSource.
The following example works against a column in the DataTable. If the user clears the TextBox the filter is removed while if there is text filter with trim.
Private Sub SearchButton_Click(sender As Object, e As EventArgs) _
Handles SearchButton.Click
If String.IsNullOrWhiteSpace(SearchTextBox.Text) Then
bindingSource.Filter = ""
Else
Dim currentRowCount = bindingSource.Count
bindingSource.Filter = $"TRIM(LastName) = '{SearchTextBox.Text}'"
MessageBox.Show($"Before: {currentRowCount} Now: {bindingSource.Count}")
End If
End Sub
Edit If the column name might be variable consider loading a ComboBox with column names then adjust code as follows.
bindingSource.Filter = $"TRIM({FilterComboBox.Text}) = '{SearchTextBox.Text}'"
In most cases working against a data source is better than working against cells values as per the above recommendation.
I added 2 Exits in the IF statement when the value matches as it's searching each column as well, so it was causing them to be hidden as it loops columns too
For i As Integer = 0 To ContactsList.RowCount - 1
For j As Integer = 0 To ContactsList.ColumnCount - 1
If ContactsList.Rows(i).Cells(j).Value.ToString.ToLower.Trim = ContactsListSearch.Text.ToLower.Trim Then
MsgBox("Item found " + i.ToString)
ContactsList.Rows(i).Visible = True
Else
ContactsList.Rows(i).Visible = False
End If
Next
Next
I want to iterate through a dataSet and apply each value to a textbox in an active report. i dont know if these text boxes need to be a the Group/Header area or what. i know that my code below is only retrieving the first row. how can I iterate through all rows and apply the data to text boxes that active reports manages to get multiple rows in the group section
Private Sub rptUserCellPhoneSwap_ReportStart(sender As Object, e As System.EventArgs) Handles Me.ReportStart
Me.PageSettings.Orientation = GrapeCity.ActiveReports.Document.Section.PageOrientation.Landscape
DateTxt.Text = Now.ToShortDateString & " " & Now.ToShortTimeString
Dim DataSet = GrabInformation(FirstName, LastName)
UserTxt.Text = LastName + ", " + FirstName
'For Each dr As DataRow In DataSet.Tables(0).Rows
' OldIMEITxt.Text = DataSet.Tables(0).Rows(dr("OldIMEI")).ToString
' NewIMEITxt.Text = DataSet.Tables(0).Rows(dr("NewIMEI")).ToString
' ReasonTxt.Text = DataSet.Tables(0).Rows(dr("SwapReason")).ToString
' DateRepTxt.Text = DataSet.Tables(0).Rows(dr("DateSwapped")).ToString
' ValueTxt.Text = DataSet.Tables(0).Rows(dr("EstimatedAccumulatedValue")).ToString
'Next
If Not IsNothing(DataSet) Then
If DataSet.Tables(0).Rows.Count > 0 Then
OldIMEITxt.Text = DataSet.Tables(0).Rows(0)("OldIMEI")
NewIMEITxt.Text = DataSet.Tables(0).Rows(0)("NewIMEI")
ReasonTxt.Text = DataSet.Tables(0).Rows(0)("SwapReason")
DateRepTxt.Text = DataSet.Tables(0).Rows(0)("DateSwapped")
ValueTxt.Text = DataSet.Tables(0).Rows(0)("EstimateAccumulatedValue")
End If
End If
End Sub
ActiveReports can read data from your DataSet without additional loops in code.
if you return the data table to DataSource property of report object, then it is enough to set DataField property of TextBox controls and GroupHeader section correctly to show data in report. the rendering engine will go through all data rows automatically:
Private Sub SectionReport1_ReportStart(sender As Object, e As EventArgs) Handles MyBase.ReportStart
' bind TextBox controls to fields in table
Me.txtF1.DataField = "F1"
Me.txtF2.DataField = "F2"
' set the grouping field
Me.GroupHeader1.DataField = "F2"
' set the report data source
Me.DataSource = GetSampleData().Tables(0)
End Sub
Private Function GetSampleData() As DataSet
Dim ds = New DataSet()
Dim dt = ds.Tables.Add("TestData")
dt.Columns.Add("F1")
dt.Columns.Add("F2")
dt.Rows.Add("1", "0")
dt.Rows.Add("2", "0")
dt.Rows.Add("1", "1")
dt.Rows.Add("2", "1")
Return ds
End Function
if you prefer to read data row by row in "semi-automatic mode", then FetchData event handler can help here:
Dim i As Integer
Dim dt As DataTable = Nothing
Private Sub SectionReport2_ReportStart(sender As Object, e As EventArgs) Handles MyBase.ReportStart
i = 0
' bind TextBox controls to fields in table
Me.txtF1.DataField = "F1"
Me.txtF2.DataField = "F2"
' set the grouping field
Me.GroupHeader1.DataField = "F2"
dt = GetSampleData().Tables(0)
End Sub
Private Sub SectionReport2_DataInitialize(sender As Object, e As EventArgs) Handles MyBase.DataInitialize
Me.Fields.Add("F1")
Me.Fields.Add("F2")
End Sub
Private Sub SectionReport2_FetchData(sender As Object, eArgs As FetchEventArgs) Handles MyBase.FetchData
If dt.Rows.Count > i Then
Me.Fields("F1").Value = dt.Rows(i)(0)
Me.Fields("F2").Value = dt.Rows(i)(1)
eArgs.EOF = False
Else
eArgs.EOF = True
End If
i = i + 1
End Sub
Private Function GetSampleData() As DataSet
Dim ds = New DataSet()
Dim _dt = ds.Tables.Add("TestData")
_dt.Columns.Add("F1")
_dt.Columns.Add("F2")
_dt.Rows.Add("1", "0")
_dt.Rows.Add("2", "0")
_dt.Rows.Add("3", "1")
_dt.Rows.Add("4", "1")
Return ds
End Function
also, i would recommend to look at the sample with run time data binding in the ActiveReports installation package.
here is a link to the sample description on the official site:
Unbound Data
This is how you would loop through to get all rows, but in this example the only data that will be left in the textboxes will be the last row.
if you want to concatenate each rows information in the specified text box then you should have the information like this.
OldIMEITxt.Text = OldIMEITxt.Text & dr("OldIMEI")
Loop Code
For each dr as Datarow in DataSet.Tables(0).Rows
OldIMEITxt.Text = dr("OldIMEI")
NewIMEITxt.Text = dr("NewIMEI")
ReasonTxt.Text = dr("SwapReason")
DateRepTxt.Text = dr("DateSwapped")
ValueTxt.Text = dr("EstimateAccumulatedValue")
Next
I have an vb.net windows application that has some values which i entered through textbox.
And two datagridviews, in that in first datagridview ,when i enter values in all columns, i have a formula which takes value from Textboxes and DatagridView1 column values. These calculated value should display in second datagridview columns.
For this i tried two ways but both showing problem.
First try:
//First Datagridview -LogCalcEnter , Second Datagrid - LogCalValue
Private Sub LogCalcEnter_CellValueChanged(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles LogCalcEnter.CellValueChanged
LogCalValue.Rows(intRow).Cells(0).Value = LogCalcEnter.Rows(iRow).Cells(0).Value * fPorCutoff.Text
LogCalValue.Rows(intRow).Cells(1).Value = LogCalcEnter.Rows(iRow).Cells(1).Value * fSWCutoff.Text
End Sub
When executing the application,before showing the form below error occurs at
Me.MainForm = Global.LogCalculation.Form1 in OnCreateMainForm().
Additional information: An error occurred creating the form. See
Exception.InnerException for details. The error is: Index was out of
range. Must be non-negative and less than the size of the collection.
Parameter name: index
So i tried another option i have button in form, when i press button,then depends on number of rows in first grid view i will set the values for second datagrid.
But it works if i have one row in Datagridview1. If more than one row, it shows error at second row.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim oLog As New Log
oLog.sWellName = tWellname.Text
oLog.fPoroCutoff = fPorCutoff.Text
oLog.fSWCutOff = fSWCutoff.Text
oLog.fN = fN.Text
oLog.fM = fM.Text
oLog.fA = fA.Text
oLog.fRW = fRW.Text
For iRow = 0 To LogCalcEnter.Rows.Count - 1
If (Trim(LogCalcEnter.Rows(iRow).Cells(0).Value) <> "" And Trim(LogCalcEnter.Rows(iRow).Cells(1).Value) <> "" And Trim(LogCalcEnter.Rows(iRow).Cells(2).Value) <> "") Then
LogCalValue.Rows(iRow).Cells(0).Value = LogCalcEnter.Rows(iRow).Cells(0).Value * oLog.fPoroCutoff
LogCalValue.Rows(iRow).Cells(1).Value = LogCalcEnter.Rows(iRow).Cells(1).Value * oLog.fSWCutOff
LogCalValue.Rows(iRow).Cells(2).Value = LogCalcEnter.Rows(iRow).Cells(2).Value * oLog.fN
End If
Next iRow
End Sub
Actually i want the first option only. But here these two cases get failed.
In the first event, your intRow & iRow may not be defined.
Try this instead,
LogCalValue.Item(0, e.RowIndex).Value = LogCalcEnter.Item(0, e.RowIndex).Value * fPorCutoff.Text
LogCalValue.Item(1, e.RowIndex).Value = LogCalcEnter.Item(1, e.RowIndex).Value * fSWCutoff.Text
I want to move the values from each of four Numeric Up/Down controls into the DataGridView columns/rows with a button. For instance, the operator sets the values in the up/down numeric controls and then clicks the button. The program should then add a new row to the DataGridView and pass whatever values that are in the Numeric Up/Down controls into the new cells of the new row. As of now, I have the adding new rows part of it working as well as the delete button working (delete last row of the DataGridView). Now, how to pass the Numeric control values into the cell of the new row of the DataGridView with the button? Each new row created of the DatGridView has four cells to correspond to the four Numeric up/down controls. Thank you.
Private Sub addStep_btn_Click(sender As Object, e As EventArgs) Handles addStep_btn.Click
LftMtr_Data_Grid.ColumnCount = 4
LftMtr_Data_Grid.RowCount = LftMtr_Data_Grid.RowCount + 1
LftMtr_Data_Grid.Columns(0).HeaderText = " Spindle Speed (rpm)"
LftMtr_Data_Grid.Columns(1).HeaderText = " Accel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(2).HeaderText = " Decel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(3).HeaderText = " Time (S)"
For Each c As DataGridViewColumn In LftMtr_Data_Grid.Columns
c.Width = 120
Next
Dim rowNumber As Integer = 1
For Each row As DataGridViewRow In LftMtr_Data_Grid.Rows
If row.IsNewRow Then Continue For
row.HeaderCell.Value = "Step " & rowNumber
rowNumber = rowNumber + 1
Next
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
rowCount1 = LftMtr_Data_Grid.RowCount
txtBox1.Text = rowCount1
End Sub
Try something like below. Note that you don't need to setup the column headers everytime, just once in the Load() event would do!
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LftMtr_Data_Grid.ColumnCount = 4
LftMtr_Data_Grid.Columns(0).HeaderText = " Spindle Speed (rpm)"
LftMtr_Data_Grid.Columns(1).HeaderText = " Accel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(2).HeaderText = " Decel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(3).HeaderText = " Time (S)"
For Each c As DataGridViewColumn In LftMtr_Data_Grid.Columns
c.Width = 120
Next
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
End Sub
Private Sub addStep_btn_Click(sender As Object, e As EventArgs) Handles addStep_btn.Click
Dim values() As Object = {NumericUpDown1.Value, NumericUpDown2.Value, NumericUpDown3.Value, NumericUpDown4.Value}
Dim index As Integer = LftMtr_Data_Grid.Rows.Add(values)
LftMtr_Data_Grid.Rows(index).HeaderCell.Value = "Step " & (index + 1)
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
End Sub
Private Sub delStep_btn_Click(sender As Object, e As EventArgs) Handles delStep_btn.Click
If LftMtr_Data_Grid.Rows.Count > 0 Then
LftMtr_Data_Grid.Rows.RemoveAt(LftMtr_Data_Grid.Rows.Count - 1)
End If
End Sub
End Class
I figured it out on my own. Here is what I came up with:
Dim rowNumber As Integer = 1
For Each row As DataGridViewRow In LftMtr_Data_Grid.Rows
If row.IsNewRow Then Continue For
row.HeaderCell.Value = "Step " & rowNumber
LftMtr_Data_Grid.CurrentCell = LftMtr_Data_Grid.Rows(LftMtr_Data_Grid.RowCount - 1).Cells(0)
LftMtr_Data_Grid.CurrentRow.Cells(0).Value = LftMtr_Speed_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(1).Value = LftMtr_Accel_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(2).Value = LftMtr_Decel_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(3).Value = test_Time_Incr1.Value
rowNumber = rowNumber + 1
Next
This application works with an empty or partially filled dataGridView. When the user clicks the button, the code creates a new row in the dataGridView, makes the new row the selected row, and then finally populates each of the cells in the new row with the values that are in the four Numeric Up/down controls (could be a text box too depending on your application). This is code copied directly from my specific application. Yours may differ slightly with variable names, label text, etc.
I have a problem . When I load my form with my datagridview , I want the data to be transferred to the text fields when I click on the > at the most left of the datagridview.
Now, I have to select the content in the rows itself to select a row. How do I set it so it selects row based on the most left row selector? instead of having me click on the contents of the row ? dtguser_CellContentClick makes me select based on the content click right? What should it be if I want to select by entire row?
Private Sub dtguser_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dtguser.CellContentClick
If GroupBox3.Enabled = False Then
Else
'this code will simply pass the value from the specific row selected by the user
lblid.Text = dtguser.CurrentRow.Cells(0).Value
serial.Text = dtguser.CurrentRow.Cells(0).Value
fname.Text = dtguser.CurrentRow.Cells(1).Value
lname.Text = dtguser.CurrentRow.Cells(2).Value
gender.Text = dtguser.CurrentRow.Cells(3).Value
address.Text = dtguser.CurrentRow.Cells(4).Value
contact.Text = dtguser.CurrentRow.Cells(5).Value
course.Text = dtguser.CurrentRow.Cells(6).Value
datestart.Text = dtguser.CurrentRow.Cells(7).Value
datecomplete.Text = dtguser.CurrentRow.Cells(8).Value
datecertify.Text = dtguser.CurrentRow.Cells(9).Value
nationality.Text = dtguser.CurrentRow.Cells(10).Value
email.Text = dtguser.CurrentRow.Cells(11).Value
certification.Text = dtguser.CurrentRow.Cells(12).Value
End If
End Sub
If you want to select the entire row set the selection mode to FullRowSelect.
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
If you want to get the data when you click the RowHeader (> button) then subscribe to the RowHeaderMouseClick event.
dataGridView1.RowHeaderMouseClick += new DataGridViewCellMouseEventHandler(dataGridView1_RowHeaderMouseClick);
Private Sub dataGridView1_RowHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs)
// put your code for copying row data into the textboxes.
End Sub