Get special max record - vb.net

I have in my Table1 3 fields (IdFactory Type Numeric-IdSector Type Numeric-NameFactory Type Text).When i click on Button1 i get max record of (IdFactory) in TextBox1.My ComboBox1 is filled with several numbers from 1 to 100.I choose (IdSector) by ComboBox1 and the records in this field (IdSector) repeat only 5 times.How to automatically display max record of (IdSector) in combobox1 when i Click on Button1.this is my code to get max record on TextBox1

ExecuteScalar returns Nothing, not DBNull.Value if no result has been found.
Dim result As Object = Cmd.ExecuteScalar
Dim id As Integer
If result Is Nothing Then
id = 1
Else
id = CInt(result) + 1
End If
TextBox1.Text = id.ToString()
ComboBox1.SelectedItem = id
This assumes that you have added the numbers to the ComboBox as Integer and not as String. If you have added them as String do ComboBox1.SelectedItem = id.ToString().

Keep your data objects local so you can be sure they closed and disposed. The Using...End Using blocks do this for you even if there is an error.
What I think you are after is the IdSector for the highest IdFactory. Although you can't use an aggregate function in a where clause; you can use a sub-query with an aggregate.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim result As Object
Using Conne As New OleDbConnection("Your connection string")
Using Cmd As New OleDbCommand("Select IdSector from Table1 Where IdFactory = (Select max(IdFactory) From Table1);", Conne)
Conne.Open()
result = Cmd.ExecuteScalar
End Using
End Using
If result Is Nothing Then
TextBox1.Text = "1"
ComboBox1.Text = "1"
Else
TextBox1.Text = (CInt(result) + 1).ToString
ComboBox1.Text = result.ToString
End If
End Sub

Related

how to make a datagridview cellvaluechange 2 column which trigged loop

