Forms acting unexpectedly - vb.net

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()

Related

Most efficient way to programmatically update and configure forms and controls

I am looking for a way to prevent user form controls from appearing one by one when I'm programmatically adding them and for ways to enhance application performance and visual appeal.
Say, I have a Panel_Top in which I programmatically add comboboxes. What is happening is that they appear one by one as they are created and I am looking for a way to suspend the refreshing of the panel and or user form to make all of those programmatically added comboboxes to appear at the same time and faster than it happens right now.
I've tried suspendlayout which doesn't do anything for me or maybe I'm doing it wrong.
MyForm.PanelTop.SuspendLayout = true
And also I've tried to set the Panel_Top to invisible like:
MyForm.Top_Panel.visible = false
Which kind of sorta looks and performs better, or it might be a placebo.
What is the correct approach to this problem?
PS: I do have form set to doublebuffer = true, if that matters
What I tend to do is create a loading modal to appear on top of the form rendering the controls that need to be created/made visible, this can optionally have a progress bar that gets incremented as the control is created/shown. With the loading modal running, the container that needs to add the controls starts with SuspendLayout, adds the controls, and then finished with ResumeLayout.
This makes it so that controls are added/shown while giving the user a visual indicator that something is going on behind the scenes.
Here is a phenomenal example of a loading modal: https://www.vbforums.com/showthread.php?869567-Modal-Wait-Dialogue-with-BackgroundWorker and here is an example of using it:
Private ReadOnly _controlsToAdd As New List(Of Control)()
Private Sub MyForm_Show(sender As Object, e As EventArgs) Handles MyBase.Shown
Using waitModal = New BackgroundWorkerForm(AddressOf backgroundWorker_DoWork,
AddressOf backgroundWorker_ProgressChanged,
AddressOf backgroundWorker_RunWorkerCompleted)
waitModal.ShowDialog()
End Using
End Sub
Private Sub backgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs)
Dim worker = DirectCast(sender, BackgroundWorker)
For index = 1 To 100
_controlsToAdd.Add(New ComboBox() With {.Name = $"ComboBox{index}"})
worker.ReportProgress(index)
Threading.Thread.Sleep(100) ' Zzz to simulate a long running process
Next
End Sub
Private Sub backgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
Dim percentageCompleted = e.ProgressPercentage / 100
' do something with the percentageCompleted value
End Sub
Private Sub backgroundWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
PanelTop.SuspendLayout()
PanelTop.Controls.AddRange(_controlsToAdd.ToArray())
PanelTop.ResumeLayout()
End Sub
SuspendLayout() is the correct way to handle this with WinForms.
But first of all, this is a function you call, and not a flag you set.
Secondly, don't forget to call ResumeLayout() at the end of the changes.
Finally, you need to ensure you only call them once when you start to change around the controls in the panel and then again at the very end. If you use them with every control you won't get any benefit.
So the pattern might look something like this:
Public Sub SomeMethod()
PanelTop.SuspendLayout() ' Prevent the panel from updating until you've finished
' Make a bunch of changes
PanelTop.Controls.Clear()
For Each ...
PanelTop.Controls.Add( ... )
Next
PanelTop.ResumeLayout() ' Allow the panel to show all the changes in the same WM_PAINT event
End Sub
You also need to ensure you don't have anything in there like DoEvents()/Invalidate() that might invoke the windows message loop and cause the form to redraw itself.

vb.net a forms "new" routine is being called before I even invoke the form

I have a form called "partmanager". On it is a button to show another form "parteditor" to allow editing details of a part. Clicking that button will show the form and pass in a variable to the parteditors "new" routine.
My problem is that when the calling form (partmanager) starts, it immediately calls new routine in the parteditor form before it (partmanager) is even initialized so the parteditor form does not get the string that is supposed to be passed in. Later, when the calling form is visible and I click the button to show the parteditor form, new has already been prematurely called and so is not called again and the form does not get the string passed in.
I hope this makes sense!
I can implement a property in the parteditor form and pass in my variable that way prior to showing the form and that will work, thereby not even requiring a "new" routine in the parteditor forms code.
So my question is, is implementing the property the proper way to pass this variable to the form being called, or am I not properly coding my forms? (I also have an intermediary module called "commands" where I have been defining command procedures, in this case just showing a form.)
any pointers would be appreciated, thanks!
here is the code for the button in the calling form:
Private Sub EditButton_Click(sender As Object, e As EventArgs) Handles EditButton.Click
Commands.EditPart(_PartNumber) 'call the editpart command
Me.Close()
Me.Dispose()
End Sub
here is the code for the form being called:
Public Class PartEditForm
Private _partNumber As String = String.Empty
Public Sub New(partNumber As String)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_partNumber = partNumber
End Sub
Private Sub PartEditForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Label1.Text = _partNumber
End Sub
End Class
and here is the code in my "commands" module for loading/showing the form:
Public PartEditForm As New PartEditForm(_partNumber)
Public Sub EditPart(partnumber As String)
If PartEditForm.IsDisposed Then
PartEditForm = New PartEditForm(partnumber)
End If
PartEditForm.Show()
End Sub
you can save the routine in a dim variable and get this on the other form and close the first form or hide but you need get in new var and contine where stop before.

Working with passed data between forms

Currently in my windows form, I have a few WinForms to work with. One WinForm acts as a main menu and is supposed to call another form as a secondary window on its own.
Private Sub btnMainGame_Click(sender As Object, e As EventArgs) Handles btnMainGame.Click
' This is the button to call up the main game controller. So simply hide this form aned then open the new form.
Dim frmController As New frmControllerScreen
frmController.Show()
Me.Hide() ' Happens on .Close as well
End Sub
The above code invokes another WinForm which is used to handle more options. When the user clicks on a particular button, a sub form is created again.
Dim OpenNewGameWindow As New frmGameConfig
OpenNewGameWindow.ShowDialog(Me)
Me.DialogResult = DialogResult.None ' Used to prevent the subform from closing the main form when it catches a dialog result.
Now in the frmGameConfig, the program is supposed to take data and pass it back to the form that called it.
Private Sub btnNewGameStartGame_Click(sender As Object, e As EventArgs) Handles btnNewGameStartGame.Click
' ... Skipped code...
frmControllerScreen.MasterQuestionList = QuestionList
frmControllerScreen.blnBankedTime = cbBankedTime.Checked
' ... Skipped code...
End Sub
However, when the frmController tries to reference MasterQuestionList... it returns a nullreference error as if it was not set.
Here's where things get funny...
When I made this code, frmControllerScreen was actually the startup form. Now when I change this form back to frmMainMenu, I get NullReference errors constantly.
My question: How am I supposed to pass information from one form to the next form if it was instantiated from a parent form. (Note I even moved the declartion to Public as a "module-wide" variable... and nothing happens but the same result.) The same error happens even if I go ahead and declare frmController.MasterQuestionList as well.
Instead of trying to pass data back from the called form to the caller, you can reference the called form's controls from the calling code after .ShowDialog.
Dim OpenNewGameWindow As New frmGameConfig
If OpenNewGameWindow.ShowDialog() Then
MasterQuestionList = OpenNewGameWindow.QuestionList
blnBankedTime = OpenNewGameWindow.cbBankedTime.Checked
End If
In OpenGameWindow button click:
Private Sub btnNewGameStartGame_Click(sender As Object, e As EventArgs) Handles btnNewGameStartGame.Click
Me.DialogResult = True
End Sub

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.