ASP.NET GridView の列をクリックしたタイミングで、列をソートする機能の実装方法を紹介します。また、ソートされた列ヘッダーには、ソート方向を示すアイコンも表示します。
GridView でのソート実装の煩雑さ
GridView では、データの並び替えのみであれば、AllowSorting プロパティを有効化するのみで実現できます。ただし、この状態では列ヘッダーにソート状態が反映されず、ユーザーはどの列をソートしたのかが非常に分かりづらいという課題があります。今回、簡易にソートアイコン(ソートインディケーター)も表示する実装を紹介します。
GridView インスタンスの準備
ASPX 上で、GridView インスタンスを宣言します。
<form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager> <div> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AllowSorting="true" OnSorting="GridView1_Sorting" OnRowDataBound="GridView1_RowDataBound"> <Columns> <asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" /> <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" /> <asp:BoundField DataField="Age" HeaderText="Age" SortExpression="Age" /> </Columns> </asp:GridView> </div> </form>
サンプルデータのバインド
DataTable のダミーデータをバインドしています。コードの注意点は、
1.ページロードタイミング(Page_Load イベント)で、BindGrid() 経由で GridView の DataSource に DataTable データをバインドしています。
2.ソート情報を含む呼び出しの場合、DataTable の DataView プロパティを利用して、ソート情報を付与したデータを GridView にバインドします。初回表示時はソート情報は含みませんが、後述の Sorting イベント内部から BindGrid が呼ばれるタイミングで、ソート情報が提供されます。
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { BindGrid(); } } private void BindGrid(string sortExpression = null, string sortDirection = null) { var dataSource = GetData(); if (sortExpression != null) { DataView dv = dataSource.DefaultView; dv.Sort = sortExpression + " " + sortDirection; GridView1.DataSource = dv; } else { GridView1.DataSource = dataSource; } GridView1.DataBind(); } private DataTable GetData() { DataColumn[] primaryColumn = new DataColumn[1]; DataTable dataTable = new DataTable(); primaryColumn[0] = dataTable.Columns.Add("ID", typeof(int)); dataTable.Columns.Add("Name", typeof(string)); dataTable.Columns.Add("Age", typeof(int)); dataTable.Rows.Add(1, "Junya", 23); dataTable.Rows.Add(2, "Kyoko", 25); dataTable.Rows.Add(3, "Emi", 24); dataTable.Rows.Add(4, "Tatsuya", 28); dataTable.Rows.Add(5, "Naoki", 33); dataTable.Rows.Add(6, "Yuka", 25); dataTable.Rows.Add(7, "Mami", 24); dataTable.PrimaryKey = primaryColumn; return dataTable; }
ソート機能の有効化(AllowSorting プロパティ)
ソート機能の有効化には、GridView の AllowSorting プロパティを有効化(true)していることを確認します。
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" AllowSorting="true" OnSorting="GridView1_Sorting" OnRowDataBound="GridView1_RowDataBound"> ... </asp:GridView>
また、列ヘッダークリックなどによるソート実行時の Sorting イベントをハンドルし、GetSortDirection メソッド内でソート情報を組み立てて、BindGrid メソッドにソート情報を提供します。
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e) { string sortExpression = e.SortExpression; string sortDirection = GetSortDirection(sortExpression); BindGrid(sortExpression, sortDirection); }
private string GetSortDirection(string column) { // ViewState から前回のソートの状態を取得 string sortDirection = "ASC"; // デフォルトは昇順 string previousSortExpression = ViewState["SortExpression"] as string; string previousSortDirection = ViewState["SortDirection"] as string; if (previousSortExpression != null && previousSortExpression == column) { // 前回と同じ列でソートする場合は、ソート順を逆にする sortDirection = previousSortDirection == "ASC" ? "DESC" : "ASC"; } // 現在のソート状態を ViewState に保存 ViewState["SortExpression"] = column; ViewState["SortDirection"] = sortDirection; return sortDirection; }
この段階で、列のソートが動作するようになりました。下記実行例では、ID 列を降順でソートしています。この段階では、まだソートアイコンは表示されていません。
ソートアイコンの表示
続いて、ソートアイコンの表示も行いましょう。今回ソートアイコンは、ヘッダーの文字列に、ソート方向を示す三角形を加えることで実現します。RowDataBound イベントは、GridView で行にデータがバインドされた時に発生します。29-30 行目で、ソート方向に応じて三角形を加えていることが分かります。
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { // ヘッダーでなければ処理をキャンセル if (e.Row.RowType != DataControlRowType.Header) { return; } string sortExpression = ViewState["SortExpression"] as string; string sortDirection = ViewState["SortDirection"] as string; // ソート情報が空であれば処理をキャンセル if (string.IsNullOrEmpty(sortExpression)) { return; } // ソート対象の列を探してインディケーターを追加 foreach (TableCell cell in e.Row.Cells) { if (!cell.HasControls()) { return; } LinkButton sortLinkButton = cell.Controls[0] as LinkButton; if (sortLinkButton != null && sortLinkButton.CommandArgument == sortExpression) { string sortIndicator = sortDirection == "ASC" ? " ▲" : " ▼"; sortLinkButton.Text = sortLinkButton.Text + sortIndicator; } } }
最終的な実行結果
任意の列でソートを行うことで、データの並び替えと、ソートアイコンが表示されるようになりました。下記スクリーンショットでは、Name 列で昇順ソートした結果となります。