Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取NotifyIcon的所有者表单?_C#_.net_Vb.net_Forms_Winforms - Fatal编程技术网

C# 获取NotifyIcon的所有者表单?

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

在C#或Vb.Net中,使用托管或非托管代码,如何检索
通知图标的所有者
表单

我已经检查了
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成员,如果我自己不可能,则按照您的建议添加一个采用该表单的附加参数。