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>
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:
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:
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:
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:
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:
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 = " " + row.Cells[0].Text;
}
else if (groupName == "ShipName")
{
row.BackColor = Color.FromArgb(236, 236, 236);
row.Cells[0].Text = " " + row.Cells[0].Text;
}
}
Siatka po kosmetykach:
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();
}
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";
}
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();
}
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:
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:
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] + " ]";
}
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.
[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ń. –
Dlaczego zagnieżdżanie siatki nie jest opcją? – Curt
@Curtowanie w gnieździe wygląda obiecująco, jednak może to zepsuć takie rzeczy jak paginacja. –