w2ui が提供している JavaScript ライブラリに Grid という表を表示するための widget があります。訳あって ASP.NET Web Forms アプリでちょっと使ってみましたので、使い方を忘れないように書いておきます。
(注:先の記事 GridView のヘッダ、列を固定(その 2)でも Grid という名前の同様な JavaScript ライブラリを紹介していますが、それとは別物です)
今回使った w2ui ライブラリはこの記事を書いている時点での最新版 1.4.3 です。jQuery も必須でとりあえず今回は自分が持っていたバージョン 1.8.3 を使いました。
たぶん、SQL Server などのデータベースからデータを取得して Grid で表示する際、どうやって Grid にデータを渡すかというところが一番の課題になると思いますので、そこのところを書いておきます。(他は w2ui の記事を読めば分かると思いますので割愛。手抜きでスミマセン)
簡単に書くと、Grid Overview のページの Example 2 に書いてあるように url にリソースを指定しておくと、Grid が url に指定されたリソースを非同期要求するので、要求を受けたら Example 2 に書いてある形式の JSON 文字列を応答として返すようにしておけば、後は表示まで全部 Grid が面倒見てくれます。
url に指定するリソースは、同じドメインにあって(AJAX なのでドメインが異なるのは NG)指定された形式の JSON 文字列を返すことができれば、.aspx ページ、HTTP ハンドラ、Web サービス、WPF、MVC のアクションメソッド、Web API などを使用できます。
ただし、Grid が非同期要求する際、{
"cmd":"get-records", ...} というデータが application/x-www-form-urlencoded 形式に変換され(JSON 文字列でないことに注意)、フォームデータとして POST されてきますので、そのフォームデータを使ってサーバー側で何か処置を行う場合は JSON 文字列を受けることが前提の Web サービス、WPF は使い勝手が悪そうです。
ASP.NET Web Forms アプリなら .aspx ページまたは HTTP ハンドラを使うのが都合がよさそうです。なので、今回は HTTP ハンドラを使用する例を書きました。
HTTP ハンドラ
Microsoft が提供している SQL Server サンプルデータベース Northwind の Orders テーブル(14 フィールド x 830 レコード)から全レコードを取得し、指定された形式の JSON 文字列にシリアル化して応答として返します。
シリアル化の方法は MSDN ライブラリの方法 : JSON データをシリアル化および逆シリアル化するを参考にしました。
コード内のコメントにも書きましたが、DateTime 型は \/Date(836406000000+0900)\/ のようにシリアル化されます。(詳しくは MSDN ライブラリの記事「スタンドアロン JSON のシリアル化」の「高度な情報 / DateTime ワイヤ形式」のセクションの説明を見てください)
クライアント側で形式変換できなければ、サーバー側で適当な文字列に変換する必要があります。(Grid を使った場合、形式変換するコードを割り込ませる場所がなさそうです。今回のサンプルではそのままにしています)
<%@ WebHandler Language="C#"
Class="_0139_w2uiOrdersHandler" %>
using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Runtime.Serialization;
using System.Web.Configuration;
using System.Collections.Generic;
using System.Runtime.Serialization.Json;
public class _0139_w2uiOrdersHandler : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
GridData data = new GridData();
data.records = new List<Record>();
string connString = WebConfigurationManager.
ConnectionStrings["Northwind"].
ConnectionString;
string query = "SELECT [OrderID], [CustomerID]," +
"[EmployeeID], [OrderDate], [RequiredDate]," +
"[ShippedDate], [ShipVia], [Freight]," +
"[ShipName], [ShipAddress], [ShipCity]," +
"[ShipRegion], [ShipPostalCode], [shipCountry]" +
"FROM [Orders]";
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(query, conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
Record record = new Record();
record.OrderID = reader.GetInt32(0);
record.CustomerID = reader.IsDBNull(1) ?
null : reader.GetString(1);
record.EmployeeID = reader.IsDBNull(2) ?
null : (int?)reader.GetInt32(2);
record.OrderDate = reader.IsDBNull(3) ?
null : (DateTime?)reader.GetDateTime(3);
record.RequiredDate = reader.IsDBNull(4) ?
null : (DateTime?)reader.GetDateTime(4);
record.ShippedDate = reader.IsDBNull(5) ?
null : (DateTime?)reader.GetDateTime(5);
record.ShipVia = reader.IsDBNull(6) ?
null : (int?)reader.GetInt32(6);
record.Freight = reader.IsDBNull(7) ?
null : (decimal?)reader.GetDecimal(7);
record.ShipName = reader.IsDBNull(8) ?
null : reader.GetString(8);
record.ShipAddress = reader.IsDBNull(9) ?
null : reader.GetString(9);
record.ShipCity = reader.IsDBNull(10) ?
null : reader.GetString(10);
record.ShipRegion = reader.IsDBNull(11) ?
null : reader.GetString(11);
record.ShipPostalCode = reader.IsDBNull(12) ?
null : reader.GetString(12);
record.ShipCountry = reader.IsDBNull(13) ?
null : reader.GetString(13);
data.records.Add(record);
}
}
}
}
}
HttpResponse response = context.Response;
// キャッシュは無効にする
response.Cache.SetCacheability(HttpCacheability.NoCache);
response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));
response.ContentType = "application/json; charset=utf-8";
data.status = "success";
data.total = data.records.Count;
// JSON 文字列にシリアル化
DataContractJsonSerializer ser =
new DataContractJsonSerializer(typeof(GridData));
ser.WriteObject(response.OutputStream, data);
// DateTime 型は \/Date(836406000000+0900)\/ のように
// シリアル化される。
}
public bool IsReusable
{
get
{
return false;
}
}
}
[DataContract]
internal class GridData
{
[DataMember]
internal string status { get; set; }
[DataMember]
internal int total { get; set; }
[DataMember]
internal List<Record> records { get; set; }
}
[DataContract]
internal class Record
{
[DataMember]
internal int OrderID { get; set; }
[DataMember]
internal string CustomerID { get; set; }
[DataMember]
internal int? EmployeeID { get; set; }
[DataMember]
internal DateTime? OrderDate { get; set; }
[DataMember]
internal DateTime? RequiredDate { get; set; }
[DataMember]
internal DateTime? ShippedDate { get; set; }
[DataMember]
internal int? ShipVia { get; set; }
[DataMember]
internal decimal? Freight { get; set; }
[DataMember]
internal string ShipName { get; set; }
[DataMember]
internal string ShipAddress { get; set; }
[DataMember]
internal string ShipCity { get; set; }
[DataMember]
internal string ShipRegion { get; set; }
[DataMember]
internal string ShipPostalCode { get; set; }
[DataMember]
internal string ShipCountry { get; set; }
}
Grid を表示する .aspx ページ
上の HTTP ハンドラを以下のように url に設定すれば(以下のコードで 0139-w2uiOrdersHandler.ashx が上記の HTTP ハンドラ)、自動的に HTTP ハンドラに非同期呼び出しがかかって JSON 文字列が取得され、Grid にデータが表示されます。その結果が上の画像です。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<script src="/jquery.js" type="text/javascript"></script>
<script src="/w2ui.js" type="text/javascript"></script>
<link href="/w2ui.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
//<![CDATA[
$(function () {
$('#myGrid').w2grid({
name: 'myGrid',
url: '0139-w2uiOrdersHandler.ashx',
columns: [
{field:'OrderID',caption:'Order ID',size:'7%'},
{field:'CustomerID',caption:'Customer ID',size:'7%'},
{field:'EmployeeID',caption:'Employee ID',size:'7%'},
{field:'OrderDate',caption:'Order Date',size:'7%'},
{field:'RequiredDate',caption:'Required Date',size:'7%'},
{field:'ShippedDate',caption:'Shipped Date',size:'7%'},
{field:'ShipVia',caption:'Ship Via',size:'7%'},
{field:'Freight',caption:'Freight',size:'7%'},
{field:'ShipName',caption:'Ship Name',size:'7%'},
{field:'ShipAddress',caption:'Address',size:'7%'},
{field:'ShipCity',caption:'City',size:'7%'},
{field:'ShipRegion',caption:'Region',size:'7%'},
{field:'ShipPostalCode',caption:'Postal Code',size:'7%'},
{field:'ShipCountry',caption:'Country',size:'7%'}
]
});
});
//]]>
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="myGrid" style="height: 400px"></div>
</form>
</body>
</html>
上のサンプル(14 フィールド x 830 レコード)でスクロールすると、Chrome 最新版ならそれなりに動きますが、IE9 あたりだと使い物にならないレベルの遅さでした。古いブラウザでの使用は考えてないのかもしれませんね。