2009-01-09 9 views
5

ACTUALIZACIÓN:He estado experimentando con mis controles un poco más y creo que me he acercado. Por favor, sigue leyendo para obtener información actualizada.¿Por qué no se inicializan los elementos secundarios de mi control de usuario personalizado?

Tengo 2 controles de usuario de ASP.NET 2.0, uno de los cuales se coloca dentro de del otro. Dentro del control interno tengo un control de etiqueta HtmlAnchor al cual intento establecer una URL desde el control externo. Cuando intento establecer la propiedad HRef desde el marcado de la página de representación, el control HtmlAnchor es null y arroja una excepción.

La URL set propiedad se llama antes del evento OnInit ya sea del interior o del exterior de control y antes de 'OnPreInit' evento principal de la página. Supongo que esto se debe a que estoy estableciendo el URL del control secundario en el marcado del control principal en la página en la que estoy renderizando los controles, lo que significa que el valor está establecido antes del OnInit(). Aquí está la versión (simplificada) del código que estoy usando:

[ParseChildren(true)]// <- Setting this to false makes the 
        // page render without an exception 
        // but ignores anything in the markup. 
[PersistChildren(false)] 
public partial class OuterControl : System.Web.UI.UserControl 
{ 
    // The private '_Inner' control is declared 
    // in the .ascx markup of the control 
    [PersistenceMode(PersistenceMode.InnerProperty)] 
    public InnerControl Inner 
    { 
     get{ return _Inner; } 
     set{ _Inner = value; } 
    } 
} 

public partial class InnerControl : System.Web.UI.UserControl 
{ 
    // The private 'linkHref' control is declared 
    // in the .ascx markup of the control 
    public string Url 
    { 
     get { return linkHref.HRef; } 
     set { linkHref.HRef = value; } 
    } 
} 

El OuterControl se utiliza en mi página Default.aspx como esto:

<uc1:OuterControl ID="OuterCtrl1" runat="server"> 
    <Inner Url="#" /> 
</uc1:OuterControl> 

En el ejemplo de marcado anterior, si Intento renderizar esta página, se lanza una excepción porque el control linkHref es nulo. Utilizando mi depurador puedo ver que cada control dentro de InnerControl es nulo, pero ni el evento & OuterControl OnInit() del InnerControl OuterControl se ha activado aún cuando se accede a la propiedad Url.

ACTUALIZACIÓN
pensé añadiendo 'ParseChildren' y 'PersistChildren' ayudarían a los atributos. Los he usado en Controles de Servidor antes pero nunca en los Controles de Usuario, aunque el efecto parece ser similar. No creo que esté interpretando correctamente la documentación de estas dos propiedades, pero puede evitar que se produzcan excepciones. Sin embargo, el marcado de la página se ignora.

¿Alguien sabe una manera de tener este trabajo. No entiendo por qué estos controles obtienen valores establecidos antes del OnInit(). Cuando intento establecer sus valores utilizando el marcado ASPX, el constructor para el InnerControl se llama dos veces. Una vez para establecer los valores basados ​​en el marcado (supongo) y de nuevo en OnInit() (que supongo que es por qué los valores de marcado se ignoran).

¿Es este esfuerzo inútil o me estoy acercando desde el ángulo equivocado?

Respuesta

0

¿Está configurando HRef en el método OnInit de la página? Si es así, intenta mover la asignación a Page_Load.

Los controles Init desde el más externo al más interno. Esto significa que si asigna el valor en OnInit de la página, los controles aún no se han inicializado.

Aquí es un documento decente en la página del ciclo de vida: http://www.codeproject.com/KB/aspnet/lifecycle.aspx

+0

Estoy configurando HRef en el marcado de la página, no en el método OnInit. Sé que esto sucede antes del evento OnPreInit() de la página. Me gustaría poder usar el marcado para establecer valores de control si es posible, ya que significa no tener que volver a compilar para realizar cambios. –

0

Usted dijo:

// The private 'linkHref' control is declared 
// in the .ascx markup of the control 

¿cambia nada si haces esto un control protegida?

0

El árbol de control se crea después de Init(); de hecho, Init() es el lugar para agregar sus controles al árbol, antes de que se deserialice viewstate. No puede acceder a linkHref antes de que se haya construido el árbol de control.

Una posible solución es almacenar la URL hasta que pueda usarla. Dentro del control interno, cambie la propiedad Url a una cadena simple:

public string Url { get; set; } 

en la carga o PreRender controlador de eventos del control interno, propagar la cadena a la (ahora inicializado) linkHref objeto:

