2008-10-06 7 views
10

Necesito recuperar un conjunto de widgets de mi capa de acceso a datos, agrupados por widget.Manufacturer, para mostrarlos en un conjunto de listas de listas ASP.NET anidadas.Mostrar un IGrouping <> con ListViews anidados

El problema es que (por lo que puedo decir) el enfoque anidado ListView me requiere dar forma a los datos antes de usarlos, y no puedo encontrar el mejor enfoque para tomar. El mejor que he podido llegar a hasta el momento es poner una consulta LINQ en mi capa de acceso de datos, así:

var result = from widget in GetAllWidgets(int widgetTypeID) 
      group widget by widget.Manufacturer into groupedWidgets 
      let widgets = from widgetGroup in groupedWidgets 
          select widgetGroup 
      select new { Manufacturer = groupedWidgets.Key, Widgets = widgets }; 

Por supuesto, los tipos anónimos no se pueden transferir, de manera que doesn' t trabajo. Definir una clase personalizada para adjuntar datos parece ser el camino equivocado. ¿Hay alguna forma de que pueda realizar la agrupación en el lado ASP.NET de las cosas? Estoy usando ObjectDataSources para acceder al DAL.

Actualizado: Bueno, no estoy creando un tipo anónimo más, y en su lugar pasa a mi DAL una IEnumerable<IGrouping<Manufacturer, Widget>> a la página ASP.NET, pero ¿cómo puedo usar esto en mis listviews? Necesito hacer que el código HTML siguiente (o algo muy parecido a él)

<ul> 
    <li>Foo Corp. 
    <ol> 
     <li>Baz</li> 
     <li>Quux</li> 
    </ol> 
    </li> 
    <li>Bar Corp. 
    <ol> 
     <li>Thinger</li> 
     <li>Whatsit</li> 
    </ol> 
    </li> 
</ul> 

Originalmente, tenía un ListView dentro de un ListView de este modo:

<asp:ListView ID="ManufacturerListView"> 
    <LayoutTemplate> 
     <ul> 
      <asp:Placeholder ID="itemPlaceholder" runat="server" /> 
     </ul> 
    </LayoutTemplate> 
    <ItemTemplate> 
     <li><asp:Label Text='<%# Eval("Manufacturer.Name") %>' /> 
     <li> 
     <asp:ListView ID="WidgetsListView" runat="server" DataSource='<%# Eval("Widgets") %>'> 
      <LayoutTemplate> 
       <ol> 
        <asp:PlaceHolder runat="server" ID="itemPlaceholder" /> 
      </ol> 
      </LayoutTemplate> 
      <ItemTemplate> 
       <li><asp:Label Text='<%# Eval("Name") %>'></li> 
      </ItemTemplate> 
     </asp:ListView> 
     </li> 
    </ItemTemplate> 
</asp:ListView> 

Nota cómo la propiedad DataSource de WidgetsListView es en sí misma datos vinculados. ¿Cómo puedo duplicar esta funcionalidad sin cambiar la forma de los datos?

Esto se está poniendo un poco complicado, lo siento si debería haber hecho una pregunta por separado en su lugar.

Respuesta

12

Ok, voy a contradecir mi declaración anterior. Como eval quiere algún tipo de nombre de propiedad en el control anidado, probablemente deberíamos darle forma a esos datos.

public class CustomGroup<TKey, TValue> 
{ 
    public TKey Key {get;set;} 
    public IEnumerable<TValue> Values {get;set;} 
} 

// y utilizarlo thusly ...

IEnumerable<CustomGroup<Manufacturer, Widget>> result = 
    GetAllWidgets(widgetTypeId) 
    .GroupBy(w => w.Manufacturer) 
    .Select(g => new CustomGroup<Manufacturer, Widget>(){Key = g.Key, Values = g}; 

/// e incluso más tarde ...

<asp:ListView ID="ManufacturerListView"> 
<LayoutTemplate> 
    <ul> 
     <asp:Placeholder ID="itemPlaceholder" runat="server" /> 
    </ul> 
</LayoutTemplate> 
<ItemTemplate> 
    <li><asp:Label Text='<%# Eval("Key.Name") %>' /> 
    <li> 
    <asp:ListView ID="WidgetsListView" runat="server" DataSource='<%# Eval("Values") %>'> 
     <LayoutTemplate> 
      <ol> 
       <asp:PlaceHolder runat="server" ID="itemPlaceholder" /> 
      </ol> 
     </LayoutTemplate> 
     <ItemTemplate> 
      <li><asp:Label Text='<%# Eval("Name") %>'></li> 
     </ItemTemplate> 
    </asp:ListView> 
    </li> 
</ItemTemplate> 
</asp:ListView> 
3

Al utilizar LINQ al grupo, se puede obtener un objeto fuertemente tipado sin esa conformación:

List<int> myInts = new List<int>() { 1, 2, 3, 4, 5 }; 
IEnumerable<IGrouping<int, int>> myGroups = myInts.GroupBy(i => i % 2); 
foreach (IGrouping<int, int> g in myGroups) 
{ 
    Console.WriteLine(g.Key); 
    foreach (int i in g) 
    { 
    Console.WriteLine(" {0}", i); 
    } 
} 
Console.ReadLine(); 

En su caso, usted tendría que:

IEnumerable<IGrouping<Manufacturer, Widget>> result = 
    GetAllWidgets(widgetTypeId).GroupBy(w => w.Manufacturer); 

Esto le permitirá devuelve el resultado del método.

+0

Gracias por el asesoramiento. Actualicé mi pregunta original con más información. –

5

que acaba de pasar bastante tiempo en esto. Finalmente encontró la solución y es muy simple.


var enumerableData = myData.Tables[0].AsEnumerable(); 
var groupedData = enumerableData.GroupBy(x => x["GroupingColumn"]); 

myParentRepeater.DataSource = groupedData; 
myParentRepeater.DataBind(); 

<asp:Repeater ID="myParentRepeater" runat="server"> 
    <ItemTemplate> 
    <h3><%#Eval("Key") %></h3> 
    <asp:Repeater ID="myChildRepeater" runat="server" DataSource='<%# Container.DataItem %>'> 
     <ItemTemplate> 
     <%#((DataRow)Container.DataItem)["ChildDataColumn1"] %> 
     <%#((DataRow)Container.DataItem)["ChildDataColumn2"] %> 
     </ItemTemplate> 
     <SeparatorTemplate> 
     <br /> 
     </SeparatorTemplate> 
    </asp:Repeater> 
    </ItemTemplate> 
</asp:Repeater> 

Eval ("Key") devuelve el valor agrupados. Al recuperar información secundaria, Container.DataItem es de tipo IGrouping pero simplemente lo convierte al tipo correcto.

Espero que esto ayude a alguien más.

+0

En su plantilla de elemento, puede reemplazar '<% # ((DataRow) Container.DataItem) [" ChildDataColumn1 "]%>' con '<% # Eval (" ChildDataColumn1 ")%>'. – Armstrongest

+0

¡Un gran hallazgo! Estaba buscando algún tipo de valor como ".Values" o algo así. Es difícil de poner en una consulta de búsqueda también. ¡Gracias! – rtpHarry

Cuestiones relacionadas