Balloon tip notifications not clearing from the sys tray? - vb.net

I have created a VB.Net program that uses the following code to send balloon tip notifications to the systray:
notify = New NotifyIcon
notify.Visible = True
notify.BalloonTipTitle = title
notify.BalloonTipText = body
notify.Icon = SystemIcons.Application
notify.ShowBalloonTip(100000)
However, the icon for this notification remains in the sys tray after the user has closed the application, and there seems to be no simple way to remove it by clicking on it.
How might I dead with this issue?

It's because you are not disposing the NotifyIcon object. Why exactly are you creating it in code in the first place? Unless you have a specific reason not to, you should be adding it to the form in the designer and then just setting properties and calling methods in code. That way, the object will be disposed when your form is. Failing that, you need to dispose it yourself when you're done with it, which means retaining a reference as long as required and calling Dispose explicitly.

Related

VB.NET access winforms non-public member

In my application that uses a multi-document interface model I have one of the windows that is constantly refreshing itself in an asynchronously. And when the UI launches another window (wizard for instance), newly created window can in some cases loose focus(wasn't able to reproduce this behavior, but is was reported by many).
I think this can be related to the fact that when async function finishes in main window it actually grabs the focus back(but apparently it only happens when wizard window doing some computation).
I was planning to cancel the timer updates in a main window when it is not active. But hit a problem of inability to access "My.Active" property.
I can see it in a debug but cannot access it from the code:
This is a partial screenshot of "My" component:
I must be missing something simple, but wasn't able to figure this out for a couple hours now.
I ended up using Reflection to get the property as it was suggested in comments to my question. It's not pretty but it works for my current scenario.
Here is the solution:
Dim prop As System.Reflection.PropertyInfo = Me.GetType().GetProperty("Active",
System.Reflection.BindingFlags.NonPublic Or
System.Reflection.BindingFlags.Instance)
Dim value As Boolean = prop.GetValue(Me)

How should you reload a form and have it re-initialize?

A older application loads some forms using implicit instances:
form2.showdialog()
Sometime between VS2008 32-bit and VS2013 64-bit, the forms stopped being initialized when they are reloaded. For example, if you load a form, close the form (using the Close method), and load the form again, the classes and controls (and, I assume, the form) are not initialized as new instances.
Re-initialization can be accomplished by putting me.dispose() in the FormClosed event, or by using an explicit instance of the form:
Using frm As New Form2
frm.ShowDialog()
End Using
Is there a good reason to use one of these methods over the other, or is there another method that should be used to cause a form to be initialized when it is reloaded?
Dispose will be called automatically if the form is shown using the Show method. If another method such as ShowDialog is used (your case it is), or the form is never shown at all, you must call Dispose yourself within your application. You can also handle the dispose by moving it from the designer file into the code file and handle things there as well.
On the other hand, Using statement typically makes your application safer to maintain and less prone to deadlocks and other misbehavior related to the lifecycle of the resource. I would stick by using this approach.
Also you cant put Me.Dispose in the Form Closed event (possible issues). If your using ShowDialog it will fail as it will dispose your objects first, if you need them they are gone.
Here's more on dispose: https://msdn.microsoft.com/en-us/library/aw58wzka(v=vs.110).aspx
The Form object and its child controls are not automatically disposed when you display the form with ShowDialog(). That sounds pretty quirky but this was done for a very good reason. After ShowDialog returns DialogResult.OK, you are normally going to obtain the dialog results. What nobody likes is that failing because of a ObjectDisposedException. Which would be likely to occur since the dialog results are often stored in controls.
You should always use the Using statement to ensure the form object and all of its controls are disposed.
A possible corner case is intentionally not disposing it because you like the redisplay the dialog with the original entered values. Which is not completely wrong, it is however a very expensive way to preserve those values. Those undisposed window objects cost an arm and a leg in system resources.
Pretty clear explanation from MSDN
Unlike non-modal forms, the Close method is not called by the .NET
Framework when the user clicks the close form button of a dialog box
or sets the value of the DialogResult property. Instead the form is
hidden and can be shown again without creating a new instance of the
dialog box. Because a form displayed as a dialog box is hidden instead
of closed, you must call the Dispose method of the form when the form
is no longer needed by your application.
When ShowDialog() called and closed, instance of the form will remain in the memory, and can be used again, for example get a result from some public property.
If you not using anymore this form, you need to call Dispose method to dispose form and form's controls
Dim myform As New MyDialogForm()
myform.ShowDialog()
Dim result As Object = myForm.SelectedResult()
myform.Dispose() 'need to call manually, if instance not used anymore
When you use Using keyword then Dispose method will be executed automatically at the end of the Using block
Dim result As Object
Using myform As New MyDialogForm()
myform.ShowDialog()
result = myForm.SelectedResult()
End Using 'myform.Dispose will be called
Bottom line: Both methods doing a same things.
But Using block will call Dispose method automatically
P.S. Putting Me.Dispose in the FormClosed eventhandler then
- instance of the form will stay in the memory even form was closed
- and will work only until you tried using disposed controls again. If you will try to show disposed object then ObjectDisposedException will be thrown.
If you not using form anymore then Using block will be best method

Operating a runtime webbrowser control from a background thread vb.net

I'm trying to use a bunch of webbrowsers in some background threads. This works no problem when I use webbrowser controls that i have placed on the form in design view but now when they are created at runtime.
I declare the webbrowsers array globally:
Dim webbroswers(-1) As WebBrowser
The following code is on the main thread:
ReDim Preserve webbroswers(somenum)
For i = 0 To sumnum
webbroswers(currentbrowsermax + i) = New WebBrowser
Next
Then this code is run on the background thread:
If webbroswers(num).InvokeRequired Then
webbroswers(num).Invoke(Sub() webbroswers(num).Navigate(someurl))
Else
webbroswers(num).Invoke(Sub() webbroswers(num).Navigate(someurl))
The program crashes at this point with the following error:
Unable to get the window handle for the 'WebBrowser' control. Windowless ActiveX controls are not supported.
Any help on this would be great. Also if anyone knows how to suppress script errors then I think this might help. I've tried: WebBrowser(num).ScriptErrorsSuppressed = True but this doesn't work (it doesn't work elsewhere in my code when running on the main thread either) Thanks!
The Control.InvokeRequired and Invoke members use the Handle property to figure out what thread owns the control. Problem is, the Handle is null for the web browsers that you created. A control only has a valid handle when you made it visible on a form. Which you didn't do. It will then try to create the handle but that's a fail whale, an ActiveX control like WebBrowser needs a valid Parent. Without Me.Control.Add(), as was done in your original version, it won't have one.
The workaround is simple, you just need another control with a valid Handle property. Any will do, it only cares about the thread that owns the handle, not the value of the handle.
You have one: your form. Use Me.InvokeRequired and Me.Invoke() instead. Or Application.OpenForms(0) if you can't easily get a reference to the form object, best avoided.

What is the correct way to fully remove a control from a parent control/form?

I have a UI element in my application where a Panel is used to host one of several potential custom UserControls. The Panel itself is hosted in a standardised UserControl that I am using something like a non-modal dialog that I'm calling a 'pane'.
The method I use is to instantiate a new instance of the standard pane, then with logic instantiate one of the several optional hosted controls inside it using Panel.Controls.Add(control). I then add the new pane to the interface control in a set location, again with a Control.Controls.Add(control), followed by a control.BringToFront() to maximise its z position.
This all works well, however when the time comes to hide the pane and destroy it, I cannot seem to fully get rid of it. Originally I was simply using Control.Controls.Remove(control) and for good measure setting the pane's Parent property to Nothing. This would have the desired effect of making the pane disappear, and my assumption was that now the control was unreferenced, that GC would dispose of it.
What I am seeing however is that the control still blits instantaneously onto the screen when the next outer hosting TabControl changes tab page, implying it still exists somewhere. I can confirm that this is not a graphical issue and the pane object persists using the VS Watch window's 'Make Object ID'. (At least I think this is proof, that without a code-accessible reference I can still directly see the object and its properties continue to exist.)
I have tried replacing
Control.Controls.Remove(pane)
pane.Parent = Nothing
with
pane.Dispose()
GC.Collect()
where the Dispose call I can confirm both removes the control from its parent's Controls collection and sets its Parent property to Nothing, but appears to do no more. It persists after forced GC and still blits onscreen occasionally.
This all leads to my original question, what is the proper way to remove and fully destroy controls after they have served their purpose?
According to this article from MSDN it seems like you might be experiencing side affects from the object being on the finalization queue.
A Dispose method should call the GC.SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, GC.SuppressFinalize prevents its Finalize method from being called.
Translation: The finalize method isn't being called, and so the resources associated with your control are not being released. After a bit more digging, I found that you should
Always call Dispose before you release your last reference to the Component. Otherwise, the resources it is using will not be freed until the garbage collector calls the Component object's Finalize method.
From this article.
So either you need to release your last reference OR you need to call the components finalize method directly so your GC.Collect() will work.

Controls disappearing on timer event-vb.net

We have a question regarding VB.Net 2008.
We are used control array in vb.net and third party timer controls.
When handle received from external application to timer control event procedure,
after this form becomes blank and controls disappear.
What we have to do to persist the controls.
You asked what you have to do to persist the controls. It's not clear whether you mean winforms or webforms, but I can answer for both possibilities:
If it's the former, you have it backwards. The default behavior of all controls is that they are "persisted" until you tell them otherwise. If anything disappears, it's because you have code somewhere that tells it to. That's where you need to start looking.
If it's webforms/ASP.Net, the problem is that you don't understand the page lifecycle. Everything that raises server events, including your third party timer controls, causes a post back. That's how events work - the browser posts the form back to the same url in such a way that the server knows to call a your event code at the right time. The thing here is that as far your server is concerned, it's still just a new http request, and that means you're working with a brand new instance of your page class every time this happens. If you've previously added some controls to your page, it doesn't matter. That was an old instance that was discarded and probably disposed by the time the page was visible in the user's browser. If you want to keep those controls, you need to make sure you add them to the page on every postback.