Radio buttons fire in VB net at form load - vb.net

I have a simple VB net form with two radio buttons in a group box and button outside the group box that calls another form that sets up other parameters. The radio buttons both send data over the serial port.
Form1_load event has a boolean value form_loading = True. This is checked in the rbtn handler and if true should exit the subroutine. On debug, the check changed even fires one button's event that is checked at design time and at this point the form_loading value is set to false and I have no idea why. There is no form_loading = false statement. If I remove the rbtn handler, the form_loading = True persists when the other form is called and returned. The groupbox with buttons is activated as it sees a rbtn1-CheckChanged when the form loads and form_loading value get set to false. I suspect that the rbtn event is firing as the form begins to load, before the form_loading = True statement is reached, but how do I stop it firing the button event?
As its stands, when debug start, there is an IO exception error:
Serialport is closed, and the code associated with the button is in
the buffer to send to a (closed) com port
Private Sub rbtnDon_CheckedChanged(sender As Object, e As EventArgs) Handles rbtnDon.CheckedChanged
If form_loading Then
Exit Sub
ElseIf rbtnDoff.Checked = True Then 'event fires when other button checkchanged = true, this stops it
Exit Sub
Else
data_out = (SOT + "N" + EOT)
SendtoBoard(data_out)
End If
End Sub`enter code here`

Thanks for your help Everyone. Elsewhere I found this tip: Remove the "handles rbtnDon checkchanged" from the sub:
Private Sub rbtnDon_CheckedChanged(sender As Object, e As EventArgs)handles rbtnDon checkchanged
and add this to the form1_load sub:
AddHandler rbtnDon.CheckedChanged, New EventHandler(AddressOf rbtnDon_CheckedChanged)
That seems to have solved the problem completely.
I could not add the startup code on my original post as for some reason the box will not accept two lots of separate code - or I am not doing it right:
It is here:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i As Integer = 0 To My.Computer.Ports.SerialPortNames.Count - 1
ccbComPort.Items.Add(My.Computer.Ports.SerialPortNames(i))
Next
If ccbComPort.Items Is Nothing Then
lblMessage.ForeColor = Color.Red
lblMessage.Text = "No Serial Ports found"
Else
ccbComPort.Text = My.Settings.oldPort
End If
ccbBaudrate.Text = My.Settings.oldBaud
pnlComPorts.Visible = True
'form_loading = True
rbtnDon.Enabled = True
AddHandler rbtnDon.CheckedChanged, New EventHandler(AddressOf rbtnDon_CheckedChanged)
End Sub
Originally I had one form with a panel for the Com port setup and everything was fine, the issue only started when I moved the port set up to form2, after which the rbtnDon event fired before form1 started.
I did try the Sub New() approach but then I just get a small blank form on debug. Adding Form1_load to it results in "NotImplemented Exception".
The method described above seems OK and fairly simple to add but maybe it is not good practice?

Related

VB: How to manually call or delay events?

