I know this Question was already posted, but it was never really answered, or I did not understand the answer :)
My Problem is that when I call this Sub within the Thread, it takes about 4 sec to execute the code, but if I make a simple Call Sub (Like commented in Code) it takes about 450 ms.
I have a simple program with 2 Subs:
To report Progress on Main Form
To do some "For" Looping
Imports System.Data.SqlClient
Public Class Form1
Public Delegate Sub ProzentDelegate(ByVal Prozent As Double)
Dim G_I_Temp As Integer = 0
Dim G_S_Prüfziffer As String
Dim G_S_Präfix As String
Dim G_I_Zähler As Integer
Dim G_I_Stellen As Integer
Dim G_D_Step As Integer = 1
Dim G_I_Position As Integer
Dim DT_G_Prüftabelle As DataTable
Dim DR_G_Prüftabelle As DataRow
Dim thisLock As New Object
Dim conn As String = "Data Source=SR-SQLWVS;Initial Catalog=Barcode;Integrated Security=True"
Dim sourceconn As New SqlConnection(conn)
Dim adap As SqlDataAdapter
Dim cmd As SqlCommand = New SqlCommand("SELECT TOP(10) * FROM dbo.Prüf_Tabelle", sourceconn)
Dim Thrd_preview As Threading.Thread
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
sourceconn.Open()
cmd.Connection = sourceconn
End Sub
Public Sub ReportProgress(ByVal Prozent As Double)
ProgressBar1.Value = Prozent
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If RB_Thread.Checked Then
If Thrd_preview IsNot Nothing Then Thrd_preview = Nothing
Thrd_preview = New Threading.Thread(AddressOf DoSomeWork)
Thrd_preview.IsBackground = True
Thrd_preview.Start()
Else
DoSomeWork()
End If
End Sub
Private Sub DoSomeWork()
Dim ds As New DataSet
DT_G_Prüftabelle = ds.Tables.Add("Prüf_Tabelle")
Dim L_I_Counter, L_I_Counter2 As Integer
Dim L_I_Ende As Integer
Dim L_I_Step As Integer
Dim L_I_Nutzen As Integer = 1
L_I_Step = 1
L_I_Ende = Val(TB_Auftrag_neu_Anzahl.Text)
G_I_Stellen = 8
G_S_Prüfziffer = "1"
G_S_Präfix = "00"
If TB_Info_Increment.Text = "" Then TB_Info_Increment.Text = 1
adap = New SqlDataAdapter("SELECT TOP(10) * FROM dbo.Prüf_Tabelle", sourceconn)
adap.FillSchema(DT_G_Prüftabelle, SchemaType.Mapped)
DT_G_Prüftabelle.Rows.Clear()
Dim pre As Date = Now
For L_I_Counter = 1 To (L_I_Ende * L_I_Step) Step L_I_Step
For L_I_Counter2 = 1 To L_I_Nutzen
DR_G_Prüftabelle = DT_G_Prüftabelle.NewRow
DR_G_Prüftabelle.Item("Auftrag_Lfd_nr") = TB_KeyLot.Text
DR_G_Prüftabelle.Item("Position") = G_I_Position
G_I_Position += G_D_Step
DR_G_Prüftabelle.Item("Barcode_soll") = F_Berechnung((Trim(Str(Val(TB_Auftrag_neu_Von.Text) + L_I_Counter - 1))).PadLeft(G_I_Stellen, "0"))
DT_G_Prüftabelle.Rows.Add(DR_G_Prüftabelle)
If ProgressBar1.InvokeRequired Then
ProgressBar1.BeginInvoke(New ProzentDelegate(AddressOf ReportProgress), (L_I_Counter * 100) / (L_I_Ende * L_I_Step))
Else
ReportProgress((L_I_Counter * 100) / (L_I_Ende * L_I_Step))
End If
Next
Next
MsgBox(Now.Subtract(pre).TotalMilliseconds.ToString & " ms.")
End Sub
Function F_Berechnung(ByVal L_Nummer As String) As String
Dim L_B_Gerade As Boolean = False
Dim L_I_Prüfziffer As Integer
Dim L_I_Stellen As Integer
Me.G_I_Temp = 0
Select Case G_S_Prüfziffer
Case "0"
F_Berechnung = L_Nummer
Case "1"
F_Berechnung = G_S_Präfix & Trim(L_Nummer)
Case "2"
F_Berechnung = G_S_Präfix & Trim(L_Nummer)
Case "3"
F_Berechnung = L_Nummer
'
Case "5" '-----Mod 10 gewichtung 31...-----
L_Nummer = G_S_Präfix & Trim(L_Nummer)
L_I_Stellen = Len(L_Nummer)
For Me.G_I_Zähler = L_I_Stellen To 1 Step -1
Me.G_I_Temp += Val(Mid(L_Nummer, Me.G_I_Zähler, 1)) * IIf(L_B_Gerade, 1, 3)
L_B_Gerade = Not L_B_Gerade
Next
L_I_Prüfziffer = IIf(10 - Me.G_I_Temp Mod 10 = 10, 0, 10 - Me.G_I_Temp Mod 10)
F_Berechnung = Trim(L_Nummer) & Trim(Str(L_I_Prüfziffer))
'
Case "6" '-----Mod 10 gewichtung 13...-----
L_Nummer = G_S_Präfix & Trim(L_Nummer)
L_I_Stellen = Len(L_Nummer)
For Me.G_I_Zähler = L_I_Stellen To 1 Step -1
Me.G_I_Temp += Val(Mid(L_Nummer, Me.G_I_Zähler, 1)) * IIf(L_B_Gerade, 3, 1)
L_B_Gerade = Not L_B_Gerade
Next
L_I_Prüfziffer = IIf(10 - Me.G_I_Temp Mod 10 = 10, 0, 10 - Me.G_I_Temp Mod 10)
F_Berechnung = Trim(L_Nummer) & Trim(Str(L_I_Prüfziffer))
'
Case Else
F_Berechnung = L_Nummer
End Select
End Function
I have tried to take out Progress Reporting but the Result is the same.
I hope you have some suggestions or solutions for me. I would be very thankful.
Give these changes a try
Change this
If ProgressBar1.InvokeRequired Then
ProgressBar1.Invoke(New ProzentDelegate(AddressOf ReportProgress), Progr)
Else
ReportProgress(Progr)
End If
to
ReportProgress(Progr)
And change method ReportProgress to
Public Sub ReportProgress(ByVal Prozent As Double)
Me.BeginInvoke(Sub()
ProgressBar1.Value = Prozent
End Sub)
End Sub
See if that makes a difference. The check for InvokeRequired is not needed, the answer is always yes.
Just wanted to report that I found a solution.
The main problem was this line of code in:
DR_G_Prüftabelle.Item("Auftrag_Lfd_nr") = TB_KeyLot.Text
So if I start this Sub from another Thread rather than from a Main Thread, for every single loop it has to go to main thread and to take Paramater from TextBox and to go back in Thread to Loop further.
I took that out, declared a variable at the begining and assigned this TextBox value to it and it works like charm.
Also I took a suggestion from dbasnett to Invoke Reporting every time without If-Else and also the suggestion from Steven Doggart to Report every 100 Loops.
You guys helped a lot. Thanks for that!!
Related
good day!
Tell me how you can quickly ping the entire network?
There is the following code that scans the network.
Public Sub Scan(ByVal subnet As String)
Dim myPing As Ping
Dim reply As PingReply
Dim addr As IPAddress
Dim host As IPHostEntry
Dim active_addr As Integer = 0
ProgressBar1.Maximum = 254
ProgressBar1.Value = 0
ListView1.Items.Clear()
For i As Integer = 1 To 254
Dim subnetn As String = "." & i.ToString()
myPing = New Ping()
reply = myPing.Send(subnet & subnetn, 900)
Label3.ForeColor = Color.Green
Label3.Text = "Scan: " & subnet & subnetn
If reply.Status = IPStatus.Success Then
Try
addr = IPAddress.Parse(subnet & subnetn)
host = Dns.GetHostEntry(addr)
If My.Computer.Network.Ping(host.HostName, 10) Then
ListView1.Items.Add(New ListViewItem(New String() {subnet & subnetn, host.HostName, "True"}))
Else
ListView1.Items.Add(New ListViewItem(New String() {subnet & subnetn, host.HostName, "False"}))
End If
Catch
ListView1.Items.Add(New ListViewItem(New String() {subnet & subnetn, " ", "False"}))
End Try
active_addr += 1
End If
ProgressBar1.Value += 1
Label5.Text = Math.Round((ProgressBar1.Value * 100) / 254, 0, MidpointRounding.AwayFromZero) & " %"
')
ListView1.Items((ListView1.Items.Count - 1)).EnsureVisible()
ListView1.Items((ListView1.Items.Count - 1)).Selected = True
Next i
ListView1.Items(0).Focused = True
ListView1.Items(0).Selected = True
End Sub
But it takes a very long time to scan the network. Tell me, is it possible to do it faster?
And can I add the device's MAC address when scanning the network?
================================================================
Found a solution that quickly scans the network (a given range of ip addresses).
Tell me. how to add to this code to display the hostname and the MAC address? and add a ProgressBar to show the scan percentage.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Ping("192.168.1.28", "175")
End Sub
Private Async Function Ping(startIP As String, endIP As String) As Task
Dim start As IPAddress = IPAddress.Parse(startIP)
Dim bytes = start.GetAddressBytes()
Dim leastSigByte = start.GetAddressBytes().Last
Dim range = endIP - leastSigByte
Dim pingReplyTasks = Enumerable.Range(leastSigByte, range).Select(Function(x)
Dim p = New Ping()
Dim bb = start.GetAddressBytes()
bb(3) = CByte(x)
Dim destIp = New IPAddress(bb)
Dim pingResultTask = p.SendPingAsync(destIp)
Return New With {
Key pingResultTask,
Key .addr = destIp
}
End Function).ToList()
Await Task.WhenAll(pingReplyTasks.Select(Function(x) x.pingResultTask))
For Each pr In pingReplyTasks
Dim tsk = pr.pingResultTask
Dim pingResult = tsk.Result
Dim ip = pr.addr
'
DataGridView1.Rows.Add(ip, pingResult.RoundtripTime, pingResult.Status)
Next pr
End Function
So I've used visual basics (vb.net) for a bit now and understand some stuff. Right now I want to make a maths quiz that when I click a button it takes me to a new form and starts the quiz. When the quiz starts I want it so it gives the user random numbers and the user needs to answer it in a textbox and if correct it moves on to the next question (Basic, I should be able to do). IMPORTANT - my question is, there's a maths rule called BODMAS (Bracket.Order.Division.Multiply.Add.Subtract) and I want to add this rule into my coding instead of doing regular simple maths...
EXAMPLE question is 2 x (2+3) - 1 = ?
2 x 5 - 1 = ?
10 - 1 = ?
9 = 9
person writes answer to textbox and moves to next similar question
This is my first time using this but I wanted to write in-depth so people can understand. Please help me if you find a video explaining what I'm looking for or if someone has a file with a similar code I could download would be greatly appreciated!
Basically,you need to determine the range of numbers you use, and then match them randomly among '*', '/', '+', '-'. Then randomly insert brackets into it.
Private codeStr As String
Private Function GenerateMathsQuiz() As String
Dim r As Random = New Random()
Dim builder As StringBuilder = New StringBuilder()
'The maximum number of operations is five, and you can increase the number [5] to increase the difficulty
Dim numOfOperand As Integer = r.[Next](1, 5)
Dim numofBrackets As Integer = r.[Next](0, 2)
Dim randomNumber As Integer
For i As Integer = 0 To numOfOperand - 1
'All numbers will be random between 1 and 10
randomNumber = r.[Next](1, 10)
builder.Append(randomNumber)
Dim randomOperand As Integer = r.[Next](1, 4)
Dim operand As String = Nothing
Select Case randomOperand
Case 1
operand = "+"
Case 2
operand = "-"
Case 3
operand = "*"
Case 4
operand = "/"
End Select
builder.Append(operand)
Next
randomNumber = r.[Next](1, 10)
builder.Append(randomNumber)
If numofBrackets = 1 Then
codeStr = InsertBrackets(builder.ToString())
Else
codeStr = builder.ToString()
End If
Return codeStr
End Function
Public Function InsertBrackets(ByVal source As String) As String
Dim rx As Regex = New Regex("\d+", RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim matches As MatchCollection = rx.Matches(source)
Dim count As Integer = matches.Count
Dim r As Random = New Random()
Dim numIndexFirst As Integer = r.[Next](0, count - 2)
Dim numIndexLast As Integer = r.[Next](1, count - 1)
While numIndexFirst >= numIndexLast
numIndexLast = r.[Next](1, count - 1)
End While
Dim result As String = source.Insert(matches(numIndexFirst).Index, "(")
result = result.Insert(matches(numIndexLast).Index + matches(numIndexLast).Length + 1, ")")
Return result
End Function
When you finish this, you will get a math quiz, then you need to know how to compile and run code at runtime.
Private Function GetResult(ByVal str As String) As String
Dim sb As StringBuilder = New StringBuilder("")
sb.Append("Namespace calculator" & vbCrLf)
sb.Append("Class calculate " & vbCrLf)
sb.Append("Public Function Main() As Integer " & vbCrLf)
sb.Append("Return " & str & vbCrLf)
sb.Append("End Function " & vbCrLf)
sb.Append("End Class " & vbCrLf)
sb.Append("End Namespace" & vbCrLf)
Dim CompilerParams As CompilerParameters = New CompilerParameters()
CompilerParams.GenerateInMemory = True
CompilerParams.TreatWarningsAsErrors = False
CompilerParams.GenerateExecutable = False
CompilerParams.CompilerOptions = "/optimize"
Dim references As String() = {"System.dll"}
CompilerParams.ReferencedAssemblies.AddRange(references)
Dim provider As VBCodeProvider = New VBCodeProvider()
Dim compile As CompilerResults = provider.CompileAssemblyFromSource(CompilerParams, sb.ToString())
If compile.Errors.HasErrors Then
Dim text As String = "Compile error: "
For Each ce As CompilerError In compile.Errors
text += "rn" & ce.ToString()
Next
Throw New Exception(text)
End If
Dim Instance = compile.CompiledAssembly.CreateInstance("calculator.calculate")
Dim type = Instance.GetType
Dim methodInfo = type.GetMethod("Main")
Return methodInfo.Invoke(Instance, Nothing).ToString()
End Function
Finally, you can use these methods like:
Private Sub GetMathQuizBtn_Click(sender As Object, e As EventArgs) Handles GetMathQuizBtn.Click
Label1.Text = GenerateMathsQuiz()
End Sub
Private Sub ResultBtn_Click(sender As Object, e As EventArgs) Handles ResultBtn.Click
If TextBox1.Text = GetResult(Label1.Text) Then
MessageBox.Show("bingo!")
TextBox1.Text = ""
Label1.Text = GenerateMathsQuiz()
Else
MessageBox.Show("result is wrong")
End If
End Sub
Result:
I have a code to color the cells in a datagridview based on defined criteria for several different pollutants, and it works well. However, there will often be occurrences of the character '<' in cases like "<0.005", meaning "below detection limit", and that crashes the routine with the message "Operator '<' is not defined for type 'DBNull' and type 'Double'."
Edit: This is the latest code as supplied by JohnG. I still get error messages when the subs encounter empty cells or invalid characters
Imports System.Data.SqlClient
Imports System.IO
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Public Class Form1
Public Property gridResults As Object
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
OpenFileDialog2.Title = "Velg fil ..."
OpenFileDialog2.InitialDirectory = "C:users\<currentuser>\Documents"
OpenFileDialog2.Filter = "Alle filer|*.*|Excel 2003|*.xls|Excel|*.xlsx"
OpenFileDialog2.FilterIndex = 2
OpenFileDialog2.ShowDialog()
End Sub
Private Sub OpenFileDialog2_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog2.FileOk
Dim strm As System.IO.Stream
strm = OpenFileDialog2.OpenFile()
TextBox2.Text = OpenFileDialog2.FileName.ToString()
If Not (strm Is Nothing) Then
strm.Close()
End If
Me.Button5_Click(sender, e)
End Sub
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
If String.IsNullOrEmpty(TextBox2.Text) Then
MessageBox.Show("Klikk ""Bla gjennom"" for å velge en fil", "Ingen inndatafil")
Exit Sub
End If
Dim FilePath As String = OpenFileDialog2.FileName
Dim MyConnection As System.Data.OleDb.OleDbConnection
Dim DtSet As System.Data.DataSet
Dim MyCommand As System.Data.OleDb.OleDbDataAdapter
MyConnection = New System.Data.OleDb.OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & FilePath & ";Extended Properties=Excel 8.0;")
MyCommand = New System.Data.OleDb.OleDbDataAdapter("select * from [Sheet1$]", MyConnection)
MyCommand.TableMappings.Add("Table", "Net-informations.com")
DtSet = New System.Data.DataSet
MyCommand.Fill(DtSet)
DataGridView2.DataSource = DtSet.Tables(0)
MyConnection.Close()
End Sub
Public Function GetElementColorsValues(elementName As String) As Decimal()
Dim ULArray(4) As Decimal
Select Case elementName
Case "As (Arsen)"
ULArray(0) = 8
ULArray(1) = 20
ULArray(2) = 50
ULArray(3) = 600
ULArray(4) = 1000
Case "Cd (Kadmium)"
ULArray(0) = 1.5
ULArray(1) = 10
ULArray(2) = 15
ULArray(3) = 30
ULArray(4) = 1000
Case "Cu (Kopper)"
ULArray(0) = 100
ULArray(1) = 200
ULArray(2) = 1000
ULArray(3) = 8500
ULArray(4) = 25000
Case "Cr (Krom)"
ULArray(0) = 50
ULArray(1) = 200
ULArray(2) = 500
ULArray(3) = 2800
ULArray(4) = 25000
Case "Hg (Kvikksølv)"
ULArray(0) = 1
ULArray(1) = 2
ULArray(2) = 4
ULArray(3) = 10
ULArray(4) = 1000
Case "Ni (Nikkel)"
ULArray(0) = 60
ULArray(1) = 135
ULArray(2) = 200
ULArray(3) = 1200
ULArray(4) = 2500
Case "Pb (Bly)"
ULArray(0) = 60
ULArray(1) = 100
ULArray(2) = 300
ULArray(3) = 700
ULArray(4) = 2500
Case "Zn (Sink)"
ULArray(0) = 200
ULArray(1) = 500
ULArray(2) = 1000
ULArray(3) = 5000
ULArray(4) = 25000
End Select
Return ULArray
End Function
'Fargeleggingsrutine - gir feilmelding
Private Sub SetDGVColColor()
Dim ULArray As Decimal()
Dim curValue As String
Dim decimalValue As Decimal
Dim colName = ""
For col As Integer = 2 To DataGridView2.ColumnCount - 1
colName = DataGridView2.Columns(col).Name
ULArray = GetElementColorsValues(colName)
For Each row As DataGridViewRow In DataGridView2.Rows
If (Not row.IsNewRow) Then
curValue = row.Cells(colName).Value
If (curValue IsNot Nothing) Then
Decimal.TryParse(curValue, decimalValue)
' the above TryParse line will set decimalValue to 0 if curValue is not a valid decimal i.e `<0.005`
Select Case decimalValue
Case >= ULArray(4)
row.Cells(colName).Style.BackColor = Color.BlueViolet
Case >= ULArray(3)
row.Cells(colName).Style.BackColor = Color.Red
Case >= ULArray(2)
row.Cells(colName).Style.BackColor = Color.Orange
Case >= ULArray(1)
row.Cells(colName).Style.BackColor = Color.Yellow
Case >= ULArray(0)
row.Cells(colName).Style.BackColor = Color.LawnGreen
Case Else
row.Cells(colName).Style.BackColor = Color.DodgerBlue
End Select
End If ' ignore empty cell
End If ' ignore the new row
Next
Next
End Sub
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
SetDGVColColor()
End Sub
'Første svar fra JohnG
'Fjerde forsøk på eksport
Private Sub ExportToExcel()
Dim excel As Microsoft.Office.Interop.Excel._Application = New Microsoft.Office.Interop.Excel.Application()
Dim workbook As Microsoft.Office.Interop.Excel._Workbook = excel.Workbooks.Add(Type.Missing)
Dim worksheet As Microsoft.Office.Interop.Excel._Worksheet = Nothing
excel.Visible = True
Try
worksheet = workbook.ActiveSheet
worksheet.Name = "ExportedFromDataGrid"
Dim cellRowIndex As Integer = 1
Dim cellColumnIndex As Integer = 1
'gets header rows.
For Each column In DataGridView2.Columns
worksheet.Cells(1, column.Index + 1).Value = column.Name
Next
'gets all other rows
Dim rowIndex = 2
For Each row As DataGridViewRow In DataGridView2.Rows
If Not row.IsNewRow Then
For colIndex As Integer = 0 To DataGridView2.Columns.Count - 1
worksheet.Cells(rowIndex, colIndex + 1).Value = row.Cells(colIndex).Value.ToString
Next
End If
rowIndex += 1
Next
' Substituted code below that loops through each column with data
' then sets the color for each of those columns by calling the SetColColor method
For index As Integer = 2 To DataGridView2.Columns.Count
Dim colName = DataGridView2.Columns(index).Name
SetExcelColColor(worksheet, colName, index + 1)
Next
MessageBox.Show("Closing excel: save if needed!")
'workbook.SaveAs("YourFileName..",)
workbook.Close()
excel.Quit()
Marshal.ReleaseComObject(worksheet)
Marshal.ReleaseComObject(workbook)
Marshal.ReleaseComObject(excel)
Catch
MessageBox.Show("Error")
End Try
End Sub
'andre eksportrutine med fargelegging fra JohnG
Private Sub SetExcelColColor(worksheet As Microsoft.Office.Interop.Excel._Worksheet, colName As String, colIndex As Integer)
Dim rIndex = 2
Dim cIndex = colIndex
Dim ULArray = GetElementColorsValues(colName)
Dim curValue As String
Dim decimalValue As Decimal
For Each row As DataGridViewRow In DataGridView2.Rows
If (Not row.IsNewRow) Then
curValue = row.Cells(colName).Value
If (curValue IsNot Nothing) Then
Decimal.TryParse(curValue, decimalValue)
Select Case decimalValue
Case >= ULArray(4)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.BlueViolet)
Case >= ULArray(3)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red)
Case >= ULArray(2)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Orange)
Case >= ULArray(1)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Yellow)
Case >= ULArray(0)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LawnGreen)
Case Else
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.DodgerBlue)
End Select
rIndex += 1
End If ' ignore empty cell
End If ' ignore new row
Next
End Sub
Private Sub btnBrowse_Click(sender As Object, e As EventArgs) Handles btnBrowse.Click
Me.ExportToExcel()
End Sub
Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
System.Windows.Forms.Application.Exit()
End Sub
End Class
I am not completely sure if I follow what you are asking so correct me if I am wrong. I am guessing the value “<0.005” is a value in a DataGridView Cell. If this is the case then you will need to change this “String” value to a “Decimal” The previous code I supplied did not check for empty or invalid numbers before the comparison is made. Since the cell value could be anything, the code needs to check for two things: An empty or null cell value or an invalid number. The error you are getting could be coming from either case.
Your comment
How can I make the routine disregard the < character, replace it with "" or replace the entire string with zero?
In this case when the cell contains the value “<0.005” will throw the error you see because comparing a string to a double won’t work. Since you state above that setting this value to zero (0) is sufficient, then I recommend you use a TryParse method. If the TryParse method is given an invalid number it will return zero (0). You could use this knowledge to implement what you describe.
I would recommend you use the same strategy you used to color the Excel cells. I changed the GetElementColorsValues method to return a Decimal array. This change is necessary if the values in the DataGridView are decimal values.
Public Function GetElementColorsValues(elementName As String) As Decimal()
Dim ULArray(4) As Decimal
Select Case elementName
Case "Arsenic"
ULArray(0) = 8
ULArray(1) = 20
ULArray(2) = 50
ULArray(3) = 600
ULArray(4) = 1000
Case "Cadmium"
ULArray(0) = 1.5
ULArray(1) = 10
………..
Now with this array we can compare the decimal values in the DataGridView. I used a Decimal.TryParse to get the Decimal value from a cells string value like below
Decimal.TryParse(curValue, decimalValue)
Above curValue is a string from the DataGridView cell and decimalValue is the retuned Decimal value from parsing the string to a decimal. The whole line Decimal.TryParse(curValue, decimalValue) will return true if the parse was successful and false if not successful.
The convenient aspect of this is that if the parse is unsuccessful (like with a value of <0.005) the TryParse will set the variable decimalValue to zero (0) as you are asking. Simply using the Decimal.TryParse will set the variable decimalValue to zero when it fails and will set it to a valid decimal number if it succeeds. This can be seen in the code below which checks for null or empty values then, if not null or empty uses the Decimal.TryParse to get the decimal value to be used in the comparison for coloring. It uses the same GetElementColorsValues(colName) method used when coloring the Excel cells... you will have to change the excel coloring code also to accommodate the Decimal array… below this method)
Update Edit to catch BDNULL cells in the data table
I was incorrect and technically, you CAN have a row in a DataTable that contains no column data. So the line: row.Cells(colName).Value will obviously throw the error you are getting. I am not saying this is the problem, but that was the only way I could reproduce your error. So the code below checks for these missing columns of data. I changed the code to use DataBoundItems since you are using this in your code; below that is the change needed without using the data bound item. Both worked, however if feel that may not be the case if the table is sorted or rows deleted etc. My next question would be why you would read these empty rows into the data table if they were well… EMPTY?
Obviously, you will need to make these changes when writing the grid to excel.
Private Sub SetDGVColColor()
Dim ULArray As Decimal()
Dim curValue As String
Dim decimalValue As Decimal
Dim colName = ""
For col As Integer = 2 To dgvElements.ColumnCount - 1
colName = dgvElements.Columns(col).Name
ULArray = GetElementColorsValues(colName)
Dim curDataBoundRow
For Each row As DataGridViewRow In dgvElements.Rows
If (Not row.IsNewRow) Then
curDataBoundRow = row.DataBoundItem ' <-- Added Code
If (Not IsDBNull(curDataBoundRow(colName))) Then ' <-- Added Code
curValue = curDataBoundRow(colName)
If (curValue IsNot Nothing) Then
Decimal.TryParse(curValue, decimalValue)
' the above TryParse line will set decimalValue to 0 if curValue is not a valid decimal i.e `<0.005`
Select Case decimalValue
Case >= ULArray(4)
row.Cells(colName).Style.BackColor = Color.BlueViolet
Case >= ULArray(3)
row.Cells(colName).Style.BackColor = Color.Red
Case >= ULArray(2)
row.Cells(colName).Style.BackColor = Color.Orange
Case >= ULArray(1)
row.Cells(colName).Style.BackColor = Color.Yellow
Case >= ULArray(0)
row.Cells(colName).Style.BackColor = Color.LawnGreen
Case Else
row.Cells(colName).Style.BackColor = Color.DodgerBlue
End Select
End If ' cell is empty
End If ' ignore null cells in data table <-- Added Code
End If ' ignore the new row if present
Next
Next
End Sub
Changes to code without using data bound items.
…….
For Each row As DataGridViewRow In dgvElements.Rows
If (Not row.IsNewRow) Then
If (Not IsDBNull(row.Cells(colName).Value)) Then ' <-- ADDED code
curValue = row.Cells(colName).Value
If (curValue IsNot Nothing) Then
…….
Changes to color excel cells method using Decimal value comparisons.
Private Sub SetExcelColColor(worksheet As Microsoft.Office.Interop.Excel._Worksheet, colName As String, colIndex As Integer)
Dim rIndex = 2
Dim cIndex = colIndex
Dim ULArray = GetElementColorsValues(colName)
Dim curValue As String
Dim decimalValue As Decimal
For Each row As DataGridViewRow In dgvElements.Rows
If (Not row.IsNewRow) Then
curValue = row.Cells(colName).Value
If (curValue IsNot Nothing) Then
Decimal.TryParse(curValue, decimalValue)
Select Case decimalValue
Case >= ULArray(4)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.BlueViolet)
Case >= ULArray(3)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red)
Case >= ULArray(2)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Orange)
Case >= ULArray(1)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Yellow)
Case >= ULArray(0)
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LawnGreen)
Case Else
worksheet.Cells(rIndex, cIndex).Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.DodgerBlue)
End Select
rIndex += 1
End If ' ignore empty cell
End If ' ignore new row
Next
End Sub
The error you report is nothing to do with the presence of "<" in your string. It's because you're trying to an actual less-than comparison on a null value. That's invalid - there's no value to compare. You need to check whether the field is null before you perform the operation, and do something else instead:
If Me.DataGridView2.Rows(i).Cells("Cd (Kadmium)").Value IsNot DBNull.Value Then
'continue with the comparisons
Else
'do something else
End If
However, you're right, the presence of "<" will also cause a problem when trying to cast the value to a Double for the comparison.
For that you can do a simple string replacement, e.g.
Dim val = Me.DataGridView2.Rows(i).Cells("Cd (Kadmium)").Value.ToString().Replace("<", "")
Dim dVal = Convert.ToDouble(val)
If dVal < Ul1Cd Then
'etc
Also check your second loop:
For i As Double = 0 To Me.DataGridView2.Rows.Count - 1
you only need
for i = 0 To Me.DataGridView2.Rows.Count - 1
since you declared it before and as double?
Also make sure to set option strict on and infer to off in project compile options.
I would like to ask for your help. I am stuck to this for more than two days, I've searched the net but unfortunately got no answer.
I have a program in vb 2008 and a database (SQL Server 2008). I have this form which contains treeview. The items display is selected from the database. When i run the program and open the form the treeview items displayed (at first), but when i closed the form and try to open it again the treeview disappear. I dont know why :( . Why is it disappearing? Can somebody help me please. Thank you.
Below is my code....
#form_load
Private Sub frmProfile_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Call conecDB()
Call initCMD()
FillTable()
CreateTree() 'create the treeview node
findNode() 'find and checked the selected nodes that was given to the profile
End Sub
'the functions
Private Sub FillTable()
'tv1.Nodes.Clear()
dtable.Columns.Add("ID", GetType(Integer))
dtable.Columns.Add("NAME", GetType(String))
dtable.Columns.Add("PARENT", GetType(Integer))
dtable.Columns.Add("LEVEL", GetType(Integer))
qSQL = "select mod_id,name,parent,level,sort,mnu_name from module where status='A' and parent!=-1"
With comDB
.CommandText = qSQL
rdDB = .ExecuteReader
End With
Do While rdDB.Read
dtable.Rows.Add(rdDB!mod_id, rdDB!name.ToString(), rdDB!parent)
My.Application.DoEvents()
Loop
For i = 0 To dtable.Rows.Count - 1
Dim ID1 As String = dtable.Rows(i).Item("ID").ToString
dtable.Rows(i).Item("LEVEL") = FindLevel(ID1, 0)
Next
rdDB.Close()
End Sub
Private Function FindLevel(ByVal ID As String, ByRef Level As Integer) As Integer
For i = 0 To dtable.Rows.Count - 1
Dim ID1 As String = dtable.Rows(i).Item("ID").ToString
Dim Parent1 As String = dtable.Rows(i).Item("PARENT").ToString
If ID = ID1 Then
If Parent1 = 0 Then
Return Level
Else
Level += 1
FindLevel(Parent1, Level)
End If
End If
Next
Return Level
End Function
Private Sub CreateTree()
tv1.Nodes.Clear()
Dim MaxLevel1 As Integer = CInt(dtable.Compute("MAX(LEVEL)", ""))
Dim i, j As Integer
For i = 0 To MaxLevel1
Dim Rows1() As DataRow = dtable.Select("LEVEL = " & i)
For j = 0 To Rows1.Count - 1
Dim ID1 As String = Rows1(j).Item("ID").ToString
Dim Name1 As String = Rows1(j).Item("NAME").ToString
'Dim mName As String = Rows1(j).Item("mNAME").ToString
Dim Parent1 As String = Rows1(j).Item("PARENT").ToString
If Parent1 = 0 Then
tv1.Nodes.Add(ID1, Name1)
Else
Dim TreeNodes1() As TreeNode = tv1.Nodes.Find(Parent1, True)
If TreeNodes1.Length > 0 Then
TreeNodes1(0).Nodes.Add(ID1, Name1)
End If
End If
Next
Next
End Sub
Private Sub findNode()
Dim rName As String = String.Empty
Dim b As Boolean = True
qSQL = "select access_id,mnu_name from profile_details where prof_id=" & lblPID.Text & ""
With comDB
.CommandText = qSQL
rdDB = .ExecuteReader
End With
Do While rdDB.Read
rName = rdDB!access_id.ToString()
Try
Dim arr As TreeNode() = tv1.Nodes.Find(rName, b)
For i = 0 To arr.Length - 1
tv1.SelectedNode = arr(i)
tv1.SelectedNode.Checked = True
Next
Catch
MsgBox(Err)
End Try
Loop
rdDB.Close()
End Sub
I am working on a Windows forms project that connects to a Microsoft Access database, reads the the file, does some math and then provides some basic statistics back. Right now I am teaching myself VB and I know the code below could be more efficient. However, right now I am just trying to make it functional.
The program filters the data it needs via sql, and there are several sql statements. I separated the code for each of the sql statements and into a subroutine so that I could call each one when the form loads and also when the user clicks a button to update. The program works fine on the form load, however, when you click the update button you get the following error on the 'odaCalls.Fill' in subroutine Count(): "The select command property has not been initialized before calling 'Fill'.
Any help is greatly appreciated. I have searched on google and tried the suggestions found there but have not found a fix.
Option Explicit On
Public Class Form1
'Count() Variables
Dim strSQL = "SELECT * FROM tblcallLog"
Dim strPath As String = "Provider=Microsoft.ACE.OLEDB.12.0 ;" _
& "Data Source=C:\callLogRev2_be.accdb"
Dim odaCalls As New OleDb.OleDbDataAdapter(strSQL, strPath)
Dim datCallCount As New DataTable
Dim intCount As Integer = 0
'LiveCalls() variables
Dim strSQLLive As String = "SELECT * FROM tblcallLog WHERE callLive=True"
Dim odaCallsLive As New OleDb.OleDbDataAdapter(strSQLLive, strPath)
Dim datCallLive As New DataTable
Dim intCallLiveCount As Integer = 0
Dim decCallLivePct As Decimal
'TransferCalls() variables
Dim strSQLTransfered As String = _
"SELECT * FROM tblcallLog WHERE callName LIKE '% transfer %' OR callName LIKE 'transfer%'"
Dim odaCallsTransfered As New OleDb.OleDbDataAdapter(strSQLTransfered, strPath)
Dim datCallTransfered As New DataTable
Dim intCallTransfered As Integer = 0
Dim decCallTranfered As Decimal
'SingleStaffCall() Variables
Dim strSQLSingleStaff As String = _
"SELECT * FROM tblcallLog WHERE callName LIKE '% single %' OR callName LIKE 'single%'"
Dim odaCallSingleStaff As New OleDb.OleDbDataAdapter(strSQLSingleStaff, strPath)
Dim datCallSingleStaff As New DataTable
Dim intCallSingleStaff As Integer = 0
Dim decCallSingleStaff As Decimal
'SingleStaffCallsLive() Variables
Dim strSQLSingleStaffLive As String = _
"SELECT * FROM tblcallLog WHERE callName LIKE '% single %' OR callName LIKE 'single%' AND callLive=True"
Dim odaCallSingleStaffLive As New OleDb.OleDbDataAdapter(strSQLSingleStaffLive, strPath)
Dim datCallSingleStaffLive As New DataTable
Dim intCallSingleStaffLive As Integer = 0
Dim decCallSingleStaffLive As Decimal
'CallToday() Variables
Dim strSQLToday As String = _
"SELECT * FROM tblcallLog WHERE startDate = date()"
Dim odaCallToday As New OleDb.OleDbDataAdapter(strSQLToday, strPath)
Dim datCallToday As New DataTable
Dim intCallToday As New Integer
'CallTodayLive() Variables
Dim strSQLTodayLiveCalls As String = _
"SELECT * FROM tblcallLog WHERE callLive=TRUE AND startDate = date()"
Dim odaCallTodayLive As New OleDb.OleDbDataAdapter(strSQLTodayLiveCalls, strPath)
Dim datCallTodayLive As New DataTable
Dim intCallTodayLive As New Integer
Dim decCallTodayLive As New Decimal
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Count()
LiveCalls()
TransferCalls()
SingleStaffCalls()
SingleStaffCallsLive()
CallToday()
CallTodayLive()
End Sub
Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
'Checks the database for updates when user pushes the update button on the static data tab.
Count()
LiveCalls()
TransferCalls()
SingleStaffCalls()
SingleStaffCallsLive()
CallToday()
CallTodayLive()
End Sub
Private Sub Count()
'database connect and call count
odaCalls.Fill(datCallCount)
odaCalls.Dispose()
intCount = datCallCount.Rows.Count
lblTotalCallsData.Text = intCount.ToString
lblTotalCallsData.Visible = True
End Sub
Private Sub LiveCalls()
'determine number of live calls
odaCallsLive.Fill(datCallLive)
odaCallsLive.Dispose()
intCallLiveCount = datCallLive.Rows.Count
lblcallsLiveData.Text = intCallLiveCount.ToString
lblcallsLiveData.Visible = True
decCallLivePct = intCallLiveCount / intCount
lblPctCallsLiveData.Text = decCallLivePct.ToString("P")
lblPctCallsLiveData.Visible = True
End Sub
Private Sub TransferCalls()
'determine the number of transfer calls
odaCallsTransfered.Fill(datCallTransfered)
odaCallsTransfered.Dispose()
intCallTransfered = datCallTransfered.Rows.Count
lblTotalTransferCallsData.Text = intCallTransfered.ToString
lblTotalTransferCallsData.Visible = True
decCallTranfered = intCallTransfered / intCount
lblPctTransferCallsData.Text = decCallTranfered.ToString("P")
lblPctTransferCallsData.Visible = True
End Sub
Private Sub SingleStaffCalls()
'determine the number of single staff calls and percentage of total
odaCallSingleStaff.Fill(datCallSingleStaff)
odaCallSingleStaff.Dispose()
intCallSingleStaff = datCallSingleStaff.Rows.Count
lblTotalSingleStaffCallData.Text = intCallSingleStaff.ToString
lblTotalSingleStaffCallData.Visible = True
decCallSingleStaff = intCallSingleStaff / intCount
lblPctSingleStaffCallsData.Text = decCallSingleStaff.ToString("P")
End Sub
Private Sub SingleStaffCallsLive()
'determine the percentage of single staff calls taken live
odaCallSingleStaffLive.Fill(datCallSingleStaffLive)
odaCallSingleStaffLive.Dispose()
intCallSingleStaffLive = datCallSingleStaffLive.Rows.Count
decCallSingleStaffLive = intCallSingleStaffLive / intCount
lblPctSingleStaffCallsLiveData.Visible = True
lblPctSingleStaffCallsLiveData.Text = decCallSingleStaffLive.ToString("P")
End Sub
Private Sub CallToday()
'determine values for todays date
odaCallToday.Fill(datCallToday)
odaCallToday.Dispose()
intCallToday = datCallToday.Rows.Count
lblTotalCallsTodayData.Text = intCallToday
lblTotalCallsTodayData.Visible = True
End Sub
Private Sub CallTodayLive()
'determine the number of live calls today
odaCallTodayLive.Fill(datCallTodayLive)
odaCallTodayLive.Dispose()
intCallTodayLive = datCallTodayLive.Rows.Count
lblCallsTodayLiveData.Text = intCallTodayLive.ToString
lblCallsTodayLiveData.Visible = True
'Statement to error correct so the database doesn't force the program to divide by zero
Try
decCallTodayLive = intCallTodayLive / intCallToday
Catch Exception As DivideByZeroException
lblPctCallsTodayLiveData.Text = "0.00%"
lblPctCallsTodayLiveData.Visible = True
Catch Exception As OverflowException
decCallTodayLive = 0
End Try
lblPctCallsTodayLiveData.Text = decCallTodayLive.ToString("P")
lblPctCallsTodayLiveData.Visible = True
End Sub
End Class
The problem is that you are disposing the dataadapters immediately after filling them.
This is why it works on form load, but not after. It would be better practice to create the and destroy the dataadapters in the methods where they are used instead of creating them on spec at the form level.