linkHref.HRef = value; 
2

Saludos Dan,

Me enfrenté a un problema similar antes con el desorden de los controles anidados, así que me encontré con ganas de ayudar, y lo marqué como favorito porque me gustó.

que reproduce el problema de la siguiente manera: -

Creado un control de usuario llamado interno:

Inner.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Inner.ascx.cs" Inherits="Inner" %> 
<a runat="server" id="linkHref">I'm inner</a> 

Inner.ascx.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

public partial class Inner : System.Web.UI.UserControl 
{ 
    public string Url 
    { 
     get 
     { 
      return this.linkHref.HRef; 
     } 
     set 
     { 
      this.linkHref.HRef = value; 
     } 
    } 
} 

Creado a control de usuario llamado externo:

Outer.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Outer.ascx.cs" Inherits="Outer" %> 
<%@ Register src="Inner.ascx" tagname="Inner" tagprefix="uc1" %> 
<uc1:Inner ID="_Inner" runat="server" /> 

Outer.ascx.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

public partial class Outer : System.Web.UI.UserControl 
{ 
    [PersistenceMode(PersistenceMode.InnerProperty)] 
    public Inner Inner 
    { 
     get 
     { 
      return this._Inner; 
     } 
    } 
} 

Entonces creó una página llamada por defecto:

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> 

<%@ Register src="Outer.ascx" tagname="Outer" tagprefix="uc1" %> 
<%@ Reference Control="~/Inner.ascx" %> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 
    <div> 
     <uc1:Outer ID="Outer1" runat="server"> 
      <Inner Url="http://google.com" /> 
     </uc1:Outer> 
    </div> 
    </form> 
</body> 
</html> 

Con todo esto, la página "predeterminada" funciona bien.

Lo que me parece extraño en su código es esta línea:

public InnerControl Inner 
    { 
     //... 
     set{ _Inner = value; } 
    } 

Cuál es el punto de crear un regulador para el control interno? No puedo entenderlo se supone que la instancia de control interno se crea a partir del marcado en el control externo, y es esta instancia creada cuyo html anchor debe ser manipulado. Si añado estas líneas a la propiedad interior en los Outer.ascx.cs

set 
{ 
    this._Inner = (ASP.inner_ascx)value; 
} 

que obtendrá una excepción de referencia nula como en el caso original. Creo que el colocador da instrucciones al generador de páginas ASP.Net para que cree otra instancia de control interno y lo establece usando la propiedad Inner. No estoy seguro, pero si tiene tiempo, puede saber exactamente cómo sucede al examinar los archivos cs generados por el creador de la página, que residen en los archivos ASP.Net temporales.

1

Si OuterControl.ascx parece

<%@ Register TagPrefix="uc1" TagName="InnerControl" Src="InnerControl.ascx" %> 
<uc1:InnerControl runat="server" ID="_Inner" /> 

entonces el problema es que la propiedad OuterControl.Inner tiene un descriptor de acceso set. Eliminar el descriptor de acceso set para solucionar el problema:

[PersistenceMode(PersistenceMode.InnerProperty)] 
public InnerControl Inner 
{ 
    get { return _Inner; } 
} 

Explicación: Si OuterControl.Inner tiene un descriptor de acceso set ...

  1. En primer lugar, ASP.NET crea una instancia ASP.outercontrol_ascx (la clase generada dinámicamente que se deriva de OuterControl,) que a su vez instancia una instancia de ASP.innercontrol_ascx (la clase generada dinámicamente que deriva de InnerControl).
  2. A continuación, porque la propiedad Inner tiene un descriptor de acceso set, ASP.NET crea una nueva instancia de InnerControl (noASP.innercontrol_ascx, como era de esperar) y los intentos para inicializar su propiedad Url a "#". Por supuesto, esto arroja NullReferenceException porque linkHref es creado por ASP.innercontrol_ascx, no por InnerControl.
  3. último (si no es la excepción había sido lanzado), ASP.NET establece Inner a la instancia de InnerControl que creó en el paso 2.

Si OuterControl.Inner no tiene un descriptor de acceso set, a continuación, en el paso 2, ASP.NET simplemente establece OuterCtrl1.Inner.Url en "#", y se omite el paso 3.

Nota: Un par de otras respuestas indican que los controles se crean o inicializan en Init. Esto es incorrecto; los controles declarados en marcado se crean y se inicializan muy temprano en el ciclo de vida de la página, en FrameworkInitialize (que ocurre antes del PreInit).

Cuestiones relacionadas