2008-12-16 19 views
23

Tengo un componente no visual que gestiona otros controles visuales.Obtener el formulario principal del componente

Necesito tener una referencia al formulario en el que está trabajando el componente, pero no sé cómo obtenerlo.

No estoy seguro de poder agregar un constructor con el elemento principal especificado como control, ya que quiero que el componente funcione simplemente al colocarlo en el diseñador.

El otro pensamiento que tenía era tener una propiedad de los padres como control, con el valor por defecto como 'Me'

cualquier sugerencia sería grande

Editar:

Para aclarar, esto es un componente , no un control , ver aquí: ComponentModel.Component

Respuesta

23

[Es importante comprender que la siguiente técnica de ISite solo funciona en tiempo de diseño. Como ContainerControl es público y se le asigna un valor, VisualStudio escribirá el código de inicialización que lo establece en tiempo de ejecución. El sitio está configurado en tiempo de ejecución, pero no puede obtener ContainerControl desde él]

Here's an article que describe cómo hacerlo para un componente no visual.

Básicamente es necesario agregar un ContainerControl propiedad a su componente:

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

y reemplazar la propiedad del sitio:

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

Si hace esto, el ContainerControl será inicializado para hacer referencia al contenga forma por el diseñador.El artículo vinculado lo explica con más detalle.

Una buena manera de ver cómo hacer las cosas es observar la implementación de Tipos en .NET Framework que tienen un comportamiento similar al que desea con una herramienta como Lutz Reflector. En este caso, System.Windows.Forms.ErrorProvider es un buen ejemplo para observar: un Componente que necesita conocer su Formulario que contiene.

+0

Gracias, funcionó bien después de algunos ajustes menores (¡se le agregaron algunos! = Null checks). – Pondidum

+1

Qué es exactamente el servicio, no es ningún miembro del componente. – Peymankh

+0

Creo que 'service' se supone que es' host', lo cambié y hasta ahora me funciona. – dlras2

8

Uso una llamada recursiva para subir la cadena de control. Agregue esto a su 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 
} 

Editar: veo que ha modificado su pregunta como yo estaba escribiendo esto. Si es un componente, el constructor de ese componente debe tomar su padre como un parámetro y el padre debe pasar esto cuando se construya. Varios otros componentes hacen esto, como el temporizador.

Guarde el control principal como miembro y luego úselo en la propiedad ParentForm que le di más arriba en lugar de esto.

+10

También puede usar Control.FindForm() para lograr esto. –

1

Creo que desea utilizar la propiedad del Sitio del IComponent. Es más o menos un equivalente a la propiedad Parent.

+0

¿hay alguna posibilidad de que puedas ser un poco más específico, por favor? He echado un vistazo a la propiedad del sitio durante la depuración, y parece que no hay nada que haga referencia al formulario principal. – Pondidum

2

Si el componene maneja otros controles visuales, entonces usted debería poder llegar al padre a través de ellos.

+0

Había pensado en esto, aunque funciona, parece un poco 'hacky' – Pondidum

+0

No estoy en desacuerdo contigo, sin embargo, si este componente siempre estará vinculado a los controles de la misma forma en que está activado, entonces tienes Nada que perder. – BFree

2

Deberá configurar el contenedor principal de alguna forma. Su componente es solo una clase, que reside en la memoria como todo lo demás. No tiene un contexto real de lo que lo creó a menos que algo le diga que lo hizo. Cree una propiedad de control principal y configúrela.

O simplemente deriva del control y usa FindForm(). No todos los controles deben tener un componente visible

1

Gracias Rob, utilicé su solución en un programa de VB.Net, se parece a esto:

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

que se hace referencia en mi blog: http://www.dailycode.info/Blog/post/2012/07/03/How-to-get-a-user-controls-parent-form-(Windows-forms).aspx

1

He encontrado this solution que no necesita la entrada . Para C# He implementado de esta manera:

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 
} 

esta manera permite que el conjunto ParentForm por el usuario, pero que es fijado por la forma de los padres como predeterminado.

Espero que te ayude.

+0

¿Esto realmente funciona para usted? Para mí, 'host' siempre se establece en' null'. –

0

intenta esto ....

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

    return parent.FindForm(); 
} 

llamada GetParentForm(this.Parent) del componente

-2

Una mejora de la anterior es:

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

Si el componente relacionado con Form es el activo Form puede obtener por Form.ActiveForm.

Cuestiones relacionadas