¿How to get the exact address of a cell? (VB.NET/INTEROP.EXCEL) - vb.net

Yes. I am using a library that almost nobody likes (COM / Interop). I am practicing doing a program that analize an Excel workbook, identify its columns and the user dials the type of each. Everything serves perfect, I can detect errors in the type of each column (for example if there is a string in a numeric column) but the only type that I am'm having problems is with dates. I asked a question here yesterday regarding dates (because I thought something) but I know from that question that dates are just numbers .... This is no problem because I can use Date.fromOADate.
Well, the situation I face is that if an Excel column contains information of dates and for example, you add a data string in that column of dates, when loading the Excel book in the program, that data string did not mark it as an error .. . but treats it as an empty cell (Thing that has surprised me).
this is the function that I wrote to mark the errors of each column
Protected Friend Function obtenerErroresColumna(ByVal column As String, ByVal page As String, ByVal tipe As String) As Integer
If (Not String.IsNullOrEmpty(column)) Then
Dim cmd As String = "Select [" & column & "] from [" & page & "$]"
Dim errors As Integer = 0
Dim table As New DataTable
Try
Dim adapter As New OleDbDataAdapter(cmd, conexion)
adapter.Fill(table)
adapter.Dispose()
For Each itm In table.Rows
If (tipe.Equals("String")) Then
If (Not IsDBNull(itm(0))) Then
If (IsNumeric(itm(0))) Then
errors += 1
setValueError = itm(0)
End If
End If
ElseIf (tipe.Equals("Numeric")) Then
If (Not IsDBNull(itm(0))) Then
If (Not IsNumeric(itm(0))) Then
errors += 1
setValueError = itm(0)
End If
End If
ElseIf (tipe.Equals("Date")) Then
If (Not IsDBNull(itm(0))) Then
If (Not IsDate(itm(0))) Then
errors += 1
setValueError = itm(0)
End If
End If
End If
Next
table.Dispose()
Return errors
Catch ex As Exception
boxMessage("Error", ex.Message, My.Resources._error).ShowDialog()
Return errors
End Try
Else
Return 0
End If
End Function
Ok, as I said the first two types is running good, the problem is when I start to compare date data type. I have this idea if the column is date type: If the program returns an empty cell (as I said earlier, the string data returns me as empty cells) then the program obtains the address of the cell to make a replacement. I have already written the method for substitution ... only as parameters would have to pass is today's date, the exact address of the cell and the column name.
I would like to check the adress of the current cell of the loop when the variable "itm" is Null (A4, B3, C50.... Etc)

I don't see any reference to Excel.Interop in your code. For the first 26 columns you can use Chr :
Dim adr = Function(col%, row%) Chr(64 + col) & row
Dim B3 = adr(2, 3) ' "B3"

