WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

w2ui Grid

by WebSurfer 2015年12月26日 16:17

w2ui が提供している JavaScript ライブラリに Grid という表を表示するための widget があります。訳あって ASP.NET Web Forms アプリでちょっと使ってみましたので、使い方を忘れないように書いておきます。

w2ui Grid

(注:先の記事 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 あたりだと使い物にならないレベルの遅さでした。古いブラウザでの使用は考えてないのかもしれませんね。

Tags:

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年12月  >>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar