2012-10-30 20 views
5

Mam dwie przechowywane procedury, które zwracają dwa zestawy powiązanych danych. Dane są takie. Pierwsza procedura zwraca dane takGrupowanie danych w Asp.Net Gridview

ISSUE_ID   ISSUETYPE   
------------------------------------- 
1   ISSUE 1 TYPE 
2   ISSUE 2 TYPE 
3   ISSUE 3 TYPE 
4   ISSUE 4 TYPE 

Druga procedura zwraca dane, takie jak ten na podstawie ISSUE_ID

HEADER ID   HEADER NAME   ISSUE_ID  
----------------------------------------------------- 
1     HEADER 1 NAME    1 
2     HEADER 2 NAME    1 
3     HEADER 3 NAME    2 
4     HEADER 4 NAME    2 
5     HEADER 5 NAME    3 

Rzecz Jak mogę grupa ta opiera się na ISSUE_ID i wyświetlać je w grupach w gridview przy użyciu zarówno przechowywane procedury. Mam google na forach i znalazłem opcje zagnieżdżone gridview. Czy mogę to osiągnąć bez użycia tego zagnieżdżonego widoku siatki.

Wreszcie chcę wyświetlić w widoku siatki w ten sposób.

ISSUE 1 TYPE 
----------------------------- 
      HEADER 1 NAME     
      HEADER 2 NAME 
ISSUE 2 TYPE 
----------------------------- 
      HEADER 3 NAME     
      HEADER 4 NAME     
ISSUE 3 TYPE 
----------------------------- 
      HEADER 5 NAME     

Dziękuję z góry za milion. Potrzebujesz sugestii, aby to osiągnąć.

+2

[Ten wpis na blogu] (http://technico.qnownow.com/grouping-gridview-aspnet/) może Ci w tym pomóc. Istnieje wiele przykładów i wyjaśnień. –

+0

Dlaczego zagnieżdżanie siatki nie jest opcją? – Curt

+0

@Curtowanie w gnieździe wygląda obiecująco, jednak może to zepsuć takie rzeczy jak paginacja. –

Odpowiedz

5

Przykładem ugrupowania w ASP.NET GridView

<asp:GridView ID="grdViewOrders" CssClass="serh-grid" runat="server" AutoGenerateColumns="False" TabIndex="1" Width="100%" CellPadding="4" ForeColor="Black" GridLines="Vertical" OnRowDataBound="grdViewOrders_RowDataBound" OnRowCommand="grdViewOrders_RowCommand" OnRowCreated="grdViewOrders_RowCreated" BackColor="White" BorderColor="#DEDFDE" BorderStyle="None" BorderWidth="1px"> 
    <Columns>  
     <asp:BoundField DataField="OrderID" HeaderText="OrderID" SortExpression="OrderID" />    
     <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />    
     <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />   
     <asp:BoundField DataField="Quantity" HeaderText="Quantity" SortExpression="Quantity" />   
     <asp:BoundField DataField="Discount" HeaderText="Discount" SortExpression="Discount" />   
     <asp:BoundField DataField="Amount" HeaderText="Amount" SortExpression="Amount" />      
    </Columns>  
    <FooterStyle BackColor="#CCCC99" />  
    <SelectedRowStyle CssClass="grid-sltrow" />  
    <HeaderStyle BackColor="#6B696B" Font-Bold="True" ForeColor="White" BorderStyle="Solid" BorderWidth="1px" BorderColor="Black" />   
</asp:GridView> 

Grouping in ASP.Net GridView

Uwagi:

  • Głównym logika w zdarzeniach RowCreated i RowDataBound w GridView.

  • Podczas iteracja wszystkich wierszy Jestem

    • zerkając na customerId (wskaźnik podstawowy) i sprawdzając inne wiersze.
    • śledzenie uruchomionego GrandTotal (ów)
    • śledzenie uruchomionego SUBTOTAL (ów)
  • W każdym momencie Podstawowe zmiany indeksów podczas iteracji przez wynik-set:

    • Dodaj SUBTOTAL (ów) wiersz
    • reset SUBTOTAL (e) jest gotowy do następnej grupy
  • Nagłówek wyświetlany jako nowy wiersz w widoku GridView.

GridView pomocnik

Używanie GridViewHelper

Poniżej widzimy kilka próbek GridViewHelper. Najpierw pokazujemy siatkę, do której zostaną utworzone grupy i podsumowania.Dane próbka pochodzi z bazy danych Northwind, z kilkoma modyfikacjami:

enter image description here

Aby utworzyć podsumowanie dla kolumny ItemTotal musimy tylko obiecanych 2 linie kodu:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum); 
} 

Najpierw tworzymy GridViewHelper ustawiający siatkę, w której będzie działać w konstruktorze. Następnie rejestrujemy podsumowanie określające nazwę kolumny i operację podsumowania do wykonania. Wynik jest poniżej:

enter image description here

W tym przykładzie nowa linia została dodana, aby wyświetlić podsumowanie. Inną opcją jest użycie wiersza stopki do wyświetlenia podsumowania, zamiast tworzenia nowego. Po dodaniu nowego wiersza do siatki tworzone są tylko wymagane komórki do wyświetlenia kolumn podsumowanych. Za pomocą stopki tworzone są wszystkie komórki. W przypadku podsumowań grup generowanie wszystkich komórek lub tylko potrzebnych komórek jest atrybutem grupowym.

Teraz utworzymy grupę. Kod jest wyświetlany poniżej:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterGroup("ShipRegion", true, true); 
    helper.ApplyGroupSort(); 
} 

Pierwszy parametr metody RegisterGroup definiuje kolumny, do których grupa musi zostać utworzona. Możliwe jest również utworzenie grupy złożonej, składającej się z szeregu kolumn. Drugi parametr określa, czy grupa jest automatyczna. W tym przypadku nowy wiersz zostanie automatycznie utworzony dla nagłówka grupy. Trzeci parametr określa, czy kolumny grup muszą być ukryte. Metoda ApplyGroupSort ustawia wyrażenie sortowania siatki jako kolumny grupy, w tym przypadku ShipRegion. Jest to wymagane do prawidłowego grupowania prac, chyba że dane są uporządkowane z bazy danych.

W powyższej próbce ShipRegion kolumna zostały ukryte:

enter image description here

Zróbmy coś bardziej interesujący, dodajmy podsumowanie do utworzonej grupy. Potrzebujemy jeszcze tylko jednej linii do zarejestrowania podsumowania w grupie:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterGroup("ShipRegion", true, true); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipRegion"); 
    helper.ApplyGroupSort(); 
} 

Tym razem metoda RegisterSummary przyjmuje kolejny parametr. Parametr określa nazwę grupy, do której należy utworzyć podsumowanie. Nazwa grupy jest automatycznie generowana z nazw kolumn grupy. Jeśli grupa ma tylko jedną kolumnę, nazwa grupy będzie nazwą tej kolumny. Jeśli grupa ma więcej niż jedną kolumnę, nazwa grupy będzie uporządkowanym połączeniem kolumn tworzących grupę, połączonych znakiem plus ("+"): "ShipRegion + ShipName".

Widzimy poniżej siatki z grupowania i podsumowania dla grupy:

enter image description here

Jest możliwe, aby utworzyć więcej niż jedną grupę w siatce, symulując hierarchicznego grupowania, jak widać poniżej:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterGroup("ShipRegion", true, true); 
    helper.RegisterGroup("ShipName", true, true); 
    helper.ApplyGroupSort(); 
} 

Wynik:

enter image description here

Wizualizacja jest zagrożona, gdy istnieje więcej niż jedna grupa.GridViewHelper ma zdarzenia umożliwiające łatwą implementację ustawień wizualnych lub funkcjonalnych. Lista zdarzeń znajduje się poniżej:

  • GroupStart: Występuje, gdy rozpoczyna się nowa grupa, oznacza to, że nowe wartości znajdują się w kolumnie grupy.
  • GroupEnd: Występuje w ostatnim wierszu grupy
  • GroupHeader: Występuje, gdy dla grupy zostanie dodany automatyczny wiersz nagłówka. Zdarzenie nie jest wyzwalane, jeśli grupa nie jest automatyczna.
  • GroupSummary: Występuje, gdy generowany jest wiersz podsumowania dla grupy. Zdarzenie nie jest wyzwalane, jeśli grupa nie jest automatyczna, ale zostanie wywołane, jeśli grupa jest grupą tłumiącą (zobaczymy ją później).
  • GeneralSummary: Występuje po obliczeniu ogólnych podsumowań. Jeśli podsumowanie jest automatyczne, zdarzenie występuje po dodaniu wiersza podsumowania i po umieszczeniu wartości podsumowania w wierszu.
  • FooterDataBound: Występuje w databinding stopki.

Z kilkoma więcej linii kodu możemy poprawić wizualny aspekt Grid:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterGroup("ShipRegion", true, true); 
    helper.RegisterGroup("ShipName", true, true); 
    helper.GroupHeader += new GroupEvent(helper_GroupHeader); 
    helper.ApplyGroupSort(); 
} 

private void helper_GroupHeader(string groupName, object[] values, GridViewRow row) 
{ 
    if (groupName == "ShipRegion") 
    { 
     row.BackColor = Color.LightGray; 
     row.Cells[0].Text = "&nbsp;&nbsp;" + row.Cells[0].Text; 
    } 
    else if (groupName == "ShipName") 
    { 
     row.BackColor = Color.FromArgb(236, 236, 236); 
     row.Cells[0].Text = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" + row.Cells[0].Text; 
    } 
} 

Siatka po kosmetykach:

enter image description here

więcej opcji grupowania

Istnieją jeszcze dwa w ciekawe próbki. Pierwszy przedstawia grupę złożoną. Druga definiuje grupę suppress, która ma takie samo zachowanie klauzuli GROUP BY BY. Powtarzane wartości są pomijane, a operacja podsumowania jest wykonywana w innych kolumnach.

Poniżej możemy zobaczyć kod i wyglądu siatki dla grupy kompozytowe:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    string[] cols = new string[2]; 
    cols[0] = "ShipRegion"; 
    cols[1] = "ShipName"; 
    helper.RegisterGroup(cols, true, true); 
    helper.ApplyGroupSort(); 
} 

enter image description here

możemy dodać podsumowanie do grupy. Tym razem będziemy definiować przeciętną operację i dodać etykietę do wskazywania operacji:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    string[] cols = new string[2]; 
    cols[0] = "ShipRegion"; 
    cols[1] = "ShipName"; 
    helper.RegisterGroup(cols, true, true); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Avg, "ShipRegion+ShipName"); 
    helper.GroupSummary += new GroupEvent(helper_GroupSummary); 
    helper.ApplyGroupSort(); 
} 

private void helper_GroupSummary(string groupName, object[] values, GridViewRow row) 
{ 
    row.Cells[0].HorizontalAlign = HorizontalAlign.Right; 
    row.Cells[0].Text = "Average"; 
} 

enter image description here

Ostatnia próba utworzy grupę eliminują. Należy wspomnieć, że jeśli zdefiniowana jest grupa pomijania, nie można utworzyć żadnej innej grupy. W ten sam sposób, jeśli zdefiniowana jest już grupa, nie możemy utworzyć grupy pomijanej, a wyjątek zostanie podniesiony, jeśli spróbujemy.

Poniżej możemy zobaczyć kod i wyglądu siatki dla grupy tłumić:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.SetSuppressGroup("ShipName"); 
    helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName"); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName"); 
    helper.ApplyGroupSort(); 
} 

enter image description here

No wartość jest wyświetlana dla kolumn, które nie mają pracy Podsumowanie zdefiniowany. Ma to sens, ponieważ GridViewHelper nie wie, jak przystąpić do podsumowywania wartości znalezionych w wierszach grupy do unikalnej wartości.Przypomina to pewną znaną wiadomość:

"Kolumna" nazwa_kolumny "jest niepoprawna na liście wyboru, ponieważ nie jest zawarta ani w funkcji agregującej ani w klauzuli GROUP BY."

To nie ma sensu, aby wyświetlić kolumny, które nie mają pracy Podsumowanie i ukryć je musimy wywołać metodę:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.SetSuppressGroup(rdBtnLstGroup.SelectedValue); 
    helper.RegisterSummary("Quantity", SummaryOperation.Sum, "ShipName"); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName"); 
    helper.SetInvisibleColumnsWithoutGroupSummary(); 
    helper.ApplyGroupSort(); 
} 