Ok guys, I found the solution of this problem. I didnt use interop but I get what I wanted.
First I needed to get the letter according to the column name. I found the web a function that returns the column letters of excel by passing as a parameter one number
Private Function ColumnIndexToColumnLetter(colIndex As Integer) As String
Dim div As Integer = colIndex
Dim colLetter As String = String.Empty
Dim modnum As Integer = 0
While div > 0
modnum = (div - 1) Mod 26
colLetter = Chr(65 + modnum) & colLetter
div = CInt((div - modnum) \ 26)
End While
Return colLetter
End Function
I insert a counter in the function that detects errors, this counter would count the cells in the column while to get the column number, I create another function that carried the columns in a arrayList.
I take the indexOf function
Protected Friend Function obtenerErroresColumna(ByVal columna As String, ByVal hoja As String, ByVal tipo As String) As Integer
If (Not String.IsNullOrEmpty(columna)) Then
Dim cmd As String = "Select [" & columna & "] from [" & hoja & "$]"
Dim errores As Integer = 0
Dim tabla As New DataTable
Dim cell As Integer = 2
Dim column As New ArrayList
column = cargarMatrizColumnas(hoja)
Try
Dim adapter As New OleDbDataAdapter(cmd, conexion)
adapter.Fill(tabla)
adapter.Dispose()
For Each itm In tabla.Rows
If (tipo.Equals("Cadena")) Then
If (Not IsDBNull(itm(0))) Then
If (IsNumeric(itm(0))) Then
errores += 1
setValoresError = itm(0)
End If
End If
ElseIf (tipo.Equals("Numerico")) Then
If (Not IsDBNull(itm(0))) Then
If (Not IsNumeric(itm(0))) Then
errores += 1
setValoresError = itm(0)
End If
End If
ElseIf (tipo.Equals("Fecha")) Then
If (Not IsDBNull(itm(0))) Then
If (Not IsDate(itm(0))) Then
errores += 1
setValoresError = itm(0)
End If
Else
MsgBox("Direccion: " & ColumnIndexToColumnLetter(column.IndexOf(columna) + 1) & cell)
End If
cell += 1
End If
Next
tabla.Dispose()
Return errores
Catch ex As Exception
cajaMensaje("Error inesperado", ex.Message, My.Resources._error).ShowDialog()
PantallaPrincipal.lbldireccion.ForeColor = Color.Red
Return errores
End Try
Else
Return 0
End If
End Function
Source of the function: https://www.add-in-express.com/creating-addins-blog/2013/11/13/convert-excel-column-number-to-name/

Related

Report's textbox function call from ControlSource not firing

Firstly, here's a pic on my report in design mode:
The underlying query for the report returns values like so:
Allen Nelli 3:A,5:B,7:A,8:A, etc.
Breton Micheline 1:A,3:A,5:B,7:A, etc
Caporale Jody 1:A,3:A,5:B,7:A, etc
I had to use a subquery to get the third field which concatenates the number : letter combinations. These values actually represent day of month and designation to a particular shift in a schedule. So basically, for a given month, each individual works the designated shift indicated by the day value.
The intention is to call a user defined public function named PopulateTextboxes(Value as String) to be called from the first textbox in the report from the textbox's ControlSource property. The third field in the query is actually named Expr1 and that is being passed as a parameter to the function. The function is designed to populate all the textboxes with the appropriate letter designation: A or B or C or D, etc. The function itself is not being fired when I run the report.
The function is as follows:
Public Function PopulateTextboxes(Expr As String) As String
'Each element of Expr should be a number followed by a colon followed by a letter: 10:A,12:B,15:C, etc.
Dim shiftData() As String
Dim Data As Variant
Dim i As Integer
Dim j As Integer
Dim temp() As String
Dim txt As TextBox
Dim rpt As Report
Dim strCtrl As String
If Expr = "" Then Exit Function
If IsNull(Expr) Then Exit Function
shiftData = Split(Expr, ",")
If UBound(shiftData) > 0 Then
'Make a 2D array
ReDim Data(UBound(shiftData), 2)
'Load up 2D array
For i = 0 To UBound(shiftData) - 1
If shiftData(i) <> "" Then
temp = SplitElement(shiftData(i), ":")
Data(i, 0) = temp(0)
Data(i, 1) = temp(1)
End If
Next i
Set rpt = Reports.item("Multi_Locations_Part_1")
If UBound(days) = 0 Then
MsgBox "days array not populated"
Exit Function
End If
'Populate each Textbox in the Multi_Locations_Part_1 Report
For i = 1 To UBound(days)
strCtrl = "txtDesig_" & CStr(i)
Set txt = rpt.Controls.item(strCtrl)
For j = 0 To UBound(Data) - 1
If Data(j, 0) = days(i) Then
txt.Value = Data(j, 1) 'A,B,C,etc.
Exit For
End If
Next j
Next i
End If
PopulateTextboxes = Expr
End Function
Private Function SplitElement(Value As String, Delim As String) As String()
Dim result() As String
result = Split(Value, Delim)
SplitElement = result
End Function
Please advise.
The best way is to call your function from the Format event of the Detail section, so it will be called for each record.
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Call PopulateTextboxes(Me.Expr1)
End Sub
If PopulateTextboxes is in a separate module, I suggest to pass Me as additional parameter for the report, so you don't have to hardcode the report name.
Also note that you need the Set keyword when assigning object variables, e.g.
Set txt = rpt.Controls.item("txtDesig_" & CStr(i))

