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 列で昇順ソートした結果となります。
