2009-04-08 16 views
8

Tengo una página maestra que está anidada en 2 niveles. Tiene una página maestra y esa página maestra tiene una página maestra.Encontrar controles dentro de las páginas maestras anidadas

Cuando se adhieren los controles en un ContentPlaceHolder con el nombre "BCR" - Tengo que encontrar a los controles de este modo:

Label lblName =(Label)Master.Master.FindControl("bcr").FindControl("bcr").FindControl("Conditional1").FindControl("ctl03").FindControl("lblName"); 

¿estoy totalmente perdido? ¿O es así como debe hacerse?

Estoy a punto de trabajar con un MultiView, que está dentro de un control de contenido condicional. Entonces, si quiero cambiar la vista, tengo que obtener una referencia de ese control, ¿verdad? ¡Conseguir que la referencia sea aún más desagradable! ¿Hay una mejor manera?

Gracias

Respuesta

4

En primer lugar, usted debe saber que MasterPages realidad se sientan dentro de las páginas. Tanto es así que el evento Load de MasterPage se llama realmente después del evento Load de su ASPX.

Esto significa que el objeto Página es en realidad el control más alto en la jerarquía de control.

Por lo tanto, sabiendo esto, la mejor manera de encontrar cualquier control en un entorno anidado, es escribir una función recursiva que recorre cada control y controles secundarios hasta encontrar el que está buscando. en este caso, sus páginas maestras son en realidad controles secundarios del control de la página principal.

Se llega al objeto de página principal desde el interior de cualquier control de la siguiente manera:

C#:

this.Page;

VB.NET

Me.Page

Me parece que por lo general, el método de control de la clase FindControl() es bastante inútil, ya que el ambiente siempre está anidado.

Porque si esto, he decidido utilizar .NET 3.5 nuevas características de Extensión para extender la clase de Control.

Al utilizar el código de abajo (VB.NET), en, por ejemplo, la carpeta de AppCode, todos sus controles serán ahora peform una búsqueda recursiva llamando FindByControlID()

Public Module ControlExtensions 
    <System.Runtime.CompilerServices.Extension()> _ 
    Public Function FindControlByID(ByRef SourceControl As Control, ByRef ControlID As String) As Control 
     If Not String.IsNullOrEmpty(ControlID) Then 
      Return FindControlHelper(Of Control)(SourceControl.Controls, ControlID) 
     Else 
      Return Nothing 
     End If 
    End Function 

    Private Function FindControlHelper(Of GenericControlType)(ByVal ConCol As ControlCollection, ByRef ControlID As String) As Control 
     Dim RetControl As Control 

     For Each Con As Control In ConCol 
      If ControlID IsNot Nothing Then 
       If Con.ID = ControlID Then 
        Return Con 
       End If 
      Else 
       If TypeOf Con Is GenericControlType Then 
        Return Con 
       End If 
      End If 

      If Con.HasControls Then 
       If ControlID IsNot Nothing Then 
        RetControl = FindControlByID(Con, ControlID) 
       Else 
        RetControl = FindControlByType(Of GenericControlType)(Con) 
       End If 

       If RetControl IsNot Nothing Then 
        Return RetControl 
       End If 
      End If 
     Next 

     Return Nothing 
    End Function 

End Module 
22

controles hallazgo es un dolor, y he estado usando este método que me dieron desde el CodingHorror blog hace ya bastante tiempo, con una sola modificación que devuelve un valor nulo si un identificador de vacío se pasa.

/// <summary> 
/// Recursive FindControl method, to search a control and all child 
/// controls for a control with the specified ID. 
/// </summary> 
/// <returns>Control if found or null</returns> 
public static Control FindControlRecursive(Control root, string id) 
{ 
    if (id == string.Empty) 
     return null; 

    if (root.ID == id) 
     return root; 

    foreach (Control c in root.Controls) 
    { 
     Control t = FindControlRecursive(c, id); 
     if (t != null) 
     { 
      return t; 
     } 
    } 
    return null; 
} 

en su caso, creo que lo que se necesita lo siguiente:

Label lblName = (Label) FindControlRecursive(Page, "lblName"); 

Usar este método es generalmente mucho más conveniente, ya que no necesita saber exactamente dónde reside el control para encontrarlo (suponiendo que conozca la identificación, por supuesto), aunque haya anidado los controles con la del mismo nombre, es probable que tengas un comportamiento extraño, por lo que podría ser algo de lo que tengas que estar pendiente.

+0

Esto funciona perfectamente. Gracias. –

+0

+1 gracias esto también me ayudó – leen3o

+0

+1 Sé que esto es como 5 años, pero este método me salvó un poco de dolor de cabeza, ¡gracias! – psoshmo

4

Aunque me encanta la recursividad, y estoy de acuerdo con Andy y Mun, otro enfoque que quizás desee considerar es tener un strongly typed Master page. Todo lo que tienes que hacer es agregar una directiva en tu página aspx.

En lugar de acceder al control de una página de su página maestra, tenga en cuenta el acceso a un control en su página principal de la página en sí. Este enfoque tiene mucho sentido cuando tiene una etiqueta de encabezado en su página maestra y desea establecer su valor desde cada página que usa el maestro.

No estoy 100% seguro, pero creo que esta sería una técnica más simple con páginas maestras anidadas, ya que simplemente señalaría VirtualPath al maestro que contiene el control al que desea acceder. Sin embargo, puede resultar complicado si desea acceder a dos controles, uno en cada página maestra respectiva.

+0

sí, buen punto. A veces es bueno poner esa funcionalidad en algún tipo de método o propiedad en su base de página personalizada. Aunque, por supuesto, no está de más tener predictores de control recursivos incorporados – andy

1

He usado el método <%@ MasterType VirtualPath="~/MyMaster.master" %>. Tengo una propiedad en la página maestra principal y luego en la página maestra de detalles otra propiedad con el mismo nombre que llama a la propiedad maestra principal y funciona bien.

Tengo esto en la página maestra principal

public string MensajeErrorString 
    { 
     set 
     { 
      if (value != string.Empty) 
      { 
       MensajeError.Visible = true; 
       MensajeError.InnerHtml = value; 
      } 
      else 
       MensajeError.Visible = false; 
     } 


    } 

esto es sólo un elemento div que tiene que mostrar un mensaje de error. Me gustaría usar esta misma propiedad en las páginas con la página maestra de detalles (esta está anidada con el maestro principal).

Luego, en el detalle principal que tienen este

public string MensajeErrorString 
    { 
     set 
     { 
       Master.MensajeErrorString = value; 
     } 

    } 

Im llamando a la utilería principal del maestro detalle para crear el mismo comportamiento.

0

Acabo de hacerlo funcionar perfectamente.

En contentpage.aspx, me escribió lo siguiente:

If Master.Master.connectsession.IsConnected Then my coded comes in here End If

2

Aquí es un código que es más genérico y funciona con una condición de encargo (que puede ser una expresión lambda!)

llamar:

Control founded = parent.FindControl(c => c.ID == "youdId", true); 

extensión de control

public static class ControlExtensions 
{ 
    public static Control FindControl(this Control parent, Func<Control, bool> condition, bool recurse) 
    { 
     Control founded = null; 
     Func<Control, bool> search = null; 
     search = c => c != parent && condition(c) ? (founded = c) != null : 
                recurse ? c.Controls.FirstOrDefault(search) != null : 
                (founded = c.Controls.FirstOrDefault(condition)) != null; 
     search(parent); 
     return founded; 
    } 
} 
Cuestiones relacionadas