What is causing 'Index was outside the bounds of the array' error?

What is causing 'Index was outside the bounds of the array' error? It can't be my file, defianetly not. Below is my code:
Sub pupiltest()
Dim exitt As String = Console.ReadLine
Do
If IsNumeric(exitt) Then
Exit Do
Else
'error message
End If
Loop
Select Case exitt
Case 1
Case 2
Case 3
End Select
Do
If exitt = 1 Then
pupilmenu()
ElseIf exitt = 3 Then
Exit Do
End If
Loop
Dim score As Integer
Dim word As String
Dim totalscore As Integer = 0
'If DatePart(DateInterval.Weekday, Today) = 5 Then
'Else
' Console.WriteLine("You are only allowed to take the test on Friday unless you missed it")
' pupiltest()
'End If
Dim founditem() As String = Nothing
For Each line As String In File.ReadAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv")
Dim item() As String = line.Split(","c)
founditem = item
Next
Dim stdntfname As String = founditem(3)
Dim stdntsname As String = founditem(4)
Dim stdntyear As String = founditem(5)
Console.Clear()
If founditem IsNot Nothing Then
Do
If stdntyear = founditem(5) And daytoday = founditem(6) Then
Exit Do
ElseIf daytoday <> founditem(6) Then
Console.WriteLine("Sorry you are not allowed to do this test today. Test available on " & item(6).Substring(0, 3) & "/" & item(6).Substring(3, 6) & "/" & item(6).Substring(6, 9))
Threading.Thread.Sleep(2500)
pupiltest()
ElseIf stdntyear <> founditem(5) Then
Console.WriteLine("Year not found, please contact the system analysts")
Threading.Thread.Sleep(2500)
pupiltest()
End If
Loop
End If
For Each line As String In File.ReadAllLines("F:\Computing\Spelling Bee\testtests.csv")
Dim item() As String = line.Split(","c)
Dim mine As String = String.Join(",", item(2), item(3), item(4), item(5), item(6))
For i As Integer = 1 To 10
Console.WriteLine(i.ToString & "." & item(1))
Console.Write("Please enter the word: ")
word = Console.ReadLine
If word = Nothing Or word <> item(0) Then
score += 0
ElseIf word = item(0) Then
score += 2
ElseIf word = mine Then
score += 1
End If
Next
If score > 15 Then
Console.WriteLine("Well done! Your score is" & score & "/20")
ElseIf score > 10 Then
Console.WriteLine("Your score is" & score & "/20")
ElseIf score Then
End If
Next
Using sw As New StreamWriter("F:\Computing\Spelling Bee\stdntscores", True)
sw.Write(stdntfname, stdntsname, stdntyear, score, daytoday, item(7))
Try
Catch ex As Exception
MsgBox("Error accessing designated file")
End Try
End Using
End
End Sub
All help is highly appreciated,
You are constantly replacing the foundItem array when you do founditem = item:
Dim founditem() As String = Nothing
For Each line As String In File.ReadAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv")
Dim item() As String = line.Split(","c)
founditem = item
Next
Also, you are using (=) the assignment operation instead of (==) relational operator, to compare. Refer to this article for help in understanding the difference between the two.
Instead of this: If stdntyear = founditem(5) And daytoday = founditem(6) Then
Use this: If (stdntyear == founditem(5)) And (daytoday == founditem(6)) Then
Now back to your main error. You continue to assign the itemarray to founditem every time you iterate (Which overwrites previous content). At the end of the Iteration you will be left with the last entry in your CSV only... So in other words, founditem will only have 1 element inside of it. If you try to pick out ANYTHING but index 0, it will throw the exception index was outside the bounds of the array
So when you try to do the following later, it throws the exception.
Dim stdntfname As String = founditem(3) 'index 3 does not exist!
To fix it do the following change:
Dim founditem() As String = Nothing
For Each line As String In File.ReadAllLines("F:\Computing\Spelling Bee\stdnt&staffdtls.csv")
'NOTE: Make sure you know exactly how many columns your csv has or whatever column
' you wish to access.
Dim item() As String = line.Split(","c)
founditem(0) = item(0) 'Assign item index 0 to index 0 of founditem...
founditem(1) = item(1)
founditem(2) = item(2)
founditem(3) = item(3)
founditem(4) = item(4)
founditem(5) = item(5)
founditem(6) = item(6)
Next
For more help on how to work with VB.NET Arrays visit this site: http://www.dotnetperls.com/array-vbnet
In your line Dim item() As String = line.Split(","c) there's no guarantee that the correct number of elements exist. It's possible that one of the lines is missing a comma or is a blank trailing line in the document. You might want to add a If item.Length >= 7 and skipping rows that don't have the right number of rows. Also, remember that unlike VB6, arrays in .Net are 0 based not 1 based so make sure that item(6) is the value that you think it is.

Compare String with Strings in array

I'm trying to use this script to compare a users input from a text box with the 22 correct words. I'm not looking for multiple cases, such as VICE is in ADVICE so it would be 2 values; I want it to have the string values to accept only equal values.
At the moment, it is only recognizing the first word TIED and displays a message box "found", but it doesn't not recognize any other word in the list.
I am writing in visual basic script
Private Sub btnSubmit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
Dim StrCorrect() As String = {"TIED", "VICE", "ICED", "DIVE", "DIET", "DATE", "CITE", "CAVE", "AIDE", "ACED", "CITED", "ACTED", "VACATE", "CATTIE", "ADVICE", "AVIATE", "ACTIVE", "VACATED", "DICTATE", "AVIATED", "ACTIVATE", "ACTIVATED"}
Dim Find As String = userinput
For Each Str As String In StrCorrect
If StrComp(Str, userinput, CompareMethod.Text).ToString = 0 Then
MsgBox("Found" & userinput)
Return
Else : MsgBox("incorrect word")
Return
End If
Next
End Sub
The problem is that your loop is explicitly returning if the first item isn't a match. You only know you don't have a match if your loop completes without finding one, so try something like this instead:
For Each Str As String In StrCorrect
If StrComp(Str, userinput, CompareMethod.Text).ToString = 0 Then
MsgBox("Found" & userinput)
Return
End If
Next
MsgBox("incorrect word")
This will only display "incorrect word" if all of the items in your list fail the first test.
Why STRCOMP? Why not a direct comparision if you want an exact match?
For Each Str As String In StrCorrect
If Str = Find Then
MessageBox.Show("Found :" & Str)
End If
Next
Try like below, It will help you...
Sample :
Dim result As String() = Array.FindAll(StrCorrect, Function(s) s.Equals(Find))
If (result.Length > 0) Then
MsgBox("Found : " & userinput)
Else
MsgBox("incorrect word")
End If
Full Code :
Dim StrCorrect() As String = {"TIED", "VICE", "ICED", "DIVE", "DIET", "DATE", "CITE", "CAVE", "AIDE", "ACED", "CITED", "ACTED", "VACATE", "CATTIE", "ADVICE", "AVIATE", "ACTIVE", "VACATED", "DICTATE", "AVIATED", "ACTIVATE", "ACTIVATED"}
Dim Find As String = userinput
Dim result As String() = Array.FindAll(StrCorrect, Function(s) s.Equals(Find))
If (result.Length > 0) Then
MsgBox("Found : " & userinput)
Else
MsgBox("incorrect word")
End If
I would use a for loop, something like
For i As Integer = 0 To StrCorrect.Length - 1
If StrCorrect(i) = Find Then
MsgBox("Found" & Find)
Return
'End if
'The else statement simply alerting that it didnt find the right word on this iteration
'The else can be removed if you dont want this alert
Else
MsgBox("incorrect word")
'Return
End If
Next

