2010-11-27 10 views
6

He estado diseñando un sitio web que tiene una cuadrícula en la página. La grilla tiene múltiples comboBoxes dentro de ella. Estos cuadros combinados interactúan. es decir, cuando un valor es cambiado por el usuario, otro tiene su valor de cambio o está deshabilitado/habilitado, etc.Controles que interactúan dentro de una cuadrícula

Me parece que para hacer esto tengo que usar FindControl mucho. Al igual que en el evento selectedindexchanged de un cuadro combinado, tendré que buscar otro comboBox.

Esto parece una manera bastante desordenada de hacer las cosas. También parece que deja el sistema abierto a errores que el compilador no encontrará, por ejemplo, si un cuadro combinado tiene su identificación cambiada más adelante en la línea.

¿Puede alguien decirme que hay una mejor manera de solucionar esto?

Respuesta

0

Es por esta misma razón que cambié de ASP.NET a desarrollo en Silverlight y aprovechando su patrón MVVM. Incluso con las plantillas de elementos GridView de ASP.NET, cada elemento no puede vincularse directamente, hacerse conocer o hacer referencia a otro elemento en la misma plantilla. Su código detrás debe saber, hasta cierto punto (que generalmente es el más completo), la jerarquía de composición de los controles de su vista.

Sin embargo, esto es lo que podría hacer para acercarse al "mejor mundo vinculante". Aún vinculará sus cuadros combinados a las mismas fuentes de datos de la lista, pero cuando se crea cada fila de elementos/controles, asociaría cada elemento con un objeto (es decir, elemento de etiqueta). Luego, en el manejo de eventos de sus controles, recuperaría otros controles asociados con el elemento de etiqueta asociado con el control que provocó el evento y hará lo que haga con ellos.

Lo sé, no es la mejor idea, pero está muy por encima de mi cabeza. Quizás cuando haya tenido tiempo de pensar más sobre esto, pueda actualizar esta publicación.

1

Tengo una aplicación web que también hace un uso extensivo de varias permutaciones de FindControl para lograr lo que describes. Aunque es frágil (no cambia las ID de control sin pruebas), puede hacerse un poco menos engorroso mediante algunas funciones de utilidad. Estas son todas las funciones de tipo FindControl que uso; esto al menos puede ayudarlo.

/// <summary> 
/// Recursively searches for a control within the heirarchy of a given control. 
/// </summary> 
/// <param name="root">The control to search within.</param> 
/// <param name="id">The ID of the control to find.</param> 
/// <returns>The Control object of the found control, or null if the control isn't found.</returns> 
public static Control FindControlRecursive(Control root, string id) 
{ 
    if (root.ID == id) return root; 

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

    return null; 
} 

/// <summary> 
/// Recursively searches for a control within the heirarchy of a given control using the Client ID 
/// of the control. Calling this too early in the lifecycle may not behave as expected. 
/// </summary> 
/// <param name="root">The control to search within.</param> 
/// <param name="clientID">The Client ID of the control to find.</param> 
/// <returns>The Control object of the found control, or null if the control isn't found.</returns> 
public static Control FindControlRecursiveByClientID(Control root, string clientID) 
{ 
if (0 == String.Compare(root.ClientID, clientID, true)) return root; 

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

return null; 
} 

/// <summary> 
/// Recursively searches for a group of controls within the heirarchy of a given control tree using the ID 
/// of the control. 
/// </summary> 
/// <param name="root">The control tree to search within.</param> 
/// <param name="id">The ID of the control to find.</param> 
/// <returns> 
/// A collection of the found controls. The collection will be empty if none are found. 
/// </returns> 
public static List<Control> FindControlsRecursive(Control root, string id) 
{ 
List<Control> collection = new List<Control>(); 
FindControlRecursive(root, id, collection); 
return collection; 
} 

private static void FindControlRecursive(Control root, string id, List<Control> collection) 
{ 
foreach (Control c in root.Controls) 
{ 
    if (0 == String.Compare(c.ID, id, true)) collection.Add(c); 
    else FindControlRecursive(c, id, collection); 
} 
} 

/// <summary> 
/// Recursively searches for a control within the heirarchy of a given control using the type 
/// of the control. 
/// </summary> 
/// <typeparam name="T">The type of the control to find.</typeparam> 
/// <param name="root">The control to search within.</param> 
/// <returns> 
/// The Control object of the found control, or null if the control isn't found. 
/// </returns> 
public static T FindControlRecursiveByType<T>(Control root) 
where T : Control 
{ 
if (root is T) return (T)root; 
foreach (Control c in root.Controls) 
{ 
    Control t = FindControlRecursiveByType<T>(c); 
    if (t != null) return (T)t; 
} 
return null; 
} 

/// <summary> 
/// Recursively searches for a set of controls within the heirarchy of a given control using the type 
/// of the control. 
/// </summary> 
/// <typeparam name="T">The type of the control to find.</typeparam> 
/// <param name="root">The control to search within.</param> 
/// <returns> 
/// A generic List object containing the controls found, or an empty List of none were found. 
/// </returns> 
public static List<T> FindControlsRecursiveByType<T>(Control root) 
where T : Control 
{ 
List<T> collection = new List<T>(); 
FindControlRecursiveByType<T>(root, collection); 
return collection; 
} 