I am developing a sales order application. I am using a datagridview to fill the sales order.
the field in my datagridview are as per below
ItemCode - ItemDescription - qty - price
The description field is a combobox.
What I want is that when a user input an ItemCode, it automatically check my database and give me the Itemdescription
I also want user to be able to select an item from the ItemDescription which is a combobox, and it wil automatically update my Itemcode.
Private Sub salesorder_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles salesorder_dgv.CellValueChanged
If salesorder_dgv.Rows.Count > 0 Then
If e.ColumnIndex = 0 Then
Dim READER As SqlDataReader
conn.Open()
Dim query As String
query = "select * from item where code = '" & salesorder_dgv.Rows(e.RowIndex).Cells(0).Value & "'"
cmd = New SqlCommand(query, conn)
READER = cmd.ExecuteReader
If READER.Read Then
salesorder_dgv.Rows(e.RowIndex).Cells(1).Value = READER.GetString(2)
End If
conn.Close()
End If
If e.ColumnIndex = 1 Then
Dim READER As SqlDataReader
conn.Open()
Dim query As String
query = "select * from item where description = '" & salesorder_dgv.Rows(e.RowIndex).Cells(1).Value & "'"
cmd = New SqlCommand(query, conn)
READER2 = cmd.ExecuteReader
If READER.Read Then
salesorder_dgv.Rows(e.RowIndex).Cells(0).Value = READER.GetString(1)
End If
conn.Close()
End If
End If
End Sub
Is there a way to make this code work? i am getting "The Connection was not closed"
There's a lot wrong there so I'll first address what you have to clean it up, then address how you should be doing it.
As suggested in the comments, you should be creating all your ADO.NET objects where you need them, including the connection. You create, use and destroy in the narrowest scope possible. Also, if you only want data from a single column, don't use SELECT *. Retrieve only the column(s) you need. As you're only retrieving data from one column of one row, you should be using ExecuteScalar rather than ExecuteReader.
Next, you should acquaint yourself with the DRY principle, i.e. Don't Repeat Yourself. You have two blocks of code there that are almost identical so you should extract out the common parts and write that only once and pass in the different parts.
Finally, don't use string concatenation to insert values into SQL code. ALWAYS use parameters. It avoids a number of issues, most importantly SQL injection, which is quite possible in your case, as the user is entering free text. With all that in mind, the code you have would be refactored like so:
Private Sub salesorder_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles salesorder_dgv.CellValueChanged
If salesorder_dgv.RowCount > 0 Then
Dim sourceColumnIndex = e.ColumnIndex
Dim targetColumnIndex As Integer
Dim query As String
Select Case sourceColumnIndex
Case 0
targetColumnIndex = 1
query = "SELECT description FROM item WHERE code = #param"
Case 1
targetColumnIndex = 0
query = "SELECT code FROM item WHERE description = #param"
Case Else
Return
End Select
Dim row = salesorder_dgv.Rows(e.RowIndex)
Dim sourceValue = row.Cells(sourceColumnIndex).Value
Using connection As New SqlConnection("connection string here"),
command As New SqlCommand(query, connection)
command.Parameters.AddWithValue("#param", sourceValue)
connection.Open()
row.Cells(targetColumnIndex).Value = command.ExecuteScalar()
End Using
End If
End Sub
Now to how you should have done it. If you're populating a combo box column with all the descriptions then you must be querying the database for them in the first place. What you should have done is retrieved both the descriptions and the codes in that initial query. That way, you never have to go back to the database. You can populate a DataTable with both the codes and the descriptions and then much of the work will be done for you.
For the example below, I started by setting up the form in the designer, which meant adding and configuring the appropriate columns in the grid and adding the BindingSource components. That also includes setting the DataPropertyName property of each grid column so it binds to the appropriate source column. I'm also manually populating the item data here but you would be getting that data from your database.
Private itemTable As New DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadItemData()
LoadSaleData()
End Sub
Private Sub LoadItemData()
With itemTable.Columns
.Add("code", GetType(String))
.Add("description", GetType(String))
End With
With itemTable.Rows
.Add("123", "First Item")
.Add("abc", "Second Item")
.Add("789", "Third Item")
.Add("xyz", "Fourth Item")
.Add("01a", "Fifth Item")
End With
itemBindingSource.DataSource = itemTable
With itemDescriptionColumn
.DisplayMember = "Description"
.ValueMember = "Description"
.DataSource = itemBindingSource
End With
End Sub
Private Sub LoadSaleData()
Dim saleTable As New DataTable
With saleTable.Columns
.Add("ItemCode", GetType(String))
.Add("ItemDescription", GetType(String))
.Add("Quantity", GetType(Integer))
.Add("Price", GetType(Decimal))
End With
saleBindingSource.DataSource = saleTable
salesorder_dgv.DataSource = saleBindingSource
End Sub
Private Sub salesorder_dgv_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles salesorder_dgv.CellValidating
If e.RowIndex >= 0 AndAlso
e.ColumnIndex = 0 AndAlso
Not String.IsNullOrEmpty(e.FormattedValue) Then
'Check that the code entered by the user exists.
e.Cancel = (itemBindingSource.Find("code", e.FormattedValue) = -1)
If e.Cancel Then
MessageBox.Show("No such item")
End If
End If
End Sub
Private Sub salesorder_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles salesorder_dgv.CellValueChanged
Dim rowIndex = e.RowIndex
Dim sourceColumnIndex = e.ColumnIndex
If rowIndex >= 0 And sourceColumnIndex >= 0 Then
Dim sourceColumnName As String
Dim targetColumnName As String
Dim targetColumnIndex As Integer
Select Case sourceColumnIndex
Case 0
sourceColumnName = "code"
targetColumnName = "description"
targetColumnIndex = 1
Case 1
sourceColumnName = "description"
targetColumnName = "code"
targetColumnIndex = 0
Case Else
Return
End Select
Dim itemRow = itemBindingSource(itemBindingSource.Find(sourceColumnName, salesorder_dgv(sourceColumnIndex, rowIndex).Value))
Dim code = CStr(itemRow(targetColumnName))
salesorder_dgv(targetColumnIndex, rowIndex).Value = code
End If
End Sub
You start by populating the items and binding that data to the combo box column and then create an empty DataTable for the sales and bind that to the grid. The code checks that any manually entered codes actually do match items and it will set the description when a code is entered manually and the code when a description is selected from the list. It does this by referring back to the BindingSource containing the item data each time, so no extra queries. You might want to consider retrieving the price data for each item too, and calculating the price for that row based on that and the quantity.

