アーカイブ

Archive for 2013年6月

ASP.NET WebFormsとknockoutで自動的にテーブルを再表示する

久々にMSDNフォーラムを覗いたら、UpdatePanel + Timerでメモリーリークがどうのという話を見かけた。

Knockout + WCFでできるよと回答したものの、それだけだとちょっとあれなので、やり方を書いてみる。

プロジェクトはココからダウンロード出来ます。

プロジェクトにknockoutを組み込む

プロジェクトにknockout.jsが組み込まれていない場合は、パッケージマネージャーコンソールを開き、knockout.jsをインストールします。もしjQueryを使っていない場合は、ついでに組み込みます。

PM> Install-Package knockoutjs
PM> Install-Package jQuery

上記のコマンドを実行すると、プロジェクトにknockout-2.2.1.debug.jsとknockout-2.2.1.jsが追加されます。

image

Knockoutを参照する

マスターページなどに、先ほどインストールしたknockoutを参照します。(Site.Master)

<%@ Master Language="VB" AutoEventWireup="false" CodeBehind="Site.master.vb" Inherits="knockoutReload.Site" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/jquery-2.0.2.js")%>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/knockout-2.2.1.js") %>'></script>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

 

まずは静的にテーブルを表示する

WCFでデータを取得する前に、静的なページで表示できることを確認しておきましょう

今回は、knockoutのドキュメントページにあるサンプルをちょこっと変えて利用します。(WebForm1.aspx)

<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" CodeBehind="WebForm1.aspx.vb" Inherits="knockoutReload.WebForm1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
    $(function () {
        function AppViewModel() {
            var self = this;
            self.people = ko.observableArray([]);

            self.reflesh = function () {
                self.people.push({ firstName: 'Bert', lastName: 'Bertington' });
                self.people.push({ firstName: 'Charles', lastName: 'Charlesforth' });
                self.people.push({ firstName: 'Denise', lastName: 'Dentiste' });
            };
        }

        var viewModel = new AppViewModel();
        ko.applyBindings(viewModel);
        viewModel.reflesh();
    });    
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div>
<table>
    <thead>
        <tr><th>First name</th><th>Last name</th></tr>
    </thead>
    <tbody data-bind="foreach: people">
        <tr>
            <td data-bind="text: firstName"></td>
            <td data-bind="text: lastName"></td>
        </tr>
    </tbody>
</table>
</div>
</asp:Content>

とりあえず実行するとこうなります。

image

サーバー側のサービスを作る

次に、knockoutから呼び出されるサービスを作成します。別途WCFサービスを作成しても良いのですが、ページメソッドでも対応できるので、今回はこちらを利用します。

まずは、クライアントにデータを返却するためのエンティティークラスを定義します。(People.vb)

<Serializable()>
Public Class People
    Public Property firstName As String
    Public Property lastName As String
End Class

続いて、ページ内にWebMethodでマークした静的メソッドを追加します。(WebForm1.aspx.vb)

Imports System.Web.Services

Public Class WebForm1
    Inherits System.Web.UI.Page

    <WebMethod()>
    Public Shared Function ReleshTable() As List(Of People)
        Return New List(Of People) From {
            New People With {.firstName = "Bert", .lastName = "Bertington"},
            New People With {.firstName = "Charles", .lastName = "Charlesforth"},
            New People With {.firstName = "Denise", .lastName = "Dentiste"}
        }
    End Function
End Class

クライアントからサービスを呼び出す

ページ初期化時にサーバー側に定義したサービスを呼び出して、クライアントのテーブルにバインドするように変更します。ViewModelに定義したrefleshメソッドを次のように変更します。定期的に呼び出したいので最後にsetTimeoutの記述を追加指定ます。

self.reflesh = function () {
    $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        url: "WebForm1.aspx/ReleshTable",
        success: function (data) {
            self.people(data.d);
            setTimeout(self.reflesh, 5 * 1000);
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            alert(textStatus);
        }
    });
};

実行すると、先ほどと見た目は同じ結果が表示されますが、F12ツールで確認すると5秒毎に読み込んでいるのがわかります。

image

カテゴリー:ASP.NET, Javascript タグ: