DataRow.SetColumnError(Int32, String) ignores Int32 value and always uses zero - vb.net

Okay, this is doing my head in. I'm calling SetColumnError() on a DataRow object that has 20 columns, but no matter which ColumnIndex I use it sets the error text on column 0. The MSDN documentation makes it plainly clear that the error text is supposed to be set on the column that the ColumnIndex provides.
I'm trying to set error text on columns 1 and 2 (I normally use constants when doing this, I have just used the integers in this example code for simplicity). Why does the error text appear on column 0 and what should I be doing to get the text to show on columns 1 and 2? I'm not receiving IndexOutOfRangeException.
Here is the code I'm having trouble with.
Public Sub ValidateRows()
For Each dgvRow As DataGridViewRow In Me.DataGridView1.Rows
If dgvRow.DataBoundItem IsNot Nothing Then
Dim rowView As DataRowView = dgvRow.DataBoundItem
Dim rowData As MyDataSet.DocumentRow = rowView.Row
rowData.ClearErrors()
If rowData.Revision = rowData.Revision_old Then
rowData.SetColumnError(1, "You must change the revision")
End If
If rowData.InternalRevision = rowData.InternalRevision_old Then
rowData.SetColumnError(2, "You must change the internal revision")
End If
End If
Next
End Sub

I'm not sure, but I think the number of the column must be of the type "DataColumn".

Related

Clear all textboxes in vb.net throws an error

