C# 获取NotifyIcon的所有者表单?
在C#或Vb.Net中,使用托管或非托管代码,如何检索C# 获取NotifyIcon的所有者表单?,c#,.net,vb.net,forms,winforms,C#,.net,Vb.net,Forms,Winforms,在C#或Vb.Net中,使用托管或非托管代码,如何检索通知图标的所有者表单 我已经检查了NotifyIcon类的基本类型,以及ComponentConverter试图找到一个可能的类型转换来获得表单,但是我没能找到 我还看到了NotifyIcon.ContextMenuStrip.FindForm()函数,但由于任何原因,当我分配ContextMenuStrip时,FindForm()函数总是返回空引用异常,而且无论如何,即使它可以工作也不是一种安全的方法,因为我可以在没有contextmenu
通知图标的所有者表单
我已经检查了NotifyIcon
类的基本类型,以及ComponentConverter
试图找到一个可能的类型转换来获得表单,但是我没能找到
我还看到了NotifyIcon.ContextMenuStrip.FindForm()
函数,但由于任何原因,当我分配ContextMenuStrip时,FindForm()
函数总是返回空引用异常,而且无论如何,即使它可以工作也不是一种安全的方法,因为我可以在没有contextmenu的情况下使用NotifyIcon
我的意图是将一个NotifyIcon
作为参数传递给一些方法,这些方法将执行常见任务以节省我的时间并减少代码
伪示例:
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
FindForm()方法只能找到控件的表单。从控件派生并通过其父属性嵌入到窗体中的类型。但NotifyIcon不是控件,它是组件。组件只有站点属性,其值仅在设计时定义
组件和表单之间存在偶然关系,Winforms承诺会自动处理任何具有构造函数重载(采用IContainer参数)的组件。并非所有人都这样做,例如OpenFormDialog和BackgroundWorker不这样做,NotifyIcon这样做。当它们不需要处理时,它们省略了构造函数
这使得从技术上可以找到表格。您需要迭代Application.OpenForms()。并使用反射来迭代它们的私有组件
集合。请注意,这只能在表单实际打开时才起作用,必须调用其Show()方法
这是一个得分为-100分的解决方案,它既丑陋又容易出错。简单且总是正确的解决方案是只向方法添加一个额外的参数,以允许传递“owner”表单。假设调用方需要知道NotifyIcon实例,它也应该知道表单。通常Me
组件没有类似控件的FindForm
方法,如果需要此类属性,则应自定义组件并应用解决方法。不幸的是,NotifyIcon
已密封,无法继承
如注释中所述,您可以使用标记
属性存储对容器表单的引用
但是,如果您正在寻找一种基于设计器的解决方案,这种解决方案不需要编写初始化代码来设置标记
,那么作为一个好的选择,您可以创建一个将属性ParentForm
添加到NotifyIcon
组件并在设计时设置属性,然后,您只需在运行时使用它,在设计时设置ParentForm
属性时,您可以在组件代码中设置Tag
属性,然后在运行时使用它
下面是用法:
将ComponentExtender
(请参阅本文末尾的代码)添加到项目中,然后构建项目。然后:
将工具箱中的ComponentExtender
添加到表单中
使用属性网格在设计器中设置notifyIcon1
的componentExtender1
属性上的ParentForm:
使用此代码查找通知图标的父窗体:
var parent = this.notifyIcon1.Tag as Form`
代码
以下是我使用并正常工作的一个实现:
[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;
}
}
}
没有“NotifyIcon的所有者表单”这样的东西。如果要将其他数据与NotifyIcon
关联,则可以像往常一样自由使用Tag
属性。虽然您可以在code中设置@IvanStoev提供的Tag
属性,我发布了一个支持设计时的解决方案,如果您是设计师迷,您可以使用该解决方案在设计时设置标记
。感谢您的时间,这是一个很好的解决方案,但是,它意味着我希望避免的设计时交互。我正在寻找一个更抽象/自动化的解决方案,例如使用反射。再次感谢。欢迎您并感谢您的反馈:)正如我所说,此解决方案对设计师粉丝很好;)顺便说一句,使用Application.OpenForms
时要小心,因为如果隐藏表单,它将不再存在于集合中。如果您要隐藏表单并使用通知图标将其显示出来,您可能会发现这很有帮助。一如既往地感谢您,很高兴收到您的答复。我将开始尝试通过反射匹配Form.Components成员,如果我自己不可能,则按照您的建议添加一个采用该表单的附加参数。