C# 获取组件';s父窗体

C# 获取组件';s父窗体,c#,vb.net,winforms,components,C#,Vb.net,Winforms,Components,我有一个非可视组件,它管理其他可视控件 我需要一个对组件正在运行的表单的引用,但我不知道如何获取它 我不确定是否要添加一个将父级指定为控件的构造函数,因为我希望该组件只需放入设计器中即可工作 我的另一个想法是使用parent属性作为控件,默认值为“Me” 任何建议都很好 编辑: 为了澄清,这是一个组件,而不是一个控件,请参见此处:我使用递归调用来遍历控制链。将此添加到您的控件中 public Form ParentForm { get { return GetParentForm( th

我有一个非可视组件,它管理其他可视控件

我需要一个对组件正在运行的表单的引用,但我不知道如何获取它

我不确定是否要添加一个将父级指定为控件的构造函数,因为我希望该组件只需放入设计器中即可工作

我的另一个想法是使用parent属性作为控件,默认值为“Me”

任何建议都很好

编辑:


为了澄清,这是一个组件,而不是一个控件,请参见此处:

我使用递归调用来遍历控制链。将此添加到您的控件中

public Form ParentForm
{
    get { return GetParentForm( this.Parent ); }
}

private Form GetParentForm( Control parent )
{
    Form form = parent as Form;
    if ( form != null )
    {
        return form;
    }
    if ( parent != null )
    {
        // Walk up the control hierarchy
        return GetParentForm( parent.Parent );
    }
    return null; // Control is not on a Form
}
编辑:我看到您在我键入此内容时修改了您的问题。如果它是一个组件,则该组件的构造函数应将其父级作为参数,并且父级在构造时应传入该参数。其他几个组件(如计时器)也可以执行此操作


将父控件另存为成员,然后在我上面给您的ParentForm属性中使用它,而不是此属性。

我认为您希望使用IComponent的Site属性。它或多或少相当于父属性。

如果componenet正在管理其他可视控件,那么您应该能够通过它们访问父属性

您必须对父容器进行一些设置。您的组件只是一个类,与其他所有组件一样驻留在内存中。除非有什么东西告诉你它是什么造成的,否则它没有真正的背景。创建父控件属性并进行设置


或者简单地从控件派生并使用FindForm()。并非所有控件都必须具有可见组件。[重要的是要了解下面的ISite技术仅在设计时有效。因为ContainerControl是公共的,并且被分配了一个值,VisualStudio将编写初始化代码,在运行时对其进行设置。站点在运行时设置,但您无法从中获取ContainerControl]

这描述了如何为非可视组件执行此操作

基本上,您需要向组件添加属性ContainerControl:

public ContainerControl ContainerControl
{
  get { return _containerControl; }
  set { _containerControl = value; }
}
private ContainerControl _containerControl = null;
并覆盖站点属性:

public override ISite Site
{
  get { return base.Site; }
  set
  {
    base.Site = value;
    if (value == null)
    {
      return;
    }

    IDesignerHost host = value.GetService(
        typeof(IDesignerHost)) as IDesignerHost;
    if (host != null)
    {
        IComponent componentHost = host.RootComponent;
        if (componentHost is ContainerControl)
        {
            ContainerControl = componentHost as ContainerControl;
        }
    }
  }
}
如果执行此操作,则设计器将初始化ContainerControl以引用包含表单。链接文章对此进行了更详细的解释


了解如何操作的一个好方法是查看.NET Framework中类型的实现,这些类型的行为类似于使用Lutz Reflector等工具所需的行为。在本例中,System.Windows.Forms.ErrorProvider是一个很好的例子:一个需要知道其包含形式的组件。

谢谢Rob,我在VB.Net程序中使用了您的解决方案,如下所示:

''' <summary>
''' Returns the parent System.Windows.form of the control
''' </summary>
''' <param name="parent"></param>
''' <returns>First parent form or null if no parent found</returns>
''' <remarks></remarks>
Public Shared Function GetParentForm(ByVal parent As Control) As Form
    Dim form As Form = TryCast(parent, Form)
    If form IsNot Nothing Then
        Return form
    End If

    If parent IsNot Nothing Then
        ' Walk up the control hierarchy
        Return GetParentForm(parent.Parent)
    End If

    ' Control is not on a Form
    Return Nothing
End Function
“”
''返回控件的父System.Windows.form
''' 
''' 
''第一个父窗体,如果未找到父窗体,则为null
''' 
公共共享函数GetParentForm(ByVal parent作为控件)作为窗体
Dim form As form=TryCast(父级,窗体)
如果形式不是什么,那么
报税表
如果结束
如果父母不是什么都不是
'向上走控制层次结构
返回GetParentForm(parent.parent)
如果结束
'控件不在窗体上
一无所获
端函数
在我的博客上引用了它: 我找到了不需要输入的。对于C#我是这样实现的:

public partial class RegistryManager : Component, ISupportInitialize
{

    private Form _parentForm;
    public Form ParentForm
    {
        get { return _parentForm;  }
        set { _parentForm = value; }
    }

    // Etc....

    #region ISupportInitialize
    public void BeginInit() {  }
    public void EndInit()
    {
        setUpParentForm();
    }
    private void setUpParentForm()
    {
        if (_parentForm != null) return; // do nothing if it is set
        IDesignerHost host;
        if (Site != null)
        {
            host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (host != null)
            {
                if (host.RootComponent is Form)
                {
                    _parentForm = (Form)host.RootComponent;
                }
            }
        }
    }
    #endregion
}
这种方式允许按用户设置ParentForm,但它由父窗体设置为默认值

我希望它能帮助你。

试试这个

private Form GetParentForm(Control parent)
{
    if (parent is Form)
        return parent as Form;

    return parent.FindForm();
}

从组件调用
GetParentForm(this.Parent)
以上的改进是:

public static Form ParentForm(this Control ctrl) => ctrl as Form ?? ctrl.FindForm();

如果与
表单
相关的组件是活动的
表单
您可以通过
表单获得它。活动表单

您是否有可能更具体一点?我在调试时查看了站点属性,似乎没有任何引用父窗体的内容。我已经想到了这一点,虽然它工作,但它确实有点“黑客”我不同意你的看法,但是如果该组件始终与它所在的同一窗体的控件绑定,那么你就不会有任何损失。谢谢,经过一些小的调整(添加了一些!=null检查),它工作得很好。服务到底是什么,它不是组件的任何成员。我认为
服务
实际上应该是
主机
-我切换了它,到目前为止它对我有效。这在运行时是如何工作的。据我所知,是设计师提供了IDesignerHost实现,因此它只能在设计模式下工作。我很抱歉。将组件拖放到from之后,代码工作正常,设计器将生成初始化代码到ContainerControl属性!因此,要使用该解决方案,您应该将组件redrop到from。您还可以使用Control.FindForm()来实现这一点。这是否真的适用于您?对我来说,
host
总是设置为
null