Background: I'm new to vb, coming from javascript.
My assignment is to use the txtBox.LostFocus event to do some validation. The problem is I need to cancel the validation step if the user intends to press either two of three buttons.
Illustration:
Code
Dim lblInputBox As Label
lblInputBox.Text = "Name:"
Dim txtInputBox As TextBox
Dim btnClear As Button
btnClear.Text = "Clear"
Dim btnSayName As Button
btnSayName.Text = "Say Name"
Dim btnExit As Button
btnExit.Text = "Exit"
' Some boolean to determine what the next action is
Dim UserIntentDetected = False
' When the user moves focus away from the textbox
Private Sub txtInputBox_LostFocus(sender As Object, e As EventArgs) _
Handles txtIputBox.LostFocus
' I want to be able to detect the next focus, but this is where I'm going wrong
If btnExit.GotFocus Or btnClear.GotFocus Then
UserIntentDetected = True
Else
UserIntentDetected = False
End If
' Only call validate if there is no intent to quit or clear
If Not UserIntentDetected Then
Call validate()
End If
' Reset the intent boolean
UserIntentDetected = False
End Sub
' Validate subroutine
Private Sub validate()
' **Fixed description**
' User moved focus away from txtbox and doesn't intend to clear or exit
Console.WriteLine("You're NOT INTENDING to clear or exit")
End Sub
I've tried to add the two button's GotFocus event to the input box's LostFocus event handler, but there were bugs with the event firing multiple times in a loop.
Eg:
Private Sub txtInputBox_LostFocus(sender As Object, e As EventArgs) _
Handles txtIputBox.LostFocus, btnExit.GotFocus, _
btnClear.GotFocus
... (code follows)
These attempts are entirely wrong, but from a javascript background, although also entirely wrong, I could hack something like this..
... (assume same element structure from vb)
var eventQueue = [];
var userIntentDetected = false;
txtInputBox.addEventListener("blur", function(event){
// Set a timeout to manually trigger the last event's click method in the eventQueue
setTimeout(function(){
if (eventQueue.length > 0 && userIntetDetected)
runIntendedHandler(eventQueue[eventQueue.length -1]);
}, 500);
})
// Both event listeners listen for click and stop default actions,
// set intent boolean to true, and add it's event object to a queue
btnExit.addEventListener("click", function(event){
event.preventDefault();
userIntentDetected = true;
eventQueue.push(event);
});
btn.addEventListener("click", function(event){
event.preventDefault();
userIntentDetected = true;
eventQueue.push(event);
});
// Validation should occur only if the user moves focus to an element
// that IS NOT either the btnExit or btnClear
function runIntendedHandler(event){
if (event.target.id = "btnExit")
// run exit functions
code...
else if (event.target.id = "btnClear")
// run clear functions
code..
userIntentDetected = false;
}
What is the proper way to work with events in vb and how would I go about detecting the next event in the queue before triggering an action? could the RaiseEvent statement help?
UPDATE 3: The answer was a lot easier than I made it seem. Apparently, you can use the btn.Focused property to check the next focus of an element from within the txtInputBox.LostFocus event handler... Go figure!
UPDATE 2: There's been a lot of confusion as to what exactly was needed, and a lot of that was my fault in describing the validation subroutine. I've changed some of the element names and added an image to sum up all of the information that was given to me by my instructor.
UPDATE 1: #TnTinMn has provided the closest working answer that can be used with a minor alteration.
Example follows:
Private LastActiveControl As Control = Me ' initialize on form creation
Protected Overrides Sub UpdateDefaultButton()
' Just added an IsNot condition to stay inline with the requirements
If (LastActiveControl Is txtNumberOfDrinks) AndAlso
((ActiveControl Is btnClear) OrElse (ActiveControl Is btnExit)) Then
Console.WriteLine("Your intent to press either btnClear or btnExit has been heard...")
' Validation happens only if the user didn't intend to click btnClear or btnExit
ElseIf (LastActiveControl Is txtNumberOfDrinks) AndAlso
((ActiveControl IsNot btnClear) OrElse (ActiveControl IsNot btnExit)) Then
Console.WriteLine("You didn't press either btnClear or btnExit.. moving to validation")
validateForm()
End If
LastActiveControl = ActiveControl ' Store this for the next time Focus changes
End Sub
Thank you all!
Winform's event order is confusing at best. For a summary, see Order of Events in Windows Forms.
Assuming I have interpreted your goal correctly, I would not respond to the txtInputBox.LostFocus event but rather override a little known Form method called UpdateDefaultButton. This method is called when the Form.ActiveControl property changes and effectively gives you an ActiveControl changed pseudo-event. If the newly ActiveControl is a Button, this method also executes before the Button.Click event is raised.
Since you want to call your validation code only when the focus changes from txtInputBox to either btnPromptForName or btnExit, you can accomplish that with something like this.
Public Class Form1
Private LastActiveControl As Control = Me ' initialize on form creation
Protected Overrides Sub UpdateDefaultButton()
If (LastActiveControl Is tbInputBox) AndAlso
((ActiveControl Is btnPromptForName) OrElse (ActiveControl Is btnExit)) Then
ValidateInput()
End If
LastActiveControl = ActiveControl ' Store this for the next time Focus changes
End Sub
Private Sub ValidateInput()
Console.WriteLine("You're either intending to prompt for name or exit")
End Sub
Private Sub btnPromptForName_Click(sender As Object, e As EventArgs) Handles btnPromptForName.Click
Console.WriteLine("btnPromptForName_Click clicked")
End Sub
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Console.WriteLine("btnExit clicked")
End Sub
End Class
Edit: I forgot to mention, that since UpdateDefaultButton runs before the Button.Click event is raised, it is possible wire-up the click event handler only if validation succeeds. You would then remove the event handler as part of the Button.Click handler code.
It looks like the solution was a lot easier than I thought. The intended (instructor's) way to do this is by checking for alternate "btn.Focused" properties within the txtInputBox.LostFocus event handler eg:
' When the user moves focus away from the textbox
Private Sub txtInputBox_LostFocus(sender As Object, e As EventArgs) _
Handles txtIputBox.LostFocus
' Check if the clear or exit button is focused before validating
' Validate only if btnClear and also btnExit IS NOT focused
If Not btnExit.Focused AndAlso Not btnClear.Focused Then
Call validateForm()
End If
End Sub
Thank you #TnTinMn for the UpdateDefaultButton and showing me an alternate way to track events. This was very helpful too.

RichEditControl event handler, prompting to save upon form close with nothing has changed

Having an issue when closing the form and nothing has changed, it still prompts to save the form. We have a form that has multiple controls. There are a few lookup combo boxes with data. They select their data and then click a button called "view". View then brings up a few textboxes and combo boxes etc and populates with data. There is also a RichEditControl that also gets loaded. After all the data is loaded in the load event. The last line is to call the following method to set event handlers for all controls. If something has changed after that then prompt to save upon form closing.
customFunc.AddDirtyEvent(Me)
The issue is and we have test if there is no richtextbox, it works. If the only control on a form is a RichEditControl, it always prompts to save no matter what, even if nothing has changed upon load. I noticed if you have a form that has a RichEditControl, and it gets populated upon form load. Even if you call the eventhandler after that, it still prompts you to save BUT if you add the eventhandler call in the form shown event, it seems to work as it doesn't set the dirty bit again. Its almost like the events are queue at the end of the form load event. But then it goes to the shown event, the call is made there and the dirty bit doesn't get reset back to true.
Issue is in our case, we can't use a shown event, because we have a button "view" that loads all the data and populates a RichEditControl. So even if we add the event handlers after the data gets loaded in the same method, it always goes back to set the dirty bit to true. We need to somehow keep the dirty bit to false after this, so if there is no changes and they just want to view data don't prompt to save upon form closing. Below is my code.
If customFunc.IsDirty = True Then
Dim dr As DialogResult = MessageBox.Show("Do you want save changes before leaving?", "Closing Mud Report", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2)
If dr = Windows.Forms.DialogResult.Yes Then
SimpleButtonSave.PerformClick()
ElseIf dr = Windows.Forms.DialogResult.Cancel Then
e.Cancel = True
End If
End If
Private Sub SetIsDirty(ByVal sender As System.Object, ByVal e As System.EventArgs)
is_Dirty = True
End Sub
Public Sub AddDirtyEvent(ByVal ctrl As Control)
For Each c As Control In ctrl.Controls
If TypeOf c Is RichEditControl Then
Dim rtb As RichEditControl = CType(c, RichEditControl)
AddHandler rtb.RtfTextChanged, AddressOf SetIsDirty
End If
If c.Controls.Count > 0 Then
AddDirtyEvent(c)
End If
Next
End Sub
In your SetIsDirty method check for RichEditControl.Modified property.
Here is example:
Private Sub SetIsDirty(ByVal sender As System.Object, ByVal e As System.EventArgs)
If TypeOf sender Is RichEditControl Then
Dim rtb As RichEditControl = CType(sender, RichEditControl)
is_Dirty = is_Dirty OrElse rtb.Modified
Else
is_Dirty = True
End If
End Sub

Forms acting unexpectedly

I'll try to explain this best I can.
I have windows form application that contaions numerous forms. The first form
to open is a non modal form that acts as command form to issue various formats to
the underlying reservation program. A second form also opens which is basically my
Main form for the application. This form contains multiple check boxes to run methods
that make changes to the reservation program. This form is also modeless. Each box that
is checked runs concurrently and performs methods to delete, change and add to the
res program below. Various boxes may be checked at any given time. Below is code to
handle the checkboxes:
Private Sub frmOWTMain_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
If e.KeyCode = Keys.Enter Then
Me.Hide() 'here i want to hide the OWTMain form
Call ckforPNR()
If Me.cbPricing.Checked Then
Call doPricing()
Me.cbPricing.Checked = false
End If
If Me.cbUdids.Checked Then
frmUdids.Show()
Me.cbUdids.Checked = False
End If
If Me.cbMod.Checked Then
Call doModUdids()
End If
If Me.cbFare.Checked Then
Call doFareSavings()
Me.cbFare.Checked = False
End If
End If
Me.show() 'This is the problem. This runs during method calls. All I'm
'looking to do is re display the OWTMain form.
End Sub
At this point I would want to re display the OWTMain form above. This is
where I am having an issue. As you can see, a number of methods are called
which involve showing other forms to the user. I do NOT want any of these
forms to be modal because I want the original first opened form to still be
able to issue commands to the res program toview information needed by the other forms.
Here is an example of some of the method calls:
Private Sub doPricing()
Dim myPrice As New Pricing 'a call to another class that handles pricing
If myPrice.getTQT = False Then
frmAddPricing.ShowDialog() 'showing new forms
Else
frmCurPricing.ShowDialog()
End If
End Sub
Private Sub doFareSavings()
Dim myPrice As New Pricing
If myPrice.checkForFS = False Then
frmFS.ShowDialog() 'showing new forms
End If
If myPrice.checkForFS = True Then
frmFSVerify.ShowDialog()
End If
End Sub
When I call any of these methods the form OWTMain shows prematurely while other
forms from the called method are still running. I expected the code at the top to run
in order of the calls but that is not the case. I just want to re display the OWTMain
form after all the code is run. I have not been able to figure this out without
creating a ton of code to minipulate the opening and closing of the windows.
Any help with this would be greatly appreciated. Thank you.
John
This will check if all sub forms are closed and then re-show the main form.
remove the exitsing me.show()
Public Sub ReShowMainForm()
' add all sub forms to this check
if frmFS.Visible = false andalso
frmUdids.Visible = false andalso
frmFSVerify.Visble = false then
Me.Show
End If
End Sub
change xyzForm.Show to xyzForm.Show(me) to make the main form available as parent to the sub forms.
Handle the FormClosed event in each sub form and add the following code
DirectCast( me.parent, frmOWTMain).ReShowMainForm()

Checkbox events when Form is opened and closed fire when form is reloaded

First... I am open to skinning this cat a different way if I am going at it wrong to begin with. Using VB 2010 .net 4.0 and I am very much a beginner.
I am making a product billing application that has a main form and a subform with additional options. Whenever that subform is reopened after being opened once, the checkbox events that were selected are blank by default. If I recheck them (so someone can uncheck) then any that are rechecked all refire and increase the variable again.
I ultimately need to be able to open that second form after closing it, display any checkboxes that were selected before as selected again and not increase the variable in the process.
Main form Checkbox code to set booleans and increase or decrease subtotal variable of most used products.
Private Sub chkbox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkbox1.CheckedChanged
If chkbox1.Checked = True Then
bChkbox1 = True
Subtotal += 15
Else
bChkbox1 = False
Subtotal -= 15
End If
End Sub
Main form button to launch subform with all products listed.
Private Sub btnAllProducts_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAllProducts.Click
Form3.Show()
End Sub
Subform checkbox code works perfectly the first time it is opened but not when relaunched.
Private Sub chkbox2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkbox2.CheckedChanged
If chkbox2.Checked = True Then 'also tried without the nested if with same results
If Me.IsHandleCreated = True Then 'me.visible behaves the same way
MsgBox("form visible true")'launches after clicking button but before form is actually on screen
Form1.bcheckbox2 = True
Form1.Subtotal += 105
End If
Else
Form1.bcheckbox2 = False
Form1.Subtotal -= 105
End If
End Sub
Booleans are used to check boxes that were checked on the main page or when it was open before.
If Form1.bcheckbox2 = True Then
chkbox2.Checked = True
End If
As I said, I can completely rework the code if it makes sense to do so or just fix something if I have made some sort of mistake.
For example, I was thinking of changing to wipe the subtotal on each form load and rebuild it based off the toggled booleans but it seems like there should be a much more elegant way with less overhead and I am just doing something incorrectly.
It is not common to have to tell checks and radios to ignore events while loading the form. You just need an Ignore or Loaded flag:
Public Class Form1
Private ignore As Boolean = True
...
Private Sub Form1_Load(...
' do normal stuff
ignore = False ' should be the ONLY place it is set
End Sub
Private Sub CheckBox2_CheckedChanged(...
If ignore Then Exit Sub
End Sub
The Form Designer code will fire events as it creates the form and controls, which CAN be handy for initializing stuff but often it causes trouble. Some controls will even get the same event twice. There isnt really a "reload" action for forms. If you hide them, Show() won't fire the Load event again.
You can avoid the flag and manually add the handlers for the troublesome controls when the form loads, but that can be tedious if there are lots of them. Flags can be abused and misused, but if it is set in that one spot only, its fine.
If someone is looking for alternative or have similar problem here's my workaround to detect event change so checkbox wouldn't get triggered on re-load:
If ((Me.CheckBox2.Value <> Sheets(1).Range("t6").Value) And (Me.CheckBox2 = True)) = True Then
' do your stuff
Me.CheckBox2.Value = False
Else
Me.CheckBox2.Value = True
End If
Where Sheets(1).Range("t6").Value is where checkbox2 value is being stored.
I have this assigned to a msgbox input so when vbno event is being triggered else is executed.
Cheers.

Auto Login Procedure (Hide Form) vb.NET Windows Forms

Okay, I am having a bit of trouble here. I am creating a log in window for an application, but I am trying to get the application to automatically log in (i.e. perform the functions that happen when the user logs in) when it starts, without showing the log in screen, if the settings already have a stored email and password. I have a notification System Tray Icon that shows when the app is running, and when the form is not visible, a balloon notification pops up so the user knows that it is still running, and click on the icon to open the log in screen.
Take a look at the following code. I know that this If Not event is being called and working correctly, because it performs everything inside the statement EXCEPT hiding the form. Why does it not change to invisible? I also tried Me.Hide, and same issue. The Balloon Notification pops up, the text boxes fill with the previously stored data...but the form stays visible...
Private Sub RadFrmLogin_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Checks settings to see if email and password have already been stored and enters them into text fields, proceeds to automatically update access list
If Not String.IsNullOrEmpty(My.Settings.Email) And Not String.IsNullOrEmpty(My.Settings.Password) Then
TxtEmail.Text = My.Settings.Email
TxtPassword.Text = My.Settings.Password
Me.Visible = False
'Displays Balloon Tip
ntfySystemTrayIcon.ShowBalloonTip(800)
End If
End Sub
As an added note, I added a test button to hide the form, and it works perfectly:
Private Sub BtnHide_Click(sender As Object, e As EventArgs) Handles BtnHide.Click
'Hides form(for testing notification tray icon and balloon tip
Me.Visible = False
ntfySystemTrayIcon.ShowBalloonTip(1000)
End Sub
(removed my stupid default debug instructions since they did not help at all)
Update
okay, so there were similar questions before, take a look here: C#/.NET - WinForms - Instantiate a Form without showing it
short explanation: usually something like form1.show is used, so it is always changed to visible = true after the form_load is finished.
Either use the instructed event form_shown and add the visible=false
or another user recommended to change start properties to minimized and activate to hide program in taskbar. This helps to prevent that annoying flickering. I guess after that you can change the options back.
Update 2 The following seems to work well:
Private _IsVisible As Boolean
Public Property IsVisible() As Boolean
Get
Return _IsVisible
End Get
Set(ByVal value As Boolean)
_IsVisible = value
If _IsVisible Then
Me.WindowState = FormWindowState.Normal
Me.ShowInTaskbar = True
Me.Visible = True
Me.Activate()
Else
Me.WindowState = FormWindowState.Minimized
Me.ShowInTaskbar = False
Me.Visible = False
End If
End Set
End Property
If you want to get rid of the small taskbar flickering, then change the forms property showInTaskbar. When it is changed during the form_load, then there seem to be a short movement at the taskbar.
And to make it perfect, in form.Shown add following code:
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Me.Visible = IsVisible
End Sub
now it is enough to use
IsVisible = False
in form_Load, or if you want to show it
IsVisible = True
Just some ideas:
If all your tasks are completed in the _Load event try just calling End. Of course that would remove your tray icon as well.
Another possibility is to call Me.Visible in the _Shown event. This may cause a flash on the screen. If so perhaps you could position the form off the screen in _Load.