private static void FindControlRecursiveByType<T>(Control root, List<T> collection) 
where T : Control 
{ 
foreach (Control c in root.Controls) 
{ 
    if (c is T) collection.Add((T)c); 
    else FindControlRecursiveByType<T>(c, collection); 
} 
} 
0

Cómo sobre el uso de eventos para hacer lo notifica?

0

Estos son muy desordenados.

Aquí hay una solución muy simple y elegante. Supongamos que su cuadrícula necesita mostrar datos en una tabla con 3 columnas. Los datos proviene de un objeto con la siguiente estructura:

[Serializable] 
public class Foo 
{ 
    public string Bar1 { get; set; } 
    public string Bar2 { get; set; } 
    public string Bar3 { get; set; } 
} 

A continuación, el control de usuario tendrán el siguiente marcado:

de marcado (GridDisplayRow.ascx):

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="GridDisplayRow.ascx.cs" Inherits="GridDisplayRow" %> 
<div> 
    <div class="cell"> 
     <asp:TextBox id="TxtProperty1" runat="server"/> 
    </div> 
    <div class="cell"> 
     <asp:DropDownList ID="DDLProperty2" runat="server" OnSelectedIndexChanged="DDLProperty2_OnSelectedIndexChanged" AutoPostBack="true"> 
     </asp:DropDownList> 
    </div> 
    <div class="cell"> 
     <input type="radio" id="RadProperty3" runat="server"> 
    </div> 
</div> 

Aviso toda la etiquetas div Los div hijos se flotan ... para que se muestren uno al lado del otro.

Codebehind (GridDisplayRow.ascx.cs):

class GridDisplayRow:UserControl 
{ 
    public event EventHandler<System.EventArgs> SomethingHappened; 

    protected void Page_Load(object sender, EventArgs e) 
    { 
     //Initialize the drop down with something; 
    } 

    //this is where we handle internal events generated by children controls. 
    //Eg: the drop down's index changed. 
    protected void DDLProperty2_OnSelectedIndexChanged(object sender, EventArgs e) 
    { 
     //we update some other child control in this... 
     this.TxtProperty1.Text = this.DDLProperty2.Value; 

     //and maybe we want to signal the page that some event happened 
     if(SomethingHappened != null) 
     { 
      //Notify the page that SomethingHappened event occured 
      SomethingHappened(this, EventArgs.Empty); 
     } 
    } 

    //This is where the binding happens 
    public object BindingObject 
    { 
     set 
     { 
      Foo temp = (Foo)value; 
      this.TxtProperty1.Text = temp.Bar1; 
      this.DDLProperty2.Value = temp.Bar2; 
      this.RadProperty3.Value = temp.Bar3; 

      this.ViewState["Foo"] = temp; 
     } 
    } 
} 

Así que en el código anterior estamos manejando la unión a Foo, en otras palabras, estamos mostrando propiedades de Foo en cada celda (div) del control .El molde es necesario porque la propiedad anterior es de tipo objeto, y en la plantilla de elemento de la cuadrícula/repetidor/lo que tienes, vincularás una instancia de GridDisplayRow al objeto Container.DataItem como se muestra a continuación. Hemos de tener en cuenta que si el origen de datos es un conjunto de datos, por ejemplo, usted tiene que echar a DataRow, o si se necesita cualquier tipo de datos adecuado:

Página de marcado:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Test.aspx.cs" Inherits="Test" %> 
<%@ Register src="GridDisplayRow.ascx" tagname="GridRow" tagprefix="ctrl" %> 

<asp:GridView ID="GridView1" runat="server"> 
    <Columns> 
     <asp:TemplateField> 
      <HeaderTemplate> 
       <div> 
        <div class="header cell">Header 1</div> 
        <div class="header cell">Header 2</div> 
        <div class="header cell">Header 3</div> 
       </div> 
      </HeaderTemplate> 
      <ItemTemplate> 
       <ctrl:GridRow ID="Row" runat="server" BindingObject='<%# Container.DataItem %>' OnSomethingHappened="Row_SomethingHappened" /> 
      </ItemTemplate> 
     </asp:TemplateField> 
    </Columns> 
</asp:GridView> 

no me gusta trabajar con rejillas porque son desordenadas y engorrosas. En este caso, engañamos a la cuadrícula para crear una tabla con una sola celda por fila y nos ocupamos del diseño dentro de esa celda mediante hojas de estilo.

Tenga en cuenta que esto funciona mejor con un repetidor ya que es muy eficiente y tiene menos carga.

Ahora vinculando la grilla: Cualquier fuente que implemente IEnumerable se puede usar para enlazar a la grilla. Como tal, una colección como List será suficiente.

Cuando el control GridRow dispara sus eventos, se envía una referencia al control a través del remitente del objeto, por lo tanto, si emite el remitente al tipo correcto puede tomar las propiedades internas del control ... las posibilidades son infinitas.

La ventaja de este método es la abstracción. Cada control puede manejar sus propios eventos, o elige notificar a la página de eventos que ocurrieron dentro de él .... bla bla bla. Entiendes la idea.

0

Trate de usar un ListView es más fácil de manejar ese tipo de requisitos. Si coloca ListView dentro de Update Panel, puede tener una mejor experiencia de usuario

Cuestiones relacionadas