2011-10-05 12 views
5

Tengo una clase (MyClass) que representa una jerarquía anidada, por lo que la clase tiene una propiedad que es una colección de MyClass. MyClass también tiene una propiedad de títuloAgregando dinámicamente un control de usuario a un repetidor

Para mostrarlo en una página web, esperaba crear un control de usuario que tuviera un repetidor. En la plantilla del elemento, tendría literal para mostrar la propiedad del título, y en el evento ItemCreated del repetidor, crearía una nueva instancia del usercontrol y la agregaría al elemento actual en el repetidor.

Mi problema es que cuando se activa el evento Page_Load en el control de usuario, si el control se agregó dinámicamente, el repetidor repMyClass poroperty es nulo, incluso si llamo EnsureChildControls. ¿Me estoy perdiendo de algo? Si creo un repetidor y coloco mi userctonrol en la plantilla del artículo, funciona bien. ¿No puedo hacer que esto funcione dinámicamente?

control

usuario:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyControl.ascx.cs" Inherits="MyControl" %> 
Items:<br/> 
<asp:Repeater ID="repMyClass" runat="server" EnableViewState="false" 
    OnItemCreated="repMenuItems_ItemCreated"> 
    <HeaderTemplate><ul><HeaderTemplate> 
    <ItemTemplate> 
     <li><%# Eval("Title") %> 
      <div><asp:PlaceHolder ID="SubItemPlaceholder" runat="server" /></div> 
     </li></ItemTemplate> 
    <FooterTemplate></ul></FooterTemplate> 
</asp:Repeater> 

usuario Código de Control:

public partial class MyControl: System.Web.UI.UserControl 
{ 
    public IEnumerable<MyClass> ChildItems { get; set; } 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     this.repMyClass.DataSource = ChildItems; 
     this.repMyClass.DataBind(); 
    } 

    protected void repMenuItems_ItemCreated(object Sender, RepeaterItemEventArgs e) 
    { 
     if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item) 
     { 
      //Get the MyClass instance for this repeater item 
      MyClass mcCurrent = (MyClass)e.Item.DataItem; 

      //If the MyClass instance has child instances 
      if (mcCurrent.Children != null && mcCurrent.Children.Length > 0) 
      { 
       //Add a new user control and set it's property so it can bind 
       PlaceHolder ph = (PlaceHolder)e.Item.FindControl("SubItemPlaceholder"); 

       MyControl ctl = (MyControl)Page.LoadControl(typeof(MyControl),new object[] {}); 

       ctl.ChildItems = mcCurrent.Children; 
       ph.Controls.Add(ctl); 
      } 
     } 
    } 
} 
+0

Puedes editar esto para explicar y quizás limpiar esto. Creo que tal vez tuviste la mitad de una edición en esta oración que no se completó. "Mi problema es que cuando el evento Page_Load es el primero para los controles que se agregaron dinámicamente, el repetidor repNyClass poroperty es nulo" – chrismay

Respuesta

0

Usted puede hacer otro constructor en el control que se lleva a la propiedad que desea y lo utiliza en el evento de carga, y luego pasar en el conjunto de objetos actualmente vacío en la llamada LoadControl().

Otro enfoque es disparar la lógica en el colocador de la propiedad en lugar de en el evento Load del control, ya que es esencialmente la carga real aquí y dispara una vez por solicitud por control si lo hago bien.

Otro enfoque es no cargarlo dinámicamente como todos.

dentro de su plantilla de elementos que puede tener algo como:

<uc:MyControl runat="server 
    ChildItems='<%# ((MyClass) Container.DataItem).Children %>' 
    Visible='<%# ((MyClass) Container.DataItem).Children.Length > 0 %>' 
    /> 

actualización

Un enfoque más que nunca me dio errores con controles secundarios en controles de usuario dentro de los repetidores o página de ciclo de vida, es para usar el evento Límite de datos de artículo en lugar del artículo creado.

En realidad, cuando lo pienso ahora, su código no debería porque e.Item.DataItem no ha estado vinculado todavía.

Intente cambiar el evento a ItemDataBound y vea si esto funciona.

.

Todavía recomiendo que incluya el control en el marcado del artículo y controle la visibilidad del control en el evento (que ahora será ItemDataBound). Puede referirse al control por medio de algo como e.Item.FindControl("ControlId") as MyControl (devolverá nulo si no se encuentra en el elemento actual).

trate de combinar ambas cosas, o al menos evento que cambia a los datos ligados en lugar de creado, y vamos a ver ...

+0

El problema es que mi control de usuario tiene sus propios controles secundarios (un repetidor en este caso). En el evento page_load del control de usuario, la variable del repetidor es en realidad nula. No puedo configurarlo solo, el framework asp.net debe hacerlo. – Jeremy

+0

La teoría es que no deberías necesitar usar la carga, usa el setter en su lugar. Otra alternativa es en la actualización de la respuesta, que uno podría solucionar el problema. Creo que el problema es el evento utilizado, esto tiene una gran probabilidad de ser el problema. – Meligy

3

hubiera hecho esto hace mucho tiempo para la creación de informes anidadas utilizando acordeones.

En Index, cuando se desea agregar dinámicamente las instancias de control del usuario:

// Declare Placeholder  
PlaceHolder ph = (PlaceHolder)e.Item.FindControl("SubItemPlaceholder") 

// Adding some literal controls to header 
ph.Controls.Add(new LiteralControl("This is the accordion header!!")); 

// Declare new control variable 
crt = new Control(); 

// Load up your User Control 
crt = LoadControl("~/MyControl.ascx"); 

// Check if it has loaded properly 
if (crt != null) 
{ 
    // GET/SET any custom properties of the User Control 
    ((myClass)crt).title = "Welcome"; 

    // Add the new User Control to the placeholder's controls collection 
    ph.Controls.Add(crt); 
} 

Nota: En el control de usuario, debe agregar el "NombredeClase" en la etiqueta de declaración

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MyControl.ascx.cs" Inherits="myTest" ClassName="myClass" %> 

Además, cualquier propiedad que desee exponer al crear instancias dinámicamente, las declarará de la siguiente manera:

public string title { get; set; } 

Así que si quiere forzar un valor cuando crea para "repMyClass" puede establecerlo como una propiedad y asignarle el valor que desee programáticamente.

+0

El problema es que mi control de usuario tiene sus propios controles secundarios (un repetidor en este caso). En el evento page_load del control de usuario, la variable del repetidor es en realidad nula. No puedo configurarlo solo, el framework asp.net debe hacerlo. – Jeremy

+0

@Jeremy: Claro que puedes. Solo crea una propiedad de tipo repetidor. A continuación, puede acceder, hacer una instantánea, hacer lo que quiera con él. Aclare: según mi opinión, debe tener una propiedad pública en UserControl, en la carga de página del UserControl debe usar esa propiedad pública para vincular los datos al repetidor. ¿Es eso correcto? –

Cuestiones relacionadas