26

我有一个管理其他可视控件的非可视组件。

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

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

我的另一个想法是拥有一个父属性作为控件,默认值为“我”

任何建议都会很棒

编辑:

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

4

10 回答 10

27

[It is important to understand that the ISite technique below only works at design time. Because ContainerControl is public and gets assigned a value VisualStudio will write initialization code that sets it at run-time. Site is set at run-time, but you can't get ContainerControl from it]

Here's an article that describes how to do it for a non-visual component.

Basically you need to add a property ContainerControl to your component:

public ContainerControl ContainerControl
{
  get { return _containerControl; }
  set { _containerControl = value; }
}
private ContainerControl _containerControl = null;

and override the Site property:

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;
        }
    }
  }
}

If you do this, the ContainerControl will be initialized to reference the containing form by the designer. The linked article explains it in more detail.

A good way to see how to do things is to look at the implementation of Types in the .NET Framework that have behaviour similar to what you want with a tool such as Lutz Reflector. In this case, System.Windows.Forms.ErrorProvider is a good example to look at: a Component that needs to know its containing Form.

于 2008-12-16T16:26:00.430 回答
9

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

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
}

编辑:我看到你在我打字的时候修改了你的问题。如果它是一个组件,该组件的构造函数应该将它的父级作为参数,并且父级应该在构造时传入 this。其他几个组件执行此操作,例如计时器。

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

于 2008-12-16T14:53:57.357 回答
3

You will have to set the parent container some how. Your component is just a class, that resides in memory just like everything else. It has no true context of what created it unless something tells you that it did. Create a Parent control property and set it.

Or simply derive from control and use FindForm(). Not all controls must have a visible component

于 2008-12-16T15:56:12.770 回答
2

如果组件正在管理其他可视控件,那么您应该能够通过它们到达父级。

于 2008-12-16T15:24:59.307 回答
2

I found this solution which does not need the input. For C# I implemented it this way:

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
}

This way allows the set ParentForm by user, but it is set by parent form as Default.

I hope it helps you.

于 2012-09-19T09:26:49.990 回答
2

Try This ....

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

    return parent.FindForm();
}

Call GetParentForm(this.Parent) from component

于 2014-09-25T09:02:46.413 回答
1

我认为您想使用 IComponent 的 Site 属性。它或多或少等同于 Parent 属性。

于 2008-12-16T15:02:35.170 回答
1

Thanks Rob, I used your solution in a VB.Net program, looks like this:

''' <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

Referenced it on my blog: http://www.dailycode.info/Blog/post/2012/07/03/How-to-get-a-user-controls-parent-form-(Windows-forms).aspx

于 2012-07-03T13:17:52.437 回答
-2

If the component related Form is the active Form you may get it by Form.ActiveForm.

于 2016-12-17T12:49:45.003 回答
-3

A improvement of above is:

public static Form ParentForm(this Control ctrl) => ctrl as Form ?? ctrl.FindForm();
于 2016-05-22T05:14:30.180 回答