I am using the following as a workaround:
Public Sub ClearTextBox(ByVal root As Control)
For Each ctrl As Control In root.Controls
ClearTextBox(ctrl)
If TypeOf ctrl Is TextBox Then CType(ctrl, TextBox).Text = 0
If TypeOf ctrl Is ComboBox Then CType(ctrl, ComboBox).Text = String.Empty
Next ctrl
End Sub
the reason i am setting the textboxes to 0 is because when I set String.Empty, one text box (containing only Int16) throws a conversion error. anyone help on stopping the error or just ignoring that one textbox?
As per Andrews response, I ran the code again, and i get the following:
+ $exception {"Conversion from string """" to type 'Short' is not valid."} System.InvalidCastException
The code highlighted is:
Dim age As Int16 = Txt_CharAge.Text
Please bear with me a little, I am totally new to this and am completely self taught. If you need further code to help, just let me know.
Thanks
When you have a line such as
Dim age As Int16 = Txt_CharAge.Text
you are telling the computer to put a string into a number. Without Option Strict On, it is free to make up any way it likes of stuffing a string (which is not an Int16) into an Int16. You have given up your control of what is happening at that point.
The better way is to tell it how to convert the characters of the text into a number. (See The Treachery of Images for an explanation that a representation of some thing is not that thing.)
There is a ready-made set of methods named TryParse for many of the built-in types.
So, instead of
Dim age As Int16 = Txt_CharAge.Text
you should have
Dim age As Integer
Integer.TryParse(Txt_CharAge.Text, age)
The TryParse methods are actually functions which return True if the parse was successful, otherwise they return False (and set the variable to its default value), but in this case it appears that you don't need to know if the parse succeeded because the default value of 0 for an Integer will suffice.
Note that there isn't really a need to use an Int16 instead of an Integer unless you know why you need to add the complication of using an Int16 instead of an Integer.

Compare two datatables, if anything is different show MessageBox

I have two datatables, one of them is populated when application starts and the other one is populated on button click. How can i check (fastest way) if anything changed in second datatable?
I have tried this but it does not work:
For Each row1 As DataRow In dtt.Rows
For Each row2 As DataRow In dtt1.Rows
Dim array1 = row1.ItemArray
Dim array2 = row2.ItemArray
If array1.SequenceEqual(array2) Then
Else
End If
Next
Next
The problem is that your loops are nested. This means that the inner For Each loops through each row of dtt1 for each single row of dtt. This is not what you want. You want to loop the two tables in parallel. You can do so by using the enumerators that the For Each statements use internally
Dim tablesAreDifferent As Boolean = False
If dtt.Rows.Count = dtt1.Rows.Count Then
Dim enumerator1 = dtt.Rows.GetEnumerator()
Dim enumerator2 = dtt1.Rows.GetEnumerator()
Do While enumerator1.MoveNext() AndAlso enumerator2.MoveNext()
Dim array1 = enumerator1.Current.ItemArray
Dim array2 = enumerator2.Current.ItemArray
If Not array1.SequenceEqual(array2) Then
tablesAreDifferent = True
Exit Do
End If
Loop
Else
tablesAreDifferent = True
End If
If tablesAreDifferent Then
'Display message
Else
'...
End If
The enumerators work like this: They have an internal cursor that is initially placed before the first row. Before accessing a row through the Current property, you must move to it with the MoveNext function. This function returns the Boolean True if it succeeds, i.e. as long as there are rows available.
Since now we have a single loop statement and advance the cursors of enumerator1 and enumerator2 at each loop, we can compare corresponding rows.
Note that the Rows collection implements IEnumerable and thus the enumerators returned by GetEnumerator are not strongly typed. I.e. Current is typed as Object. If instead you write
Dim enumerator1 = dtt.Rows.Cast(Of DataRow).GetEnumerator()
Dim enumerator2 = dtt1.Rows.Cast(Of DataRow).GetEnumerator()
Then you get enumerators of type IEnumerator(Of DataRow) returning strongly typed DataRows.

Check if object exists at list index in Visual Basic

I need to check if an object exists at a specified index in a List in Visual Basic.
What I have is
Dim theList As New List(Of Integer)({1,2,3})
If theList.Item(3) = Nothing Then
'some code to execute if there is nothing at position 3 in the list
But when I run the program I get System.ArgumentOutOfRangeException, saying the index is out of range. Of course it is, the entire point was to see if it does or doesn't exist. If "= Nothing" is not the way to check if something exists at that index, what is?
I am in my Application Development class and we are working on Windows Forms Applications using Visual Studio 2017, if any of that matters.
If you are checking a list of objects, you need to change two things.
The way to check for nothing is to use Is Nothing.
You can't even attempt to check items beyond the end of the list, so you must first check that the index you want to use is less than the number of items in the list'
You should change your code to
If theList.Items.Count > 3 AndAlso theList.Item(3) Is Nothing Then
'some code to execute if there is nothing at position 3 in the list
End If
Note the use of AndAlso rather than And in the If statement. This is required because it ensures that the check on item 3 happens only if there are at least 4 items in the list.
Also note that, in the code you posted, the list is a List(Of Integer). An Integer can never be Nothing, so the second part of you check is either not needed or you should be checking for = 0 instead of Is Nothing.
Any time you have a list you can only access members of the list, accessing an imaginary item outside of the bounds will result in the error you specified.. The integer datatype comparison to Nothing is a comparison to 0. IMO this use of nothing is not ideal. If you want nothing you might look at Nullable. Here is some code to take a look at.
Dim theList As New List(Of Integer)({0, 1, 2, 3})
For idx As Integer = 0 To theList.Count - 1 'look at each item
If theList.Item(idx) = Nothing Then
Stop ' item is 0
End If
Next
Dim i As Integer = Nothing ' i = 0
'Dim theListN As New List(Of Integer?)({1, 2, 3, Nothing, 5})
Dim theListN As New List(Of Nullable(Of Integer))({1, 2, 3, Nothing, 5, Nothing})
For idx As Integer = 0 To theListN.Count - 1 'look at each item
If theListN.Item(idx) Is Nothing Then
'item is nothing, not 0
Dim nullI As Nullable(Of Integer) = theListN.Item(idx)
If Not nullI.HasValue Then Stop
End If
Next

VBA ADODB test is two fields are convertable?

I'm writing a function that copies contents of a recordset(from ADODB library) into another. Specifically copying some contents of Oracle g11(fragment of it) to Access 2007.
Becasue I want to make sure that I write either all contents or none at all- I am checking if the Fields of each recordset are the same(have same Name and Type).
Problem is that very quickly I stumbled upon a case were one recordset has field Type adVarChar and the other has adVarWChar. To be honest I am not sure how are these data types different but as I understand they both represent a variable lenght character field, and correct me if I'm wrong but I should be able to write contents of adVarChar into adVarWChar.
Now I undrstand that there are many more types of strings that ADODB recognizes, and that there many types of integers, doubles, floats .... you get the point.
So my question is how can I detect if you can write/coerce/convert contents of one data type(ADODB's data types) to another?
Is there a susinct and DRY way of doing this?
See my code for reference
Sub AppendRecords(NewRecords As ADODB.Recordset, OriginalRecords As ADODB.Recordset)
Dim AllFieldsMatch As Boolean
Dim Iterator As Integer
Dim ActiveField As Field
Dim FieldCount As Integer
Dim FieldNames() As String
Dim FieldValues() As Variant
FieldCount = NewRecords.Fields.Count
For Iterator = 0 To FieldCount - 1
If NewRecords.Fields(Iterator).Name <> OriginalRecords.Fields(Iterator).Name Then
AllFieldsMatch = False
Err.Raise 10001, "AppendRecords", "Field names are not matching."
End If
Next
For Iterator = 0 To FieldCount
If NewRecords.Fields(Iterator).Type <> OriginalRecords.Fields(Iterator).Type Then
AllFieldsMatch = False
Err.Raise 10002, "AppendRecords", "Field Types are not matching."
End If
Next
If NewRecords.EOF And NewRecords.BOF Then
Err.Raise 10003, "AppendRecords", "There are no records in new Recordset."
End If
Iterator = 0
ReDim FieldNames(Iterator To FieldCount - 1)
ReDim FieldValues(Iterator To FieldCount - 1)
For Each ActiveField In NewRecords.Fields
FieldNames(Iterator) = ActiveField.Name
Next
While Not NewRecords.EOF
For Each ActiveField In NewRecords.Fields
FieldNames(Iterator) = ActiveField.Value
Next
OriginalRecords.AddNew FieldNames, FieldValues
NewRecords.MoveNext
'LogCompletedJob "GetCoverageTable" 'Ignore for now
Wend
End Sub
I've done this before to map ADO field data types with DAO field data types. However I haven't done this with Oracle. This link may help:
https://docs.oracle.com/cd/B19306_01/server.102/b14232/apb.htm
Or this:
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/oracle-data-type-mappings
You could try and update the field value without checking data types. Add error handling to catch obvious fails and then compare the contents of the two field values to see if the data made it across.
i.e. Remove this:
For Iterator = 0 To FieldCount
If NewRecords.Fields(Iterator).Type <> OriginalRecords.Fields(Iterator).Type Then
AllFieldsMatch = False
Err.Raise 10002, "AppendRecords", "Field Types are not matching."
End If
Next
And add error handling/checks to this part of the code:
For Each ActiveField In NewRecords.Fields
FieldNames(Iterator) = ActiveField.Value
Next

Error Reading string into array

I'm in the process of creating a tile based game. This game requires a method to load a text file and write the numbers between the delimiter "-", to a multidimensional array. However, an error message "object not set to an instance occurs.
'Load map
Public Sub LoadMap(ByVal URI As String)
Using reader As New System.IO.StreamReader(URI)
For x As Integer = 0 To 13
Dim line = reader.ReadLine()
Dim tokens() As String = line.Split("-")
'adds values to multidimensional array
For y As Integer = 0 To 16
Me.map(x, y) = Integer.Parse(tokens(y))
Next y
Next x
End Using
End Sub
Example map - numbers represent image id's
2-2-2-0-0-0-0-0-0-0-0-3-3-5-5-5-5
2-2-2-0-0-0-0-0-0-0-0-3-3-5-5-5-5
2-2-2-0-0-0-0-0-0-0-0-3-3-2-2-2-5
2-2-2-0-0-0-0-0-0-0-0-3-3-2-2-2-5
2-2-2-0-0-0-0-0-0-0-0-3-3-2-2-2-5
0-0-0-0-0-0-0-0-0-0-0-3-3-2-2-2-5
3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
4-4-4-4-4-3-4-4-4-4-4-4-4-2-2-2-2
I can't seem to establish the problem. Thanks in advance...
Always use Option Strict On! (Your code shouldn’t even compile, you need to parse the input integers, or your map stores strings, which is equally as bad since you logically store numbers.)
Name your variables properly.
Omit vacuous comments. Only comment things that aren’t obvious from the code.
Don’t hard-code magic numbers (what’s 11? 8?)
Don’t declare variables before initialising. Declare on first use.
The outer loop in your code makes no sense.
Don’t close streams manually, always use a Using block to ensure the program still works in the face of exceptions.
Initialise map.
Which leaves us with:
Public Sub LoadMap(ByVal URI As String)
Const MapHeight As Integer = 12
Const MapWidth As Integer = 9
Me.map = New Integer(MapHeight, MapWidth) { }
Using reader As New System.IO.StreamReader(URI)
For x As Integer = 0 To MapHeight - 1
Dim line = reader.ReadLine()
Dim tokens() As String = line.Split("-")
For y As Integer = 0 To MapWidth - 1
Me.map(x, y) = Integer.Parse(tokens(y))
Next y
Next x
End Using
End Sub
Bonus: Check for errors: what if the map doesn’t have the predefined width/height? Why hard-code this at all?
osRead.ReadLine() returns Nothing if the end of the input stream is reached. You call Peek to see if you're at the end of the input, but then, you proceed to read 12 lines without checking if you're at the end of the input in-between. If you have less than 12 more lines, you'll get the error you mentionned on temp.Split("-"), because temp will have a value of Nothing, so you can't call methods on it.
Also, just noticed something... your Map is 11x8, but you're reading 12 lines, and going through 9 values, you probably want to do:
For x As Integer = 0 To 10
or
For x As Integer = 1 To 11
Same thing for your other loop.
If temp is null (Nothing) in VB.Net, then you can't call methods on it.
Do a check for Nothing before attempting to do anything with the value.
So Just to be sure you have updated your code to look something like this:
If temp IsNot Nothing
'tempLine stores the split read line
Dim tempLine() As String
'splits readline into - ERROR Not set to an instance
tempLine = temp.Split("-")
'adds values to multidimensional array
For y As Integer = 0 To 8
Me.map(x, y) = tempLine(y)
Next y
End If
And you are STILL getting the null reference exeption?
also make sure that your StreamReader is properly initialized... if the initialization fails (perhaps because of a bad URI) then attempting to call osRead.peek() will throw the "object not set to an instance" error.