Reputation: 20464
In C# or Vb.Net, using managed or unmanaged code, how I could retrieve the owner Form
of a NotifyIcon
?
I've checked the base types of NotifyIcon
Class and also the ComponentConverter
trying to find out a possible type-casting to obtain the Form, but I was not able to.
I also seen the NotifyIcon.ContextMenuStrip.FindForm()
function, but for any reason when I assign a contextmenustrip the FindForm()
function always returns a null-reference exception, and anyways even if it could work will not be a safe approach because I could have a notifyicon without a contextmenu.
My intention is to pass a NotifyIcon
as an argument to some methods that will perform common tasks to save me time and reduct code.
Pseudo example:
Public Shared Sub MinimizeToSystray(ByVal ntfy As NotifyIcon)
If (ntfy Is Nothing) Then
Throw New ArgumentNullException(paramName:="ntfy")
ElseIf (ntfy.Icon Is Nothing) Then
Throw New ArgumentException(message:="The NotifyIcon doesn't have an icon.",
paramName:="ntfy")
Else
Dim f As Form = ntfy.GetOwnerForm()
f.WindowState = FormWindowState.Minimized
f.Hide()
ntfy.Visible = True
End If
End Sub
Upvotes: 3
Views: 674
Reputation: 941665
The FindForm() method can only find the form for controls. The kind that derive from Control and are embedded in a form through its Parent property. But NotifyIcon is not a control, it is Component. A Component only has a Site property, its value is only defined at design time.
There is a casual relationship between a component and the form, Winforms promises to automatically dispose any components that have a constructor overload that takes an IContainer argument. Not all them do, OpenFormDialog and BackgroundWorker for example don't, NotifyIcon does. They omit the constructor when they don't need disposal.
Which makes it technically possible to find the form back. You'd need to iterate Application.OpenForms(). And use reflection to iterate their private components
collection. Do note that this can only work when the form was actually opened, its Show() method must have been called.
That's a solution that scores -100 points, it is both ugly and error prone. The simple and always-correct solution is to just add an extra argument to the method to allow passing the "owner" form. With the assumption that, since the caller needs to know the NotifyIcon instance, it also should know the form. Typically Me
.
Upvotes: 4
Reputation: 125227
Component doesn't have a FindForm
method like controls and if you need such property you should customize the component and apply a workaround. Unfortunately NotifyIcon
is sealed
and can not be inherited.
As mentioned by Ivan Stoev in comments, you can use Tag
property to store a reference to the container form.
But If you are looking for a designer based solution that works without writing such initialization codes to set the Tag
, as a good option, you can create an extender component that adds a property ParentForm
to your NotifyIcon
component and set the property at design-time, then you can simply use it at run-time and when setting the ParentForm
property at design-time you can set Tag
property in component code, and then use it at run-time.
And here is the usage:
Add a the ComponentExtender
(see the code at the end of post) to your project, then build the project. Then:
ComponentExtender
from toolbox to your formParentForm on componentExtender1
property of your notifyIcon1
at designer using property grid:Use this code to find the parent form of your notify icon:
var parent = this.notifyIcon1.Tag as Form`
Code
Here is an implementation that I used and works properly:
[ProvideProperty("ParentForm", typeof(NotifyIcon))]
public class ComponentExtender
: System.ComponentModel.Component, System.ComponentModel.IExtenderProvider
{
private Hashtable components;
public ComponentExtender() : base() { components = new Hashtable(); }
public bool CanExtend(object extendee)
{
if (extendee is Component)
return true;
return false;
}
public Form GetParentForm(NotifyIcon extendee)
{
return components[extendee] as Form;
}
public void SetParentForm(NotifyIcon extendee, Form value)
{
if (value == null)
{
components.Remove(extendee);
component.Tag = null;
}
else
{
components[extendee] = value;
component.Tag = value;
}
}
}
Upvotes: 2