Pregunta

Parte de la serie de controles en los que estoy trabajando, obviamente, me involucra agrupando algunos de ellos en compuestos. Estoy empezando a aprender rápidamente que esto tiene en cuenta (¡todo esto es nuevo para mí!) :)

Básicamente tengo un control StyledWindow , que es esencialmente un Panel glorificado con capacidad para hacer otros bits (como agregar bordes, etc.).

Aquí está el código que crea una instancia de los controles secundarios dentro de él. Hasta este punto, parece que ha estado funcionando correctamente con controles estáticos mundanos:

    protected override void CreateChildControls()
    {
        _panel = new Panel();

        if (_editable != null)
            _editable.InstantiateIn(_panel);

        _regions = new List<IAttributeAccessor>();
        _regions.Add(_panel);
    }

Los problemas surgieron hoy cuando intenté anidar un control más complejo dentro de él. Este control utiliza una referencia a la página, ya que inyecta JavaScript para que sea un poco más ágil y receptivo (el RegisterClientScriptBlock es la única razón por la que necesito la referencia de la página).

Ahora, esto estaba causando " objeto nulo " errores, pero localicé esto en el método de renderizado, que por supuesto estaba intentando llamar al método contra el objeto [null] Page .

Lo que me confunde es que el control funciona bien como independiente, pero cuando se coloca en StyledWindow , ¡todo va terriblemente mal!

Entonces, parece que me estoy perdiendo algo en mi StyledWindow o ChildControl . ¿Alguna idea?

Actualizar

Como Brad Wilson bastante acertadamente señalado , no ve los controles que se agregan a la colección Controls . Para esto es el _panel , esto estaba allí para manejarlo, básicamente, a continuación, anular Controls (obtuve esto de una guía en algún lugar):

    Panel _panel;    // Sub-Control to store the "Content".
    public override ControlCollection Controls
    {
        get
        {
            EnsureChildControls();
            return _panel.Controls;
        }
    }

Espero que eso ayude a aclarar las cosas. Disculpas.

Actualización siguiendo Respuesta de Longhorn213

Bien, he estado jugando un poco con el control, colocando uno dentro del compuesto y otro afuera. Luego obtuve el estado de Página en el evento principal del evento en el ciclo de vida del control y lo representé en la página.

La versión independiente funciona correctamente y la página se introduce como se espera. Sin embargo, el que está anidado en el Compuesto es diferente. ¡El evento OnLoad no se está disparando en absoluto! Así que supongo que Brad probablemente tenga razón en que no estoy configurando la jerarquía de control correctamente. ¿Puede alguien ofrecer algún consejo sobre lo que me estoy perdiendo? ¿No es suficiente el método del Panel? (bueno, obviamente no lo es, ¿verdad?): D

Gracias por su ayuda, chicos, apreciado :)

¿Fue útil?

Solución 3

Resuelto!

¡Cierto, hoy estaba decidido a que me rompieran esto! Aquí estaban mis pensamientos:

  • Pensé que el uso de Panel era un poco pirateado, así que debería eliminarlo y descubrir cómo se hace realmente.
  • No quería tener que hacer algo como MyCtl.Controls [0] .Controls para acceder a los controles agregados al compuesto.
  • ¡Quería que la maldita cosa funcionara!

Entonces, busqué y presioné MSDN , este artículo fue REALMENTE útil (es decir, como casi copiar y pegar, y bien explicado - algo que MSDN es tradicionalmente malo en). Niza!

Así que, arranqué el uso de Panel y seguí prácticamente el artículo y lo tomé como un evangelio, tomando notas a medida que avanzaba.

Esto es lo que tengo ahora:

  • Aprendí que estaba usando el término incorrecto. Debería haberlo estado llamando Control de plantillas . Mientras que los controles de plantilla son técnicamente compuestos, hay una diferencia distinta. Los controles con plantilla pueden definir la interfaz para los elementos que se agregan a ellos.
  • Los controles con plantilla son muy potentes y, de hecho, ¡son muy rápidos y fáciles de configurar una vez que los rodeas!
  • Jugaré un poco más con el soporte del diseñador para asegurarme de que lo entiendo completamente y luego recibiré una publicación en el blog :)
  • Una " Plantilla " el control se utiliza para especificar la interfaz para los datos de plantilla.

Por ejemplo, aquí está el marcado ASPX para un control con plantilla:

<cc1:TemplatedControl ID="MyCtl" runat="server">
    <Template>
        <!-- Templated Content Goes Here -->
    </Template>
</cc1:TemplatedControl>   

Aquí está el código que tengo ahora

public class DummyWebControl : WebControl
{
    // Acts as the surrogate for the templated controls.
    // This is essentially the "interface" for the templated data.
}

En TemplateControl.cs ...

    ITemplate _template;
    // Surrogate to hold the controls instantiated from 
    // within the template.
    DummyWebControl _owner;

    protected override void CreateChildControls()
    {
        // Note we are calling base.Controls here
        // (you will see why in a min).
        base.Controls.Clear();
        _owner = new DummyWebControl();

        // Load the Template Content
        ITemplate template = _template;
        if (template == null)
            template = new StyledWindowDefaultTemplate();
        template.InstantiateIn(_owner);

        base.Controls.Add(_owner);
        ChildControlsCreated = true;
    }

Luego, para facilitar el acceso a los controles del objeto [Surrogate]:

(es por esto que necesitamos borrar / agregar a la base. Controles)

    public override ControlCollection Controls
    {
        get
        {
            EnsureChildControls();
            return _owner.Controls;
        }
    }

Y eso es prácticamente todo, ¡fácil cuando sabes cómo! :)

Siguiente: ¡Soporte de región de tiempo de diseño!

Otros consejos

No te veo agregando tus controles a la colección de controles en ninguna parte, lo que explicaría por qué no pueden acceder a la página (ya que nunca se han colocado oficialmente en la página).

Siempre he puesto las llamadas de JavaScript en la función OnLoad. Como los de abajo.

protected override void OnLoad(EventArgs e)
{

    // Do something to get the script
    string script = GetScript();

    this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "SomeJavaScriptName", script);

    // Could also use this function to determine if the script has been register. i.e. more than 1 of the controls exists
    this.Page.ClientScript.IsClientScriptBlockRegistered("SomeJavaScriptName");

    base.OnLoad(e);
}

Si aún desea hacer el render, puede escribir el script en la respuesta. Que es lo que hace el RegisterScriptBlock, solo pone el script en línea en la página.

Bien, comencé a jugar y me di cuenta de que había algo mal con mi instancia de control, ya que Longhorn tenía razón, debería poder crear referencias de script en OnLoad (y no pude) , y Brad tenía razón al afirmar que debo asegurar que mi jerarquía Controls se mantuviera agregando a la colección Controls del compuesto.

Entonces, tenía dos cosas aquí:

  1. Había anulado el acceso a la propiedad Controls para que el compuesto devuelva la colección de controles de este Panel ya que no quiero tener que ir a ctl.Controls [ 0] .Controls [0] para obtener el control real que quiero. He eliminado esto, pero debo solucionarlo.
  2. No había añadido el Panel a la colección Controls , Ahora he hecho esto.

Entonces, ahora funciona, sin embargo, cómo obtengo la propiedad Controls para que el compuesto devuelva los elementos en el Panel , en lugar de < código> Panel en sí?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top