連載:VS 2005でいってみようDBプログラミング

第10回 実践アプリケーションで一歩踏み込むASP.NET 2.0の世界

山田 祥寛(http://www.wings.msn.to/
2006/11/29
Page1 Page2 Page3 Page4

[3]サーバ・コントロールを配置する

 新規作成したBbs.aspxをフォーム・デザイナで表示すると、マスタ・ページで定義された部分がグレーアウトした状態で、編集可能なコンテンツ部分のみがContentコントロールとして表示されていることが確認できるはずです。

 ここでは、Contentコントロールで定義された領域内に、図4の要領でサーバ・コントロールを配置します。


図4 Bbs.aspxのフォーム・レイアウト
  自動作成されるContentコントロール。
  TreeViewコントロール(tree)を配置。フォーマットは「ニュース」に設定。
  SqlDataSourceコントロール(sds)を配置。
  HyperLinkコントロール(lnkPrev)を配置。
  Literalコントロール(ltrSep)を配置。
  HyperLinkコントロール(lnkNext)を配置。

 また、配置したサーバ・コントロールに対しては、表4の要領でプロパティ情報を設定しておきましょう。

コントロール プロパティ 設定値
DOCUMENT Title 掲示板アプリ(スレッド一覧)
SqlDataSource ConnectionString myDb(第2回を参照)
DataSourceMode DataReader
SelectQuery SELECT [id], [subject], [nam], [deleted], [last_modified] FROM [Bbs] WHERE ([parent] = @parent) ORDER BY [last_modified] DESC
HyperLink
(lnkPrev)
Text <前ページへ
Visible False
Literal Text
Visible False
HyperLink
(lnkNext)
Text 次ページへ>
Visible False
表4 Bbs.aspxのプロパティ設定

 HyperLink/Literalコントロールは、それぞれ前後ページへのナビゲーション・リンクを作成するためのものです。デフォルトではVisibleプロパティをFalse(非表示)にしておき、前/次ページがある場合にのみプログラムから動的にTrue(表示)に切り替えるものとします。

 SqlDataSourceコントロールのSelectQueryプロパティを設定するためのクエリビルダの操作については、第5回の内容を参照してください。Bbsテーブル上の各フィールドをグリッド・ペインにドラッグ&ドロップし、絞り込み条件としてparent行の[フィルタ]列に対して「=@parent」と指定します。最終的に表4に示したようなSQL命令ができていればOKです。

[4]ページ・ロード時の処理を定義する

 以上でフォーム・デザイナ上の作業は完了です。次に、TreeViewコントロールが表示されたときに、データベース(Bbsテーブル)の内容をツリーに流し込むと同時に、最上位記事(親を持たない記事)が5件以上ある場合に[次ページへ]のリンクを作成するための処理をイベント・ハンドラに記述してみましょう。

 コード・エディタから以下のように記述してください。

<%@ Import Namespace="System.Data.Common" %>

……中略……

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)

   ' 現在のページ(pag)と最上位記事の表示開始位置(record)を初期化
  Dim pag As Integer = 1
  Dim record As Integer = 0

  ' クエリ情報「page」が空でない場合、
  ' 現在のページと表示開始位置をセット
  If Request.QueryString("page") IsNot Nothing And _
      Request.QueryString("page") <> "" Then
    pag = Int32.Parse(Request.QueryString("page"))
    record = (pag - 1) * 5
  End If

  ' TreeViewコントロールに記事情報を追加
  ' AddChildArticlesメソッドの戻り値は、残レコードが存在するかどうか
  Dim flag As Boolean = Me.AddChildArticles(0, tree.Nodes, record)

  ' 変数pagが1より大きい(2ページ目以降の)場合、
  ' [前ページへ]リンクを生成
  If pag > 1 Then
    lnkPrev.NavigateUrl = "Bbs.aspx?page=" & pag - 1
    lnkPrev.Visible = True
  End If

  ' 変数flagがTrueである(未読み込みのレコードが存在する)場合、
  ' [次ページへ]リンクを生成
  If flag Then
    lnkNext.NavigateUrl = "Bbs.aspx?page=" & pag + 1
    lnkNext.Visible = True
  End If

  ' [前ページへ][次ページへ]のリンクを出力時、
  ' 区切り文字も表示状態に
  If pag > 1 And flag Then ltrSep.Visible = True

