VB.Net: Dynamicly created MonthCalendar does not fire LostFocus or GotFocus - vb.net

I've created a form that has a tabbed control that gets users controls added to each tab dynamically and a StatusStrip at the bottom of the form. When the app starts, the user controls are loaded in the tabs based on security with at least 1 tab being loaded. On the StatusStrip, two ToolStripComboBoxes, 2 ToolStripButtons, 1 ToolStripLabel, and 1 ToolStripStatusLabel. Everything loads fine and works.
I've been taksed to have a MonthCalendar popup when the user presses one of the two buttons. Here's the code I use to do this:
If IsNothing(theCal) Then
theCal = New MonthCalendar
AddHandler theCal.DateSelected, AddressOf theCalDateSelected
AddHandler theCal.LostFocus, AddressOf theCalLostFocus
AddHandler theCal.GotFocus, AddressOf theCalLostFocus
theCal.Parent = Me
theCal.Top = StatusStripMain.Top - theCal.Height
theCal.Left = ComboBoxAvailableLegDay.Bounds.X
theCal.Anchor = AnchorStyles.Bottom + AnchorStyles.Left
theCal.Show()
theCal.BringToFront()
theCal.Focus()
Else
Me.Controls.Remove(theCal)
theCal = Nothing
End If
theCal is defined as Protected at the top of the form's class. So, pressing the button will create the MonthCalendar and position it correctly if it doesn't exists and if it does exists, then it is removed. This works with no problems.
My problem is that theCal never fires GotFocus or LostFocus. I've got the procedure theCalLostFocus defined as follows and it never thows the exception. I can put a breakpoint at the throw and the code never makes it to that point.
Private Sub theCalLostFocus(ByVal sender As Object, ByVal e As EventArgs)
Throw New NotImplementedException
End Sub
Clicking a date on theCal will call theCalDateSelected procedure, but clicking any other area of the form does not fire theCalLostFocus. Since the user may want to not select a date and I don't want to force them to have to press the button to remove theCal, I'd like to be able to remove theCal when it loses focus. Anyone have any idea why this is happening and anyone got a solution?
Thanks.
-NCGrimbo

i'm not that surprised that the focus event won't fire, because you add the handler before inserting it in the visual tree. try adding the handler after the call to show(). or maybe in the loaded event handler. Note that since you request the focus, your focus event handler will be called every time.
Rq : as it is written, your code has memory leak since you do not remove the event handler when you clear theCal, so since a reference is kept to theCal, neither theCal nor the event handler get cleared and this lead to memory leak (cyclical reference).

Related

Use control's events if when it is contained in a custom control

I created a custom object, name: MyList.
This Object contains a picturebox and a grid.
I need to do something if the user press on this grid, so i have to "use" MouseDown events of the grid.
I used this event in the MyList project (i can save in a propriety the result for example) but in hosts project can't.
I have only the MouseDown event of the MyList, so if i press on the "form" of the object, this events works, but if i press on the grid of this MyList.
So, i can use MouseDown Event of MyList, but how i can use Grid Events?

Form border style none was closed while minimized to tray will not restore

Created a form in VB.net 2013 with
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
And a button with
Me.WindowState = System.Windows.Forms.FormWindowState.Minimized
The issue is, if the User closes the form while the form was minimized to the taskbar, when you start the program back up again... you can see the program in the taskbar, but clicking on the taskbar icon for the program does nothing... clicking on the notification tray icon for the program does nothing... EVEN if the notification tray icon is set to
Form.Show
Form.Activate
Form.WindowState = System.Windows.Forms.FormWindowState.Normal
I have tried forcing the form to refresh.
I have tried forcing the form to redraw itself at the initial size.
The only thing that works to show it again after this defunct state is to put
Me.WindowState = System.Windows.Forms.FormWindowState.Maximized
in the form_load event, then let the form load, stop debugging, and then comment out the line again so the form goes back to how it is suppose to be.
Am I missing something?
Also, hovering over the taskbar icon for the program shows the full form in peek... so it does appear to be loaded, just not in the state that it should be in.
Chances are that you are writing the WindowState or the location and size properties when you close the form.
If saving the location and size, make sure to first check the WindowState property:
If Me.WindowState = FormWindowState.Normal Then
'// save your form size and location
End If

Why is return from MessageBox.Show not "DialogResult.Cancel" when the close button is pressed?