DataGridView add checkbox and allow to select only records based on variable value via checkbox

In vb.net I have DataGidView showing all columns from my Access database. Then in form Load event I added this code to add check box column to DataGridView.
Dim chk As New DataGridViewCheckBoxColumn()
DataGridView1.Columns.Add(chk)
chk.HeaderText = "Select Question"
chk.Name = "chk"
Here I want user to only select those many records as my maxquestions variable integer value and do not let user select more questions. I also want that user cannot change values of my DataGridView. And thereafter I want to export selected questions to a new table mynewtable already created in database.
Thanks, help appreciated.
I have done something and it somehow works fine...
Private Sub DataGridView1_CellValueChanged(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
If (TryCast(DataGridView1.CurrentCell, DataGridViewCheckBoxCell)) IsNot Nothing Then
Dim count As Integer = 0
For Each row As DataGridViewRow In DataGridView1.Rows
Dim isChecked As Boolean = CBool(row.Cells(6).EditedFormattedValue)
If isChecked Then
count = count + 1
Else
' count -= 1
End If
Next
If count > mark_1_questions Then
Label3.ForeColor = Color.Red
Else
Label3.ForeColor = Color.Black
End If
Label3.Text = "You Have Selected: " & count & " Questions."
If count = mark_11_questions Then
MessageBox.Show(Me, "Maximum/Required Questions Selected : " & mark_11_questions, "Caution")
'DataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically
Button1.Enabled = True
ElseIf count > mark_11_questions Then
MessageBox.Show(Me, "Please unselect some questions : " & count - mark_11_questions, "Caution")
Button1.Enabled = False
Else
End If
End If
End Sub
Now the question is how to export selected records through checkbox to table altogether.
You can get the count like this.
Private Function GetCheckedCount() As Integer
Dim CheckedRows As Integer
For Each row As DataGridViewRow In DataGridView1.Rows
If CBool(row.Cells(8).Value) Then
CheckedRows += 1
End If
Next
Return CheckedRows
End Function

UltraWinGrid deletes top record rather than the selected one

I've got an ultrawingrid that I can select rows on, and need to be able to delete the highlighted row. At the moment, it calls the database SQL query that I wrote but instead of deleting the record in the row I selected, it deletes the record in the top row instead. Can anybody work out why?
Private Sub btnDeleteIncident_Click(sender As Object, e As EventArgs) Handles btnDeleteIncident.Click
Try
Dim rowValue = ugHistory.Selected.Rows
Dim rowToDelete = ugHistory.Rows(0).Cells(0).Value.ToString
Dim removeIncident As MsgBoxResult
removeIncident = MsgBox("Are you sure you wish to delete this incident?", MsgBoxStyle.Question + MsgBoxStyle.YesNo, "Confirm")
If removeIncident = MsgBoxResult.Yes Then
Database.deleteIncident(rowToDelete)
txtClientSave.Text = ""
rtbProblem.Text = ""
rtbSolution.Text = ""
dtpStart.Value = Date.Today
dtpEnd.Value = Date.Today
dtpStartTime.Value = DateTime.Now
dtpEndTime.Value = DateTime.Now
cboxSolved.Checked = False
btnUpdate.Hide()
btnSave.Show()
ElseIf removeIncident = MsgBoxResult.No Then
loadIncidents()
End If
Catch Ex As Exception
MsgBox("No incidents to delete")
End Try
loadIncidents()
End Sub
Database SQL query;
Public Shared Sub deleteIncident(ByVal supportID As Integer)
Connect()
Dim Dc As New OleDbCommand
Dc.Connection = Con
Dc.CommandText = "DELETE * FROM tblIncidents WHERE([supportID] = " & supportID & ")"
Dc.ExecuteNonQuery()
Disconnect()
End Sub
You are taking the value for rowToDelete from the first row of the grid not from the current active row
I suggest you to change this line
Dim rowToDelete = ugHistory.Rows(0).Cells(0).Value.ToString
to
Dim rowToDelete = ugHistory.ActiveRow.Cells(0).Value.ToString
Also, it is always better to follow a safe approach when handling reference objects like 'ActiveRow', so before running your code add a test for a valid
ActiveRow
if ugHistory.ActiveRow Is Nothing Then
Return
End If
Dim rowToDelete = ugHistory.ActiveRow.Cells(0).Value.ToString

Export datatable to crystal report

I created a datatable (.xsd) that corresponds to the datatable I coded in the code-behind.
Protected Sub btnDproceed_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDproceed.Click
'---> ASSUME THAT I CODES FOR THE FIRST FOUR COLUMNS OF DATATABLE IS MADE HERE
'---> CREATE DYNAMIC COLUMNS OF SCORES
cn.Open()
'---> SQL COMMAND HERE THAT GET TOP 5 DATA FROM DATABASE USED TO GENERATE 5 ADDITIONAL COLUMNS IN dt
rs = cmd.ExecuteReader
Do While rs.Read
Dim gwno As String = rs.Item("GWNO").ToString
If gwno.Length = 1 Then
gwno = "0" & gwno
End If
Dim vHeader As String = "LES" & gwno & "_" & rs.Item("GWTYPE")
If Not dt.Columns.Contains(vHeader) Then
Dim f As New Data.DataColumn(vHeader, GetType(System.String))
dt.Columns.Add(f)
f.AllowDBNull = True
End If
Loop
cn.Close()
'---> DATA ROWS FOR SCORES
For Each row As DataRow In dt.Rows
If Not dt.Columns.Contains("RANK") Then
dt.Columns.Add("RANK").SetOrdinal(0)
End If
Dim v As Integer
v = v + 1
row(0) = v.ToString
For col As Integer = 4 To dt.Columns.Count - 1
'---> SQL COMMAND THAT GETS DATA (score) BASED ON THE 5 GENERATED COLUMNS ABOVE
rs = cmd.ExecuteReader
If rs.Read = True Then
If Not String.IsNullOrEmpty(rs.Item("SCORE").ToString) Then
row(col) = rs.Item("SCORE").ToString
Else
row(col) = rs.Item("REMTYPE").ToString
End If
End If
cn.Close()
Next
Next
'---> ADDITIONAL STATIC COLUMNS
dt.Columns.Add("LE_SUM")
dt.Columns.Add("LE_CNT")
dt.Columns.Add("LE_AVE")
dt.Columns.Add("UE_SUM")
dt.Columns.Add("UE_CNT")
dt.Columns.Add("UE_AVE")
dt.Columns.Add("AVERAGE")
dt.Columns.Add("CGRADE")
dt.Columns.Add("+/-GPTS")
dt.Columns.Add("CRANK")
dt.Columns.Add("DEF")
dt.Columns.Add("EXPTD")
dt.Columns.Add("ABCNT")
dt.Columns.Add("INC")
Dim crpt As New ReportDocument()
CrystalReportViewer1.DisplayGroupTree = False
crpt.Load(Server.MapPath("~/CrystalReport.rpt"))
crpt.SetDataSource(dt)
CrystalReportViewer1.ReportSource = crpt
End Sub
As seen above, the dt and Scores.xsd has similar datacolumns which will be used in generating the crystal report (yes, it's working). But the problems are the Top 5 columns and it's corresponding data. In Scores.xsd, DataColumn5 to DataColumn9 and DataColumn24 to DataColumn28 can't generate data in Crystal Report since in datatable dt, there's no same name datacolumns. Now, how can I make there columns in Crystal Report since these columns are changing depending on the Top 5.

Deleting multiple records from sql bound Datagrid

The procedures below allowed me to delete several records at once by checking the checkbox on my datagrid. The procedure was written on ASP.net but now I am using a winform on VB.net.
I have a datagrid with column name "Delete" where the checkboxes are located. The user would check
the records it wants to delete and the would delete those records. I use the "Ticket Number" column values as the parameter for my query.
The issue I have is that since was written for ASP.Net, I cannot find how the winform VB.net equivalent for this line:
Dim chkDelete As CheckBox = DirectCast(grdRoster.Rows(i).Cells(0).FindControl("Delete_Row"), CheckBox)
FindControl is not a member of System.Windows.Forms.DataGridViewCell. Plus I am pretty sure that the whole line is wrong since the checkboxes
are located on a datagrid column set as ColumnType: DataGridViewCheckBoxColumn and are not really individual controls.
How can I get the same result on a winform? Here is my entire code.
Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
'Create String Collection to store
'IDs of records to be deleted
Dim ticketNumberCollection As New StringCollection()
Dim strTicketNumber As String = String.Empty
'Loop through GridView rows to find checked rows
For i As Integer = 0 To grdRoster.Rows.Count - 1
Dim chkDelete As CheckBox = DirectCast(grdRoster.Rows(i).Cells(0).FindControl("Delete_Row"), CheckBox)
If chkDelete IsNot Nothing Then
If chkDelete.Checked Then
strTicketNumber = grdRoster.Rows(i).Cells(1).ToString
ticketNumberCollection.Add(strTicketNumber)
End If
End If
Next
'Call the method to Delete records
DeleteMultipleRecords(ticketNumberCollection)
' rebind the GridView
grdRoster.DataBind()
End Sub
' Sub to delete multiple records
' #param "idCollection" calls the string collection above
' and deletes the selected record separated by ","
Private Sub DeleteMultipleRecords(ByVal ticketNumberCollection As StringCollection)
Dim IDs As String = ""
'Create string builder to store
'delete commands separated by ,
For Each id As String In ticketNumberCollection
IDs += id.ToString() & ","
Next
Try
Dim strTicketID As String = IDs.Substring(0, IDs.LastIndexOf(","))
DataSheetTableAdapter.DeleteRecord(strTicketID)
Catch ex As Exception
Dim errorMsg As String = "Error in Deletion"
errorMsg += ex.Message
Throw New Exception(errorMsg)
Finally
Me.Close()
End Try
End Sub
for deleting multiple records from a data bound gridview you should create the DataGridViewCheckBoxColumn at run time
Dim chk As New DataGridViewCheckBoxColumn()
DataGridView1.Columns.Add(chk)
chk.HeaderText = "Select"
'then bind your datagridview with dataset
Dim sql As String = "SELECT * FROM table_name"
' Dim connection As New SqlConnection(connectionString)
conn.Open()
sCommand = New SqlCommand(sql, conn)
sAdapter = New SqlDataAdapter(sCommand)
sBuilder = New SqlCommandBuilder(sAdapter)
sDs = New DataSet()
sAdapter.Fill(sDs, "table_name")
sTable = sDs.Tables("table_name")
DataGridView1.DataSource = sDs.Tables("table_name")
'then traverse through each column and get the checked values
Try
DataGridView1.EndEdit()
For j = Me.DataGridView1.Rows.Count - 1 To 0 Step -1
If Not IsDBNull(DataGridView1.Rows(j).Cells(0).Value) Then
If DataGridView1.Rows(j).Cells(0).Value = True Then
check = True
If MessageBox.Show("Do you want to delete these records?", "Delete", MessageBoxButtons.YesNo) = DialogResult.Yes Then
For i = Me.DataGridView1.Rows.Count - 1 To 0 Step -1
If Not IsDBNull(DataGridView1.Rows(i).Cells(0).Value) Then
If DataGridView1.Rows(i).Cells(0).Value = True Then
'remove the checked columns and update datatable
DataGridView1.Rows.RemoveAt(i)
sAdapter.Update(sTable)
End If
End If
Next
Else
Return
End If
Else
End If
End If
Next
If check = False Then
MsgBox("Nothing Selected")
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try