String values left out of PropertyInfo.GetValue

I am not very well-versed in Reflection, but I have been working on this bit of code for a few days trying to obtain the values of class properties. I am using an API to find the values inside of cron jobs managed by the program VisualCron.
I'll explain the structure a bit. Each cron job has several tasks inside of it which have their own settings. The settings are stored in properties inside the TaskClass class that are declared like so:
Public Property <propertyname> As <classname>
Each property is tied to its own class, so for instance there is an Execute property inside TaskClass which is declared like this:
Public Property Execute As TaskExecuteClass
Inside TaskExecuteClass are the properties that hold the values I need. With the below block of code I have been able to retrieve the property values of all types EXCEPT strings. Coincidentally, the string values are the only values I need to get.
I know there must be something wrong with what I've written causing this because I can't find anyone with a similar issue after lots and lots of searching. Can anyone help me please?
Dim strAdd As String = ""
For Each t As VisualCronAPI.Server In vcClient.Servers.GetAll()
For Each f As VisualCron.JobClass In t.Jobs.GetAll
For Each s As VisualCron.TaskClass In f.Tasks
Dim propVal As Object
Dim propInfo As PropertyInfo() = s.GetType().GetProperties()
For i As Integer = 0 To propInfo.Length - 1
With propInfo(i)
If s.TaskType.ToString = propInfo(i).Name.ToString Then
Dim asm As Assembly = Assembly.Load("VisualCron")
Dim typeName As String = String.Format("VisualCron.{0}", propInfo(i).PropertyType.Name)
Dim tp As Type = asm.GetType(typeName)
Dim construct As ConstructorInfo = tp.GetConstructor(Type.EmptyTypes)
Dim classInst As Object = construct.Invoke(Nothing)
Dim classProps As PropertyInfo() = classInst.GetType().GetProperties()
For h As Integer = 0 To classProps.Length - 1
With classProps(h)
If .GetIndexParameters().Length = 0 Then
propVal = .GetValue(classInst, Nothing)
If Not propVal Is Nothing Then
strAdd = f.Name & " - " & s.Name & " - " & .Name & " - " & propVal.ToString
End If
End If
If strAdd <> "" Then
ListBox1.Items.Add(strAdd)
End If
End With
Next
End If
End With
Next
Next s
Next f
Next t
I solved my own problem, albeit in a crappy way. This is probably incredibly inefficient, but speed isn't a necessity in my particular case. Here is the code that works:
Dim strAdd As String = ""
For Each t As VisualCronAPI.Server In vcClient.Servers.GetAll()
For Each f As VisualCron.JobClass In t.Jobs.GetAll
For Each s As VisualCron.TaskClass In f.Tasks
Dim propVal As Object
Dim propInfo As PropertyInfo() = s.GetType().GetProperties()
For i As Integer = 0 To propInfo.Length - 1
With propInfo(i)
If s.TaskType.ToString = propInfo(i).Name.ToString Then
Dim asm As Assembly = Assembly.Load("VisualCron")
Dim typeName As String = String.Format("VisualCron.{0}", propInfo(i).PropertyType.Name)
Dim tp As Type = asm.GetType(typeName)
Dim construct As ConstructorInfo = tp.GetConstructor(Type.EmptyTypes)
Dim classInst As Object = construct.Invoke(Nothing)
Dim classProps As PropertyInfo() = classInst.GetType().GetProperties()
For h As Integer = 0 To classProps.Length - 1
With classProps(h)
If .GetIndexParameters().Length = 0 Then
propVal = .GetValue(CallByName(s, propInfo(i).Name.ToString, [Get]), Nothing)
If Not propVal Is Nothing Then
If propVal.ToString.Contains("\\server\") Or propVal.ToString.Contains("\\SERVER\") Then
strAdd = f.Name & " - " & s.Name & " - " & .Name & " - " & propVal.ToString
ListBox1.Items.Add(strAdd)
End If
End If
End If
End With
Next
End If
End With
Next
Next s
Next f
Next t
The piece of code that made the difference was the
classProps(h).GetValue(CallByName(s, propInfo(i).Name.ToString, [Get]), Nothing)
line.
If there are any suggestions for improving this code - I'm assuming that I've still got a lot of mistakes in here - then please comment for the future viewers of this answer and so I can adjust my code and learn more about how all of this works.

To iterate through the values of combo box control using vb.net

I update my question here .. Am using a combo box with no of phone numbers .I want to get the phone no one by one in a variable. Now am using the below code to get the combobox values. But still now am getting the following error message System.Data.DataRowView. Please help me to fix this error. am new for vb.net.
My partial code is here ..
For i = 0 To ComboBox1.Items.Count
Dim s As String
s = Convert.ToString(ComboBox1.Items(i))
Next i
you are using an index which is zero based.
change this:
For i = 0 To ComboBox1.Items.Count
to this:
For i = 0 To ComboBox1.Items.Count - 1
This also works!
Dim stgTest = "Some Text"
Dim blnItemMatched As Boolean = False
'-- Loop through combobox list to see if the text matches
Dim i As Integer = 0
For i = 0 To Me.Items.Count - 1
If Me.GetItemText(Me.Items(i)) = stgTest Then
blnItemMatched = True
Exit For
End If
Next i
If blnItemMatched = False Then
Dim stgPrompt As String = "You entered '" & stgTypedValue & "', which is not in the list."
MessageBox.Show(stgPrompt, "Incorrect Entry", MessageBoxButtons.OK, MessageBoxIcon.Information)
Me.Text = ""
Me.Focus()
End If
Your problem probably happens here:
s = Convert.ToString(ComboBox1.Items(i))
This doesn't return the value. It returns a string representation of the object at the given index, which in your case apparently is of type System.Data.DataRowView.
You would have to cast ComboBox1.Items(i) to the approbriate type and access its Value. Or, since its a DataRowView, you can access the values throgh the appropriate column names:
Dim row = CType(ComboBox1.Items(i), System.Data.DataRowView)
s = row.Item("column_name")
Nevertheless, first of all you should definitely close and dispose the connection, no matter whether the transaction fails or succeeds. This can be done in a finally block (option 1) or with a using statement (option 2).
Option 1
// ...
con1 = New MySqlConnection(str)
con1.Open()
Try
// ...
Catch ex As Exception
Lblmsg.Text = " Error in data insertion process....." + ex.Message
Finally
con1.Close()
con1.Dispose()
End Try
Option 2
// ...
Using con1 as New MySqlConnection(str)
con1.Open()
Try
// ...
Catch ex As Exception
Lblmsg.Text = " Error in data insertion process....." + ex.Message
Finally
con1.Close()
End Try
End using
Even after long time back you will achieve this with simply by following
For Each item As Object In combx.Items
readercollection.Add(item.ToString)
Next
Please try this
For j As Integer = 0 To CboCompany.Items.Count - 1
Dim obj As DataRowView = CboCompany.Items(j)
Dim xx = obj.Row(0)
If xx = "COMP01" Then
CboCompany.SelectedIndex = j
Exit For
End If
Next
I could not find this answer online in its entirety but pieced it together. In the snippet below cbox is a ComboBox control that has the DisplayMember and ValueMember properties initialized.
Dim itemIE As IEnumerator = cbox.Items.GetEnumerator
itemIE.Reset()
Dim thisItem As DataRowView
While itemIE.MoveNext()
thisItem = CType(itemIE.Current(), DataRowView)
Dim valueMember As Object = thisItem.Row.ItemArray(0)
Dim displayMember As Object = thisItem.Row.ItemArray(1)
' Insert code to process this element of the collection.
End While