SqlDataSource などのデータソースコントロールを使わないで GridView の各列にソート機能を実装するにはどうすればいいかということを書きます。
元は MSDN Forum のスレッド「SqlDataSourceを使わずに、GridViewの並べ替えができますでしょうか?」の話です。
MSDN ライブラリ GridView Class の「データへのバインド」のセクションに書いてありますが、GridView はデータソースコントロール(SqlDataSource, ObjectDataSource など)と連携して並べ替え、更新、削除、およびページング機能を提供しています。
逆に言えば、データソースコントロールを使わないと、ソート、更新、削除、およびページング機能が必要な場合、全て自力でコードを書いて実装することになります。
以下に、例としてソート機能を自力で GridView に実装する方法を書きます。
ソートを行うために GridView と SqlDataSource の中でどのような操作が行われているかは不明ですが、おそらく、取得したデータから DataView を作って、その Sort プロパティ に SortExpression を設定し、ソートした結果を GirdView に表示していると思われます。
そのあたりの処理を自力でコードを書いて実装してみます。
昇順に並べ替えるだけなら、GridView.Sorting イベントのハンドラで、DataView の Sort プロパティを引数の GridViewSortEventArgs オブジェクトから取得できる SortExpression に設定するだけで可能です。
SqlDataSource + GridView を使った場合、同じ LinkButton のクリックを繰り返すと ASC / DESC が切り替わりますが、そこまで同じにしようとするとちょっと面倒です。
SqlDataSource + GridView でそれをどのように実現しているか分かりませんが、GridView の属性に CurrentSortField, CurrentSortDir というのを追加し、それに前回クリックされた LinkButton の SortExpression およびその時 ASC or DESC どちらだったかの情報を保持することを考えてみました。
そのソースコードを以下にアップしておきます。このコードの実行結果が上の画像の GridView です。ヘッダの Name を 2 回クリックして降順に並べ替えています。
.aspx.cs ファイル
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
public partial class _0055_GridViewSorting : System.Web.UI.Page
{
// データソース用の DataView を作成
protected DataView CreateDataSource()
{
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add(new DataColumn("ID", typeof(Int32)));
dt.Columns.Add(new DataColumn("Name", typeof(string)));
dt.Columns.Add(new DataColumn("Type", typeof(string)));
dt.Columns.Add(new DataColumn("Price", typeof(Int32)));
dt.Columns.Add(new DataColumn("Qty", typeof(Int32)));
dt.Columns.Add(new DataColumn("Amount", typeof(Int32)));
dt.Columns.Add(new DataColumn("CatID", typeof(Int32)));
dt.Columns.Add(new DataColumn("Note", typeof(string)));
dt.Columns.Add(new DataColumn("Disc", typeof(bool)));
dt.Columns.Add(new DataColumn("Date", typeof(DateTime)));
for (int i = 0; i < 15; i++)
{
dr = dt.NewRow();
dr["ID"] = i;
dr["Name"] = "Product Name_" + i.ToString();
dr["Type"] = "Product Type " + (100 - i).ToString();
dr["Price"] = 123000 * (i + 1);
dr["Qty"] = (i + 1) * 20;
dr["Amount"] = 123000 * (i + 1) * (i + 1);
dr["CatID"] = 100 - i;
dr["Note"] = "Note_" + i.ToString();
dr["Disc"] = (i % 2 == 0) ? true : false;
dr["Date"] = DateTime.Now.AddDays(i);
dt.Rows.Add(dr);
}
return new DataView(dt);
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GridView1.DataSource = CreateDataSource();
GridView1.DataBind();
}
}
protected void GridView1_Sorting(object sender,
GridViewSortEventArgs e)
{
GridView gv = (GridView)sender;
DataView view = CreateDataSource();
string exp = e.SortExpression;
// 同じ LinkButton をクリックした場合 ASC / DESC を切り
// 替えるための処理。
// GridView の属性に CurrentSortField, CurrentSortDir
// を追加し、それに前回クリックされた LinkButton の
// SortExpression およびその時 ASC or DESC どちらだった
// かの情報を保持。
if (gv.Attributes["CurrentSortField"] != null &&
gv.Attributes["CurrentSortDir"] != null)
{
if (exp == gv.Attributes["CurrentSortField"])
{
if (gv.Attributes["CurrentSortDir"] == "ASC")
{
exp = exp + " DESC";
gv.Attributes["CurrentSortDir"] = "DESC";
}
else
{
exp = exp + " ASC";
gv.Attributes["CurrentSortDir"] = "ASC";
}
}
else
{
gv.Attributes["CurrentSortField"] = exp;
exp = exp + " ASC";
gv.Attributes["CurrentSortDir"] = "ASC";
}
}
view.Sort = exp;
gv.DataSource = view;
gv.DataBind();
}
}
.aspx ファイル
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="0055-GridViewSorting.aspx.cs"
Inherits="_0055_GridViewSorting" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView ID="GridView1" runat="server"
AllowSorting="True"
CurrentSortField=""
CurrentSortDir=""
onsorting="GridView1_Sorting">
</asp:GridView>
</form>
</body>
</html>
上のコードを見ると、自力で一行もコードを書く必要のない SqlDataSource を使う方が正解と思えます。何らかの理由で SqlDataSource を使えない場合でも、上に紹介した MSDN Forum の記事に書いてあるように ObjectDataSource を使うという手段もあります。