Code getting skipped after 'For' loop - vb.net

I'm seeing some strange behavior during my form load event. Everything works as expected until I run a For loop. Any code below the Next line won't fire. I get no error the form just loads like every things good but it ignores those lines. I have placed a msgbox("test") above and below the loop to confirm this behavior.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Do some form loading stuff
msgbox("test1") 'This will Fire
For i = 0 To DataGridView1.Columns.Count
DataGridView1.Columns(i).SortMode = DataGridViewColumnSortMode.NotSortable
Next
msgbox("test2") 'This wont fire
End Sub
I could fix this by just putting the loop at the bottom of the form load but it bugs to me to not understand why this is happening.
EDIT: After further testing I've found out that if I just run the FOR loop without changing the sort mode then the test2 messagebox will fire. If I comment out the sortmode line everything works fine. Something about setting the sort mode in a loop is preventing the rest of the code from running.
P.S. If anyone knows of a better way to make a databound datagridview with extra columns not sort-able i'm all ears.

The problem is the loop that executes once too often
Arrays in NET starts at index zero and the maximum index is the length of the array minus one
For i = 0 To DataGridView1.Columns.Count - 1
DataGridView1.Columns(i).SortMode = DataGridViewColumnSortMode.NotSortable
Next
Your loop causes an exception that is probably trapped in the caller code and silently suppressed or, being in the load method and if you execute this code inside VS debugger, it is simply not catched for a well know problem with the load event in 64bit code with a debugger attached.

There's an error in your code: you can't enumerate untill DataGridView1.Columns.Count
Fix it like this:
For i = 0 To DataGridView1.Columns.Count -1
DataGridView1.Columns(i).SortMode = DataGridViewColumnSortMode.NotSortable
Next
By the way, you don't see the MsgBox because DataGridView1.Columns(i) is going to raise an exception, but this exception will be ignored if it's in the Load method.

Related

How to update a group of combo boxes using Loops