End Sub

' 指定された記事コード(parent)を親記事とする子記事群を
' ツリー(nodes)に追加
' 引数recordはレコードの取得開始位置を指定(parent=0の場合のみ使用)
Protected Function AddChildArticles(ByVal parent As Integer, ByVal nodes As TreeNodeCollection, ByVal record As Integer) As Boolean

  Dim result As Boolean = False

  ' あらかじめ定義されたパラメータに引数parentの値をセット
  sds.SelectParameters.Clear()
  sds.SelectParameters.Add("parent", parent)
  Dim reader As DbDataReader = _
    sds.Select(DataSourceSelectArguments.Empty)

  ' 取得した記事情報を新規ノードとしてツリーに追加
  ' その際、その記事が最末端でない(子記事を持つ)場合には、
  ' AddChildArticlesメソッドを再帰的に呼び出し、
  ' 同様にノードの追加を行う
  Dim cnt As Integer = 0

  Do While reader.Read()
    ' 引数parentが0(最上位記事)の場合、カウント件数が
    ' 出力開始位置(record)以下である場合に表示をスキップし、
    ' 出力終了位置(record+4)を越えたタイミングでループを脱出
    ' (これによってrecord〜record+4件目の記事を出力)
    If parent = 0 Then
      If record + 4 < cnt Then
        result = True
        Exit Do
      End If
      cnt = cnt + 1
      If record >= cnt Then Continue Do
    End If

    ' deletedフィールド(削除済みか)がTrueである場合、
    ' 「削除済み」と出力
    ' それ以外の場合には個別記事表示画面(BbsShow.aspx)
    ' へのリンクを生成
    Dim node As New TreeNode()
    If reader("deleted") = True Then
      node.NavigateUrl = "Bbs.aspx"
      node.Text = "削除済み"
    Else
      node.NavigateUrl = "BbsShow.aspx?id=" & reader("id")
      node.Text = String.Format("{0}. {1} {2}({3:yyyy年MM月dd日 HH:mm:ss})", reader("id"), reader("subject"), reader("nam"), reader("last_modified"))
    End If

    Me.AddChildArticles(reader("id"), node.ChildNodes, False)
    nodes.Add(node)
  Loop
  Return result
End Function
リスト1 ページ・ロード時の処理を記述したコード(Bbs.aspx)

 データベースから読み込んだ情報をTreeViewコントロールに展開する方法については、第5回でも紹介していますので、詳細はこちらを参照してください。

 ここで注目していただきたいのは、TreeViewコントロールに対してページング機能を実装する方法です。ここでは、あくまで簡易的な方法として、Bbsテーブルから「parent=0」の条件を満たすレコード(最上位記事)を全件取得し、ツリー展開時にrecord 〜 record+4件目――すなわち、取得開始位置から5件のレコードのみを取り出す方法を取っています。

 また、クエリ情報page、AddChildArticlesメソッドの戻り値(次のレコードが残っているか)に基づいて、前後ページへのリンクの要否を判定し、HypertLink/Literalコントロールで構成されるナビゲーション・リンクの表示/非表示を切り替えています。

 この方法では、常にすべての最上位記事をデータベースから読み込むことになりますので、そのようなデータが大量になった場合に十分な性能が得られない可能性がありますが、小規模なアプリケーションであれば、さほど問題になることはないはずです。大量データのページングを扱う方法については、第12回にてあらためて紹介する予定です。


 INDEX
  Visual Studio 2005でいってみようDBプログラミング
  第10回 実践アプリケーションで一歩踏み込むASP.NET 2.0の世界
    1.スレッド一覧画面を作成する(1)
  2.スレッド一覧画面を作成する(2)
    3.個別記事表示/返信/投稿画面を作成する(1)
    4.個別記事表示/返信/投稿画面を作成する(2)
 
インデックス・ページヘ  「Visual Studio 2005でいってみようDBプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間