I'm using the following code:
Dim Reply As DialogResult = MessageBox.Show("GOT IT!")
If Reply = DialogResult.OK Then '...`
When I click the Close button (red "X" in corner) the condition looking for DialogResult.OK still evaluates to true and when I check the Reply variable's value at runtime after clicking the close button it is 1 {OK}.
From the documentation on MessageBox Class it says:
Displays a message window, also known as a dialog box, which
presents a message to the user. It is a modal window, blocking other
actions in the application until the user closes it. A MessageBox can
contain text, buttons, and symbols that inform and instruct the user.
While I find the documentation on DialogBoxes a little convoluted and confusing, it appears to me (and i could be bery wrong) that the Close button should by default set the return to IDCancel which, I must assume is somehow parsed by the MessageBox class into DialogReturn.Cancel.
So why does MessageBox not show the return form the close button as DialogResult.Cancel??
This is all very confusing to me because it seems the MessageBox class is not consistent with other forms from within the same Systems.Windows.Forms namespace.
For instance, if we look at the documentation from the Form Class's .DialogResult method, it specifically tells us the return from the close button is DialogResult.Cancel:
When a form is displayed as a modal dialog box, clicking the Close
button (the button with an X in the top-right corner of the form)
causes the form to be hidden and the DialogResult property to be set
to DialogResult.Cancel.
As already stated in the comments above, you could get IDCancel result when clicking the Close Red Button, only if you add a MessageBoxButtons enum that include the Cancel option For example MessageBoxButtons.OKCancel and others.
The MessageBox.Show method is indeed a wrapper around the WinApi MessageBox function. You could see this wrapping looking at the reference sources
The behavior of MessageBox.Show is different from the link that you have pointed. That one is relative to the WinForm engine and of course the behavior of the WinForm Form class is totally managed by the library to handle the scenarios presumed for a WinForm class.
In the WinApi documentation you could find a subtle reference in the section about the Return value where they talks about the behavior when the cancel button is present. Then trial and error confirms this assumption.
You need to pass in MessageBoxButtons as an override that includes a cancel button so like MessageBoxButtons.OKCancel.
Dim message As String = "GOT IT!"
Dim caption As String = "Fancy Caption"
Dim Reply As DialogResult = MessageBox.Show(message, caption, MessageBoxButtons.OKCancel)
If Reply = DialogResult.OK Then '...`
If you dont want the caption than skip it but you'll still need a comma, like:
MessageBox.Show("GOT IT!",,MessageBoxButtons.OKCancel)
See here for full enumeration of options for MessageBoxButtons.

How to run code on Exit vb.net

I would just like to know how to run code in vb.net when the program is closed with the red cross in the top right of the screen.
Use Form.FormClosing Event - Read the Remarks on this event documentation for better implementation of your functionality.
It occurs before the form is closed.
Check FormClosingEventArgs properties for further manipulations:
e.CloseReason
e.Close
However, canceling the event will set to true the Cancel property of
the FormClosingEventArgs class that is passed as a parameter to the
parent form. To force all MDI parent and child forms to close, set the
Cancel property to false in the MDI parent form.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
sr.WriteLine("8 - FormClosing");
}
Windows Forms Events Lifecycle
You need to handle the FormClosing event: use the CloseReason property of the FormClosingEventArgs to determine why the form is closing - you want to look for CloseReason.UserClosing - and set the Cancel property to true if you want to cancel the form close.

Windows Forms: Unable to Click to Focus a MaskedTextBox in a Non TopLevel Form

Like the title says, I've got a Child form being shown with it's TopLevel property set to False and I am unable to click a MaskedTextBox control that it contains (in order to bring focus to it). I can bring focus to it by using TAB on the keyboard though.
The child form contains other regular TextBox controls and these I can click to focus with no problems, although they also exhibit some odd behavior: for example if I've got a value in the Textbox and I try to drag-click from the end of the string to the beginning, nothing happens. In fact I can't use my mouse to move the cursor inside the TextBox's text at all (although they keyboard arrow keys work).
I'm not too worried about the odd TextBox behavior, but why can't I activate my MaskedTextBox by clicking on it?
Below is the code that shows the form:
Dim newReportForm As New Form
Dim formName As String
Dim FullTypeName As String
Dim FormInstanceType As Type
formName = TreeView1.SelectedNode.Name
FullTypeName = Application.ProductName & "." & formName
FormInstanceType = Type.GetType(FullTypeName, True, True)
newReportForm = CType(Activator.CreateInstance(FormInstanceType), Form)
Try
newReportForm.Top = CType(SplitContainer1.Panel2.Controls(0), Form).Top + 25
newReportForm.Left = CType(SplitContainer1.Panel2.Controls(0), Form).Left + 25
Catch
End Try
newReportForm.TopLevel = False
newReportForm.Parent = SplitContainer1.Panel2
newReportForm.BringToFront()
newReportForm.Show()
I tried your code and got a good repro this time. As I mentioned in my original post, this is indeed a window activation problem. You can see this in Spy++, note the WM_MOUSEACTIVATE messages.
This happens because you display the form with a caption bar. That convinces the Windows window manager that the window can be activated. That doesn't actually work, it is no longer a top-level window. Visible from the caption bar, it never gets drawn with the "window activated" colors.
You will have to remove the caption bar from the form. That's best done by adding this line to your code:
newReportForm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Which will turn the form into a control that's otherwise indistinguishable from a UserControl. You can still make it distinctive by using this code instead:
newReportForm.ControlBox = False
newReportForm.Text = ""
Either fix solves the mouse click problem.
This is a miserable bug and it took me a long time to find this question. We're doing exactly the same thing as the OP, displaying a Form inside a split container. My workaround was to add an event handler to the MaskedTextBox's Click event:
private void MaskedTextBoxSetFocus(object sender, EventArgs e)
{
var mtb = (MaskedTextBox)sender;
mtb.Focus();
}
This works for the MaskedTextBox but I'm concerned about other odd behavior due to this bug so I will probably set the border style as in the accepted answer.
The text box behavior is a symptom of the same problem. Something is swallowing mouse down notifications. It isn't explained by your code snippet. Forms indeed swallow the mouse click that activates them, but that is a one-time behavior and is turned off by setting its TopLevel property to False.
Not much left. One candidate is the Control.Capture property, turned on at the MouseDown event for a button so that the button can see the MouseUp event, no matter where the mouse moved. That's a one-time effect as well. Watch out for controls that set the Focus in a MouseDown event.
The other is some kind of IMessageFilter code in your form(s) that's eating WM_LBUTTONDOWN messages.