Microsoft Office BeforeCloseHandler - vb.net

I made a function in vb.net for desktop application that totally saved the documents before closed, I implemented it with the System.Threading.Timer.
I'm asking with favor on how you experienced it.
So, I made a timer to saved the documents before closed.
But, upon testing without the timer, just one call to the function or Handler, the documents are not saved before closed, because a dialog box appears asking to saved or not or cancel.
Is it really in need to have the timer? because we know a timer could delay the system even a single milliseconds.
I setup the timer with 100 milliseconds.
But, I don't want to use the timer, I want to saved the documents before closed for just one call of the function.
Is it really using the timer is the solution? or it can be done with just one call setup?
If it can be done in one function call, then I think I'm missing a code.
Thanks for your opinion and experienced.

You can handle the FormClosing event. In the handler you can perform actions before the form closes you can even cancel the closing event. Here's a an example:
Dim Saved As Boolean = False
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If Not Saved Then
Dim Result As DialogResult = MessageBox.Show("Do you want to save your text?", "Save Text?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
Select Case Result
'Since pressing the No button will result in closing the form without
'saving the text we don't need to handle it here
Case Windows.Forms.DialogResult.Yes
SaveText_Click()
Case Windows.Forms.DialogResult.Cancel
e.Cancel = True
End Select
End If
End Sub
Private Sub TextBox1_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBox1.TextChanged
Saved = False
End Sub
'SaveText is a button for the user to manually save the text on demand.
'Since we don't need the sender or the eventargs, we can handle the click event without them.
'this way we can call this like any sub without having to worry about providing the right parameters.
Private Sub SaveText_Click() Handles SaveText.Click
'Add your procedure to save the text here
Saved = True
End Sub
If you don't want the option to close without saving just omit the messagebox and the select block and just call SaveText() and include the code to save your data in there.

Related

Avoid refresh event in a WebBrowser control?

I am using the GEPluginControl in VB.NET (VS2010).
My app works fine. I am using the GEWebBrowser control (included on the GEPluginControl), and I am able to show the information in the Google Earth format.
However, I am having troubles when the GEWebBrowser control Refresh method is called. When this happens, the GEWebBrowser starts to fail (the earth disappears and I am not able to reload it again).
I am not calling the Refresh method explicitly. I think this method is called automatically in the following case: when the user close the window, I'm catching the event Form_Closing, in order to ask the user if really wants to exit. If the answer is No, the user will stay on the app, but the GEWebBrowser control appears blank!. I can hear the sound associated to the refresh method, so I think this method may be my trouble.
Here is the Form_Closing event code:
Private Sub frmPrincipal_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If MessageBox.Show("Quit", "Really want to exit?", _
MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
'App end.
server.Stop()
Else
'User decides to stay.
e.Cancel = True
End If
End Sub
Does anybody knows how to avoid the WebBrowser (GEWebBrowser in this case) to execute the refresh method? If anyone knows how to solve this in any other way, I would still be very grateful.
You could try this (not guaranteed to work):
Private Sub StopRefresh(sender As System.Object, e As System.EventArgs) Handles WebBrowser1.ProgressChanged
WebBrowser1.Stop()
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.

Windows Form Cancel Button Not Working

I have a Visual Studio, Visual Basic form that includes an OK button and a Cancel button.
What I want to do is have the OK button save the options that the user chooses and of course the Cancel button discarding them and returning them to their previous values.
But what I'm noticing is that as I'm debugging the form, the values are being saved regardless of whichever button I'm choosing. On the form's properties, I have declared that indeed the CancelBtn is the CancelBtn and that the OK button is the OK button, but the values are still being saved regardless.
Is there a better way to do what I would like this form to do?
EDIT:
Here's the code so far for the two buttons, both are being set to close the window. AcceptOption should save the values and CancelOption should just close the form. I'm sorry if this isn't done well but the FAQ's that I found only mention changing the properties of each button and nothing about the code.:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles AcceptOptionBtn.Click
' Save the Options
Me.Close()
' Close the form
End Sub
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles CancelOptionBtn.Click
' Close the form
Me.Close()
End Sub
Don't change "the values" until the user clicks the Save button.
The form should be preloaded with a copy of the values you would like to update.
The Cancel button should just close the form.
The Save button should cause "the values", not the forms copy, to be updated.
EDIT:-
In regard to this question, there is nothing wrong with the code you have posted. Are the right handlers being called for the right button clicks? Are the form's AcceptButton and CancelButton properties set to the right buttons?
What data are your editing controls bound to, if at all?
There's nothing magical about OK and Cancel buttons. They're just... buttons. If you save your data every time a change is made, the Cancel button won't magically "unsave" them. Though if you save changes in the OK button's Click event handler, then clicking the Cancel button obviously won't save your changes. To help you further we'd need to know how you save your data.
Edit:
From looking at your code, I think you're passing data directly to your form, without performing a copy of your objects. Therefore if you modify this data, it will also be changed in the parent form. By working with a copy of your data in this form, any changes which aren't saved will be correctly discarded.
Your event handler for the cancel button should look like this:
Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click
Me.Close()
End Sub
Your event handler for the OK button should look like this:
Private Sub btnOK_Click(sender As System.Object, e As System.EventArgs) Handles btnOK.Click
SaveSettings 'call a routine to save the settings the user has entered
Me.Close()
End Sub
It is as simple as that!
If you open your form like
myForm.showdialog()
you don't have to define the handler for the close button click event, it is automatically handled; just set the 'DialogResult' property for the button
btnCancel.DialogResult = DialogResult.Cancel
Also if you want to close the form when ESC is pressed then set the 'CancelButton' property for the form:
myForm.CancelButton = btnCancel
On the other hand if you open the form like
myForm.Show()
you do need to specify the action(s) to take on the close button click event as indicated here, ie:
Private Sub BtnCancelClick(ByVal sender As System.Object, ByVal e As EventArgs) Handles btnCancel.Click
Close()
End Sub
I was having the same issues. As soon as I use My.Settings.Blabla = Blabla.value, it gets saved even if I haven't used My.Settings.Save() which makes My.Settings.Save() completely pointless as far as I can tell.
I ended up taking up Jordell's advice: Don't change "the values" until the user clicks the Save button but it wasn't too clear for me how to go about it.
I ended up using temporary variables in all my settings subs instead of the user My.Settings.UserConfigs. Only when I was in the OK sub did I call
My.Settings.UserConfigSetting = temporary_UserCofigValue
Here is an example from the code I was working on:
Private Sub btnOptionsThemeLB_Back_Update_Click(sender As System.Object, e As System.EventArgs) Handles btnOptionsThemeLB_Back_Update.Click
If (tempOptionsThemeLB_Back = Nothing) Then
tempOptionsThemeLB_Back = Me.btnOptionsThemeLB_Back.BackColor
End If
tempOptionsThemeLB_Back = RGBToColor(txtbOptionsThemeLB_Back_Red.Text, txtbOptionsThemeLB_Back_Green.Text, txtbOptionsThemeLB_Back_Blue.Text, tempOptionsThemeLB_Back)
Me.btnOptionsThemeLB_Back.BackColor = tempOptionsThemeLB_Back
End Sub
And only withing the Ok sub did I call My.Settings.
'Theme Section
My.Settings.colorBtnBack = tempOptionsThemeLB_Back

VB.Net: Understanding the way Application.Run() works

Hans Passant gave me a great answer here, so I thought of asking for more details to try to understand the way Application.Run() works.
As far as I understand from the docs, it seems that Application.Run() starts a message loop on the current thread, which in turns enables it to process user input (Is that right?). The overloaded version Application.Run(Form) basically does the same, only it exists when the form closes, and it shows the form by default.
That raises a few questions:
How would one do to simply call from the Main() sub a function that can communicate with the user to (message boxes and so on) and wait for it to exit?
When the message loop is started without a form, how do you launch a new form from this loop, and wait for it to exit? ShowDialog could work, unless you don't want the form to display immediately when launched (eg. if you have a for that's launched minimized to the system tray)
Basically, the situation would be as follows: sub `Main` has a list of tasks to execute in 20mn, with a system tray icon telling the user that the program will operate in 20mn. A timer ticks after 20mns, and has to execute say approx. 15 tasks one by one, every time creating an instance of a progress dialog, initially hidden in the taskbar.
`ShowDialog` would display the form, which is not wanted; so the way I would do it would be to pass the progress dialog a callback to a function that starts the next task. But that wouldn't exit the first progress form before the second has exited, would it? Which means 15 forms would end up being opened...
So the solution may be to invoke (begininvoke?) the callback on the main application loop... Only, I don't know how to do this, because I don't have a form associated with the loop to invoke the callback on...
I hope my questions are clear (I might confuse many things, sorry),
Thanks,
CFP.
Drop a Timer, ProgressBar and a BackgroundWorker on the form. First thing you'll want to do is to prevent the form from getting visible when the program is started. Paste this code into the form class:
Protected Overrides Sub SetVisibleCore(ByVal value As Boolean)
If Not Me.IsHandleCreated Then
value = False
Me.CreateHandle
End If
MyBase.SetVisibleCore(value)
End Sub
Use the timer to get the job started. Set its Interval and Enabled properties, add the Tick event handler:
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Show()
ProgressBar1.Visible = True
Me.Enabled = False
BackgroundWorker1.RunWorkerAsync()
End Sub
That makes the form visible when the job is started and starts the background worker. Set the BGW's WorkerReportsProgress property to True and add the 3 event handlers:
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'' Do stuff here, call BackgroundWorker1.ReportProgress to update the PB
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
ProgressBar1.Value = e.ProgressPercentage
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
ProgressBar1.Visible = False
Me.Enabled = True
Me.Hide()
End Sub
It is up to you to fill in the code for the DoWork event handler. Have it do those 15 jobs, be sure to call BackgroundWorker1.ReportProgess so that the progress bar gets updated. Which is what the ProgressChanged event handler does. The RunWorkerCompleted event handler hides the form again.
You can call the Show() method in the context menu item event for the NotifyIcon so that the user can make your form visible again. Call Application.Exit() in the context menu item that allow the user to quit your app. Make sure you disable that when the BGW is running. Or implement a way to cleanly stop the job.

Where do I control the behavior of the "X" close button in the upper right of a winform?

I'm venturing into making my VB.NET application a little better to use by making some of the forms modeless.
I think I've figured out how to use dlg.Show() and dlg.Hide() instead of calling dlg.ShowDialog(). I have an instance of my modeless dialog in my main application form:
Public theModelessDialog As New dlgModeless
To fire up the modeless dialog I call
theModelessDialog.Show()
and within the OK and Cancel button handlers in dlgModeless I have
Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
Me.DialogResult = System.Windows.Forms.DialogResult.OK
Me.Hide()
End Sub
Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click
Me.DialogResult = System.Windows.Forms.DialogResult.Cancel
Me.Hide()
End Sub
and that seems to work fine.
The "X" button in the upper right is getting me, though. When I close the form with that button, then try to reopen the form, I get
ObjectDisposedException was unhandled. Cannot access a disposed object.
I feel like I'm most of the way there but I can't figure out how to do either of the following:
Hide that "X" button
Catch the event so I don't dispose of the object (just treat it like I hit Cancel)
Any ideas?
The class of this dialog is System.Windows.Forms.Form.
Catch the FormClosing event and, if the reason is UserClosing, set Cancel on the event to true.
Something like the following:
Private Sub Form1_FormClosing(sender as Object, e as FormClosingEventArgs) _
Handles Form1.FormClosing
if e.CloseReason = CloseReason.UserClosing then
e.Cancel = true
Me.Hide()
end if
End Sub
Use Me.Close() to hide the form. To open it, use the following snippet:
If theModelessDialog.IsDisposed Then
theModelessDialog = New dlgModeless
End If
dlgModeless.Show()
If this is saving data, then you'll need to figure some way of storing it (perhaps in a static variable/s in the form). This is the proper way to do what you are trying to achieve though.
You'll also have to forgive me if my VB is off, it's been a while.
the formclosing event allows me to do a managed exit of the form so I have included a question to confirm to exit. I also have a form flag bterminate to force the cancel where i want it to and therefore not ask the question. Thanks your suggestion helped me as well :)
Dim msgboxresponse As MsgBoxResult
If e.CloseReason = CloseReason.UserClosing Then
If Not Me.bTerminate Then
msgboxresponse = MsgBox("Are you sure you want to cancel adding?", _
MsgBoxStyle.Question + MsgBoxStyle.YesNo, Me.Text)
If msgboxresponse <> MsgBoxResult.Yes Then
e.Cancel = True
Return
End If
End If
End If
#John was Hiding the form in his code and the answers above provide a solution to that case. Often, though, you are not planning to use the form again, so you really do want the form to be Disposed. All Close related activities will be in one place if you Handle the FormClosing event using Me.FormClosing by adding it to anyCancel/Close/Exit code that you already have. e.g. in #John's case:
Private Sub Cancel_Button_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Cancel_Button.Click, Me.FormClosing
....More code
Me.Dispose
End Sub
Note the use of the Me.Dispose instead of any existing Me.Close. If you leave the Me.Close you'll create an infinite loop. See this for the subtle differences between Close and Dispose.
Agree with handling the FormClosing event. Or change the properties on the form to hide the system X control.
I've tried everything and it didn't work
if you just want to close, without showing an messagebox, you will just need:
Private Sub FORM1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
>e.Cancel = False
>FORM2.Show() (if you want to show another form)
End Sub
Hope this helps you...!