views:

3156

answers:

5

I have a non-visual component which manages other visual controls.

I need to have a reference to the form that the component is operating on, but i don't know how to get it.

I am unsure of adding a constructor with the parent specified as control, as i want the component to work by just being dropped into the designer.

The other thought i had was to have a Property of parent as a control, with the default value as 'Me'

any suggestions would be great

Edit:

To clarify, this is a component, not a control, see here :ComponentModel.Component

+1  A: 

I use a recursive call to walk up the control chain. Add this to your control.

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
}

Edit: I see you modified your question as I was typing this. If it is a component, the constructor of that component should take it's parent as a parameter and the parent should pass in this when constructed. Several other components do this such as the timer.

Save the parent control as a member and then use it in the ParentForm property I gave you above instead of this.

Rob Prouse
A: 

I think you want to use the Site property of the IComponent. It's more or less an equivalent to the Parent property.

arul
any chance you could be a little more specific please? i have had a look at the site property while debugging, and there seems to be nothing that references the parent form.
Pondidum
+1  A: 

If the componenet is managing other visual controls, then you should be able to get to the parent through them.

BFree
I had thought of this, while it works, it does seem a little 'hacky'
Pondidum
I don't disagree with you, however if this component will always be tied to the controls of the same form that it's on, then you have nothing to lose.
BFree
+1  A: 

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

Brian Rudolph
+6  A: 

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 (service != 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.

Edit added check for service != null - implementation now matches that of System.Windows.Forms.ErrorProvider.

Joe
Thanks, this worked fine after a few minor tweaks (added some != null checks to it).
Pondidum
What exactly is service, it's not any member of the component.
Peymankh
I think `service` is actually supposed to be `host` - I switched it, and it's working for me so far.
Daniel Rasmussen