I have a form with combo boxes (cmbPort#) to select up to 8 serial ports. I want to first clear the item list for each, populate them with currently available system ports, and then add the option "Off" to each list. Finally, to set each combo box according to defaults saved in string spName(). I created a GroupBox (gBox1) and dragged each cmbPort onto it but I'm not sure how to reference the controls on it. I'm using VB 2015.
Can you help with VB.NET code to use loops ("For Each" or similar) to do this more efficiently?
Private Sub frmProp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cmbPort1.Items.Clear()
...
cmbPort8.Items.Clear()
For Each sp As String In My.Computer.Ports.SerialPortNames
cmbPort1.Items.Add(sp)
...
cmbPort8.Items.Add(sp)
Next
cmbPort1.Items.Add("Off")
...
cmbPort8.Items.Add("Off")
cmbPort1.Text = spName(1)
...
cmbPort8.Text = spName(8)
End Sub
Loops are an incredibly useful tool to master. I pitched here some code so you can get the idea, but I was working out of IDE so you might have to apply some fixes to this code to make it work as you want it to.
The main idea is that you shouldn't have to write a line more than once. If you multiply the same operation on several lines of code, you create potential problems for the future. Loops and subs are really helpful to prevent this kind of issues.
Private Sub frmProp_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'This is for later
Dim cmbIndex As Integer = 1
'You basically do the same operations for every Combobox in your list, son only one loop needed
For Each cmbPort As ComboBox In {cmbPort1, cmbPort2, cmbPort3 [...] cmbPort8} 'this is a way to declare an array
'Clear
cmbPort.Items.Clear()
'Add SerialPortNames
For Each sp As String In My.Computer.Ports.SerialPortNames
cmbPort.Items.Add(sp)
Next
'Add "Off"
cmbPort.Items.Add("Off")
'This last one is a little bit trickier because you want to match numbers
'This is the place where you get errors when something doesn't go as planned
'If you need to keep it inside the loop here's a way to achieve that, but honestly I would't do that
'Instead I would suggest that you take this part out of the loop and do it manually
If spName(cmbIndex) IsNot Nothing Then cmbPort.Text = spName(cmbIndex)
cmbIndex += 1
Next
End Sub
You shouldn't consider efficiency into this equation, as this operation will not be called all the time, only on load. I mean: you should always do things in the best way you can, but optimization is sometimes the enemy of good, readable code.

How can cancelling DataGridViewCellValidatingEventArgs replace all event handlers with itself?

I'm having a very strange problem in a VB application. I have a function written like this:
In the innermost condition, two statements are commented out here. These were found to have no effect on the strange behaviour. This is the minimal example I've found causing trouble.
(Note that the names of objects have been changed in this example.)
Private Sub MyForm_CellValidating(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs) Handles myDGV.CellValidating
Dim dgv As DataGridView = CType(sender, DataGridView)
Select Case dgv.Columns(e.ColumnIndex).Name
Case "uniqueColumn"
' Validate that the values in our unique column are unique.
For i As Integer = 0 To dgv.RowCount - 1
If i <> e.RowIndex Then
' Here i != j, so compare to the value...
If e.FormattedValue = dgv.Rows(i).Cells(e.ColumnIndex).FormattedValue Then
e.Cancel = True
'dgv.ShowRowErrors = True
'dgv.Rows(e.RowIndex).ErrorText = "Data in the unique column must be unique"
End If
End If
Next 'i
Case Else
' Perform no validation.
End Select
End Sub
What trouble, you ask? For some inexplicable reason, whenever the line
e.Cancel = True
is executed, afterwards, nearly all buttons and form widgets in the entire application, including even the close button in its window bar (what a user would use to exit the application) stop doing whatever they previously did and now call this event handler instead.
In other words, commenting out that line (and doing the validation manually when the form is submitted) fixes the problems. I'd like to know why this happens, though. Some pointers:
Here's a list of which things are not affected:
The minimize and maximize button in the top bar.
All objects in its menu bar.
This handler is private to its form class, it's not referenced anywhere else in the application.
I'm at a loss. Just how? What could possibly cause this?
e.Cancel is for stopping the validation when the input is deemed incorrect. This causes the cell to still have focus as the user is expected to correct whatever they did wrong. The CellValidating event will then be raised again whenever the cell is about to lose focus until your code deems the input to be correct.
You can use the Control.CausesValidation property to control whether a control (for instance a button) should raise validation events when it gains focus.

If statement makes debugger skip backwards

I have a Visual Studio 2015 Windows Forms program with a menu form and several others. The code for the menu button in question looks like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Visible = False
Form1.Show()
End Sub
When this button is pressed, Form 1 is loaded. Within the Form 1 load event is the following For loop:
For i As Integer = 1 To 10
If x_DataTable.Rows(0)(i.ToString()) <> "" Then
Me.Controls(("txt" & (i)).ToString()).Text = x_DataTable.Rows(0)(i.ToString())
Dim s As String = Me.Controls(("txt" & (i)).ToString()).Text.Trim()
If Convert.ToInt32(s.Substring(s.Length - 2)) < (m_DataTable.Rows(0)("Limit")) Then
Me.Controls(("txt" & (i)).ToString()).BackColor = Color.IndianRed
End If
End If
Next
Every time that the debugger hits the line that starts with "If Convert.ToInt32", it exits the for loop and the load event sub, and skips backwards to the Form1.Show() statement in the menu code above. Any idea what might be causing this or how to make it execute the code normally?
The Form.Load event has some odd exception handling behavior on x64 systems compared to x86 when a debugger is attached. When an exception is unhandled in a x86 process running on an x64 version of Windows the function is basically aborted, and the exception is eaten by the wow64 sub-system. Execution resumes at the last .net code on the stack before Load was called.
See this answer for a very thorough explanation.
Please Check Convert.ToInt32(s.Substring(s.Length - 2)) , (m_DataTable.Rows(0) ("Limit")) are valid Integers
Ok, I think I figured it out. The "Limit" column at row 0 was null, so it was not able to execute that line. Still not sure why it didn't show any error messages and just skipped backwards though.
Sounds like the assemblies and the source code are out of sync. Have you changed the config (Release|Debug) or maybe not built, or build to the wrong location?

Working around Selenium.StaleElementReferenceException

I'm trying to speed up some slow code by separating page loads from page analysis, but it seems that this breaks some rules that Selenium usually follows. As I understand it (found here) when you find something, Selenium stores references to it, not the actual thing you've found.
The result of this behaviour is that you can't load another page before processing the things you found. ie this sequential example works:
myDriver.Navigate.GoToUrl("mysite")
myVar = myDriver.FindElementsByClassName("upperContainer")
thisPN(i) = Trim(myVar.FindElement(By.ClassName("partNumber")).Text)
myDriver.Navigate.GoToUrl("http://www.google.com")
In order to make it faster though, I'm trying to pass the found items to a new thread for processing while the driver does other page loads.
This is illustrated by the below code which throws an exception An unhandled exception of type 'OpenQA.Selenium.StaleElementReferenceException' occurred in WebDriver.dll
Additional information: stale element reference: element is not attached to the page document
sub main()
myDriver.Navigate.GoToUrl("mysite")
myVar = myDriver.FindElementsByClassName("upperContainer")
Dim myThread As New Thread(Sub() ripitems(myVar))
myThread.Start() 'this line kicks off the sub
myDriver.Navigate.GoToUrl("anothersite") ' and then this line changes the page before the sub has got going
end sub
sub ripitems(ByVal elementCollection As System.Collections.ObjectModel.ReadOnlyCollection(Of IWebElement))
for i = 0 to 100
thisPN(i) = Trim(elementCollection.FindElement(By.ClassName("partNumber")).Text)
next i
end sub
I can cure this exception by adding an arbitrary Threading.Thread.Sleep(500) in after myThread.Start(). So I know it's the page change, not the threading that breaks things.
Is there any function that copies the found HTML into the result variable, so that I can use it even after the page I'm looking at has changed. Something along the lines of:
myVar = **ByVal** myDriver.FindElementsByClassName("upperContainer")

VB.Net App Stuck in Loop

I would just like the program to end itself.
Application.Exit just keeps rolling me back in a loop.
EDITED to Include Code::
Module Module 1
Sub Main()
Sub1()
Sub2()
End Sub
Sub1()
EndSub
Sub2()
End Sub
End Module
EDIT: It seems to be looping back here to Sub ChooseDomain2.. I am including Sub 1 as well.
Sub ChooseDomain1()
Dim DomainName As Object
'Get List of all users on Domain using WinNT
DomainName = InputBox(messageOK, Title, defaultValue)
de.Path = "WinNT://****".Replace("****", DomainName)
If DomainName Is "" Then ChooseDomain2() Else StoreUserData1()
End Sub
Sub ChooseDomain2()
MsgBox("Welcome to the Domain Searcher. Click OK to Auto Search for Domain")
Dim MsgBoxResult As Object = ActiveDirectory.Domain.GetCurrentDomain.Name
MsgBoxResult = InputBox(messageCan, Title, MsgBoxResult)
de.Path = "WinNT://*****".Replace("*****", MsgBoxResult)
StoreUserData1()
End Sub
When it hits end Module it Just starts back from Square one.
Modules don’t execute at all – so it never “hits end module” and never starts “from square one”. Modules merely group methods that can be executed, and Main is a special method that serves as the start of your application.
That said, your code is guaranteed (!) not to execute repeatedly. Also, there is no Application.Exit anywhere in your code so it’s hard to see what you are actually executing. Not the code you showed, anyway.
Note that VB potentially executes code that you didn’t write (code can be auto-generated by the compiler, in particular the application framework) but this doesn’t seem to be happening in your case, and shouldn’t loop in any case. But again, this is impossible to say from the information you have given.
Application.Exit is not required as the console app will quit after it finishes executing the last line in Sub Main. As previously mentioned it is likely you have Sub1 calling Sub2 (or something similar), so set a breakpoint on the start of each sub to find which one is continually being called. Then you can do a search in your code to find where this sub is being called from.