wiem, że jest to duży duży imię! Powstały siatki można zobaczyć poniżej:

enter image description here

operacji Podsumowanie

GridViewHelper posiada trzy wbudowane w operacjach Podsumowanie: Podsumowując, średniego i liczby wierszy. Bardzo przydatną funkcją jest możliwość zdefiniowania niestandardowych operacji podsumowania. Aby to osiągnąć, musimy udostępnić GridViewHelper dwie metody. Metoda zostanie wywołana dla każdego wiersza znalezionego w siatce (lub grupie), a druga zostanie wywołana w celu pobrania wyniku operacji podsumowania. Poniżej mamy próbkę niestandardowej operacji podsumowania. Operacja semi-dummy zwróci minimalną wartość:

private List<int> mQuantities = new List<int>(); 

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterSummary("Quantity", SaveQuantity, GetMinQuantity); 
} 

private void SaveQuantity(string column, string group, object value) 
{ 
    mQuantities.Add(Convert.ToInt32(value)); 
} 

private object GetMinQuantity(string column, string group) 
{ 
    int[] qArray = new int[mQuantities.Count]; 
    mQuantities.CopyTo(qArray); 
    Array.Sort(qArray); 
    return qArray[0]; 
} 

W powyższym kodzie możemy zobaczyć wymagane podpowiedzi metod. Oba otrzymują podsumowane nazwy grup i kolumn. Jeśli podsumowanie nie jest względne do grupy, parametr grupy będzie mieć wartość null. Metoda, która jest wywoływana dla każdego wiersza znalezionego w siatce, odbiera również wartość kolumny w bieżącym wierszu.

Powstały siatki można zobaczyć poniżej:

enter image description here

Ograniczenia

w jednej próbce powiedzieliśmy, że możemy symulować hierarchicznego grupowania. Chociaż siatka wydaje się przedstawiać hierarchiczne grupowanie, rzeczywista implementacja nie jest hierarchiczna. Nie ma grupy lub podgrupy. Są tylko grupy zarejestrowane sekwencyjnie. Staje się to problemem, jeśli musimy utworzyć podsumowanie dla wewnętrznej grupy. Poniżej możemy zobaczyć, co się dzieje w tej sytuacji:

protected void Page_Load(object sender, EventArgs e) 
{ 
    GridViewHelper helper = new GridViewHelper(this.GridView1); 
    helper.RegisterGroup("ShipRegion", true, true); 
    helper.RegisterGroup("ShipName", true, true); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum, "ShipName"); 
    helper.RegisterSummary("ItemTotal", SummaryOperation.Sum); 
    helper.GroupSummary += new GroupEvent(helper_Bug); 
    helper.ApplyGroupSort(); 
} 

private void helper_Bug(string groupName, object[] values, GridViewRow row) 
{ 
    if (groupName == null) return; 

    row.BackColor = Color.Bisque; 
    row.Cells[0].HorizontalAlign = HorizontalAlign.Center; 
    row.Cells[0].Text = "[ Summary for " + groupName + " " + values[0] + " ]"; 
} 

enter image description here

Jak widzimy, podsumowanie jest tworzony po nagłówku grupy zewnętrznej. Dzieje się tak dlatego, że sekwencja zdarzeń jest:

Group1_Start 
Group1_End 
Group2_Start 
Group2_End 

hierarchicznego grupy sekwencja zdarzenie powinno być:

Group1_Start 
Group2_Start 
Group2_End 
Group1_End 

Wykonanie

GridViewHelper wdrożono jako samodzielne grupy zamiast dziedziczona klasa. Umożliwia to użycie GridViewHelper z dowolnym GridView i nie wymusza na programistach dziedziczenia określonego GridView, co może mieć wpływ na projektowanie klas. W rozwiązaniu są jeszcze cztery klasy: GridViewSummary, GridViewGroup, GridViewSummaryList i GridViewGroupList. Klasy "list" zostały utworzone, aby umożliwić dostęp za pomocą indeksera string: helper.GeneralSummaries ["ItemTotal"].

Gdy GridViewHelper jest utworzone odniesienie do GridView docelowym jest zapisywana, a zdarzenie RowDataBound jest związany z metodą, która wykonuje pracę:

public GridViewHelper(GridView grd, bool useFooterForGeneralSummaries, SortDirection groupSortDirection) 
{ 
    this.mGrid = grd; 
    this.useFooter = useFooterForGeneralSummaries; 
    this.groupSortDir = groupSortDirection; 
    this.mGeneralSummaries = new GridViewSummaryList(); 
    this.mGroups = new GridViewGroupList(); 
    this.mGrid.RowDataBound += new GridViewRowEventHandler(RowDataBoundHandler); 
} 

Niektóre metody wykorzystywane wewnętrznie w GridViewHelper zdefiniowano publiczne, ponieważ zapewniają pewne przydatne funkcje, które mogą być potrzebne w przypadku niektórych dostosowań. Istnieje kilka innych opcji, które nie zostały pokazane w przykładach, ale można je łatwo zweryfikować za pomocą Visual Studio Intellisense.

Znane problemy

Wydajność może być zagrożona z nadmiernego boksu i unboxing typów wartości. Aby rozwiązać ten problem, możemy zaimplementować wbudowane operacje podsumowujące za pomocą generycznych, ale nie jest to łatwe, jak chcielibyśmy, jak można to zobaczyć w Korzystanie z Generics for Calculations. Inna możliwość: przeciążenie operatora generycznymi. W rzeczywistości nie wpłynie to na aplikację, z wyjątkiem sytuacji, gdy istnieje milion wierszy lub jeśli istnieje tysiące użytkowników grupujących i podsumowujących dane jednocześnie.

Próbka online zachowuje wartość parametru GridView EnableViewState. Jest to wymagane, ponieważ gdy właściwość EnableViewState ma wartość true, jeśli strona znajduje się w funkcji PostBack, GridView zostanie odbudowany z ViewState i nie wywoła zdarzenia RowDataBound. Możemy bezpiecznie wyłączyć ViewState w ASP.Net 2.0, ponieważ ControlState będzie nadal zapisywane.

3

To nie odpowiada dokładnie na pytanie, tutaj używam denormalizowanego zestawu wyników zamiast tego w pytaniu, jednak dostosowanie danych nie powinno być głównym problemem.

Oto jak uzyskać grupowanie kopalni, najpierw dołączyć do wiersza danych zobowiązany do znalezienia grupy, a także ja porwać delegata render:

readonly Dictionary<Control, string> _groupNames = new Dictionary<Control, string>(); 
private Group _lastGroup; 
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e) 
{ 
    if (e.Row.RowType == DataControlRowType.DataRow) 
    { 
     var obj = (Obj)e.Row.DataItem; 
     if (obj.Group != _lastGroup) 
     { 
      e.Row.SetRenderMethodDelegate(RenderGridViewRowWithHeader); 
      _lastGroup = obj.Group; 

      // Cache group description for this row, note that you might 
      // like to implement this differently if you have your data normalized. 
      _groupNames[e.Row] = obj.Group.Description;     } 
     } 
    } 
} 

Następnie w metodzie render:

private void RenderGridViewRowWithHeader(HtmlTextWriter output, Control container) 
{ 
    // Render group header 
    var row = new TableRow { CssClass = "groupingCssClass" }; 
    row.Cells.Add(new TableCell()); 
    row.Cells.Add(new TableCell 
    { 
     ColumnSpan = ((GridViewRow)container).Cells.Count - 1, 
     Text = _groupNames[container] 
    }); 
    row.RenderControl(output); 

    // Render row 
    container.SetRenderMethodDelegate(null); // avoid recursive call 
    container.RenderControl(output); 
} 

Wiem, że to hack, ale ASP.NET jest o to wszystko, gdy pojawi się w szczegóły. To rozwiązanie jest dość przyjazne ze stanem kontroli, dodawanie wierszy do siatki w środowisku wykonawczym może powodować zachowanie zestresowane.

+0

To wszystko sprawia, że ​​jestem na drodze ... Miałem trudny czas związany z wyrzuceniem do siatki Ręcznie dodałem wiersze i deleguję, aby działało poprawnie. Dziękuję @GLM –

Powiązane problemy