.NET TIPS

[ASP.NET]データベースからツリー・メニューを生成するには?

山田 祥寛
2005/04/08

 「TIPS:[ASP.NET]TreeViewコントロールでツリー・メニューを作成するには?」では、カスタム・コントロールであるTreeViewコントロールを利用して、XMLファイル(ツリー定義ファイル)からツリー・メニューを生成する方法について紹介した。

 しかし、ある程度大規模なサイトになれば、メニュー情報はコンテンツ管理と併せてデータベース上で行っているのが一般的だろう。その場合に、メニュー情報だけをわざわざXMLファイル(=ツリー定義ファイル)として管理する(この方法についての詳細は前掲のTIPSを参照)、もしくはデータベースと二重管理をしなければならないというのは、保守性/開発生産性いずれを取ってみてもうれしいことではない。

 そこで本稿では、TreeViewコントロールを利用して、データベース上で管理されたデータからツリー・メニューを生成する方法について紹介する。なお、本稿のサンプルを利用するには、あらかじめ前掲のTIPSの手順に従って、TreeViewコントロールをインストールしておく、また、データベース上に以下のようなsitemapテーブルを作成しておく必要がある。

フィールド名 データ型 概要
url VARCHAR(255) リンク先のURL(主キー)
title VARCHAR(50) タイトル
target VARCHAR(10) リンク時のターゲット
parent VARCHAR(255) 親ノードのURL(urlフィールドに対応。親ノードを持たない場合には“-”をセット)
sitemapテーブルのフィールド・レイアウト

 また、sitemapテーブルには、以下の表のようなデータをあらかじめセットアップしておくこと。

url title target parent
books.aspx 新着書籍情報 _blank -
bbs.aspx Q&A掲示板 _blank -
config.aspx サーバサイド環境構築 _blank -
sample.aspx JSP&サーブレットサンプル集 _blank books.aspx
xml.aspx 10日でおぼえるXML入門教室 _blank books.aspx
e_aspnet.aspx ASP.NET環境設定 _blank config.aspx
e_jsp.aspx JSP環境設定 _blank config.aspx
e_j2se.aspx J2SE _blank e_jsp.aspx
e_apache.aspx Apache _blank e_jsp.aspx
sitemapテーブルにセットするデータ(例)

 それでは、具体的なコードを見ていくことにしよう。

<%@ Page ContentType="text/html" Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Register TagPrefix="ie" Namespace="Microsoft.Web.UI.WebControls"
             Assembly="Microsoft.Web.UI.WebControls" %>
<script runat="Server">
void Page_Load(Object sender, EventArgs e){
  Boolean flag = SetNewNode("-", tree.Nodes);
}
// 指定されたURL(parent)を親ノードとするノード群をツリーに追加
Boolean SetNewNode(String parent, TreeNodeCollection nodes){
  // 変数flagは、配下に子ノードがあるかどうかを判定するフラグ
  Boolean flag = false;
  SqlConnection objDb = new SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet");
  // パラメータparentをキーにsitemapテーブルを検索
  // (parentで指定されたURLを親に持つコンテンツを抽出)
  SqlCommand objCom = new SqlCommand("SELECT url,title,target FROM sitemap WHERE parent=@parent", objDb);
  objCom.Parameters.Add("@parent", parent);
  objDb.Open();
  SqlDataReader objDr = objCom.ExecuteReader();
  // 取得したコンテンツを新規ノードとしてツリーに追加
  // その際、そのコンテンツが最末端でない(子ノードを持つ)場合には
  // SetNewNodeメソッドを再帰的に呼び出し、同様にノードの追加を行う
  while (objDr.Read()) {
    TreeNode node = new TreeNode();
    node.NavigateUrl = objDr.GetString(0);
    node.Text = objDr.GetString(1);
    node.Target = objDr.GetString(2);
    // SetNewNodeメソッドがtrueを返す場合、ノード型を“Folder”に、
    // falseである場合には“File”にそれぞれセット
    if (SetNewNode(objDr.GetString(0), node.Nodes)) {
      node.Type = "Folder";
    }else{
      node.Type = "File";
    }
    nodes.Add(node);
    flag = true;
  }
  objDb.Close();
  return flag;
}
</script>
<html>
<head>
<title>データベースからツリー・メニューを生成</title>
</head>
<body>
<form runat="Server">
<ie:TreeView id="tree" runat="Server"
  SystemImagesPath="/webctrl_client/1_0/treeimages/">
  <ie:TreeNodeType Type="Folder"
    ExpandedImageUrl="/webctrl_client/1_0/images/folderopen.gif"
    ImageUrl="/webctrl_client/1_0/images/folder.gif" />
  <ie:TreeNodeType Type="File"
    ImageUrl="/webctrl_client/1_0/images/html.gif" />
</ie:TreeView>
</form>
</body>
</html>
データベースから動的にツリー・メニューを生成するWebフォーム(C#版:treeview_db_cs.aspx)
 
<%@ Page ContentType="text/html" Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Register TagPrefix="ie" Namespace="Microsoft.Web.UI.WebControls"
             Assembly="Microsoft.Web.UI.WebControls" %>
<script runat="Server">
Sub Page_Load(sender As Object, e As EventArgs)
  Dim flag As Boolean = SetNewNode("-", tree.Nodes)
End Sub
' 指定されたURL(parent)を親ノードとするノード群をツリーに追加
Function SetNewNode(parent As String, nodes As TreeNodeCollection) As Boolean
  ' 変数flagは、配下に子ノードがあるかどうかを判定するフラグ
  Dim flag As Boolean=False
  Dim objDb As New SqlConnection("Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=dotnet")
  ' 仮引数parentをキーにsitemapテーブルを検索
  ' (parentで指定されたURLを親に持つコンテンツを抽出)
  Dim objCom As New SqlCommand("SELECT url,title,target FROM sitemap WHERE parent=@parent", objDb)
  objCom.Parameters.Add("@parent",parent)
  objDb.Open()
  Dim objDr As SqlDataReader = objCom.ExecuteReader()
  ' 取得したコンテンツを新規ノードとしてツリーに追加
  ' その際、そのコンテンツが最末端でない(子ノードを持つ)場合には
  ' SetNewNodeメソッドを再帰的に呼び出し、同様にノードの追加を行う
  Do While objDr.Read()
    Dim node As New TreeNode()
    node.NavigateUrl = objDr.GetString(0)
    node.Text = objDr.GetString(1)
    node.Target = objDr.GetString(2)
    ' SetNewNodeメソッドがtrueを返す場合、ノード型を“Folder”に、
    ' falseである場合には“File”にそれぞれセット
    If SetNewNode(objDr.GetString(0),node.Nodes) Then
      node.Type = "Folder"
    Else
      node.Type = "File"
    End If
    nodes.Add(node)
    flag = True
  Loop
  objDb.Close()
  Return flag
End Function
</script>
<html>
<head>
<title>データベースからツリー・メニューを生成</title>
</head>
<body>
<form runat="Server">
<ie:TreeView id="tree" runat="Server"
  SystemImagesPath="/webctrl_client/1_0/treeimages/">
  <ie:treenodetype Type="Folder"
    ExpandedImageUrl="/webctrl_client/1_0/images/folderopen.gif"
    ImageUrl="/webctrl_client/1_0/images/folder.gif" />
  <ie:TreeNodeType Type="File"
    ImageUrl="/webctrl_client/1_0/images/html.gif" />
</ie:TreeView>
</form>
</body>
</html>
データベースから動的にツリー・メニューを生成するWebフォーム(VB.NET版:treeview_db_vb.aspx)

 サンプルの細かなロジックについてはコード内のコメントを参照していただくとして、ここで注目していただきたいのは、再帰的に呼び出されるSetNewNodeメソッドだ。

 本サンプルでは、最上位のノード(parentフィールドが0であるノード)から順にツリーへの追加処理を行い、それぞれのノードについて子ノードが存在する場合には子ノードの追加処理を行う。そして、さらにその下位のノードが存在する場合には、孫ノードを追加する……というように、再帰的な処理を最下位のノードまで繰り返すことで、ツリー・メニューを生成しているわけだ。これによって、不特定数の階層を持つツリー情報についても、これだけコンパクトなコードで構築することができる。

 前掲のTIPSと比べると、TreeViewコントロールのTreeNodeSrc属性(ツリー定義ファイルとの関連付けの設定を行う)がなくなっていることが分かる。このコードでは、ツリー定義ファイルを利用する代わりに、ページがロードされるタイミングでSetNewNodeメソッドを呼び出してツリー・メニューを構築している。

 このSetNewNodeメソッドのパラメータには、TreeViewコントロール(treeオブジェクト)のNodesプロパティが指定されているが、このプロパティの値はTreeNodeCollectionクラス(Microsoft.Web.UI.WebControls名前空間)のオブジェクトだ。SetNewNodeメソッド内でこのTreeNodeCollectionオブジェクトのAddメソッドが呼び出されることで、メニュー・ツリーの項目が実際に追加されるようになっている。

 以上を理解したら、さっそく、サンプル・コードを実行してみよう。データベースに格納した内容に従って、以下のような結果を得られれば成功だ。

treeview_db_xx.aspxの実行結果

 なお、本稿ではTreeView、TreeNodeなどの各クラスの詳細については説明しない。各メソッド/プロパティに関する詳細を知りたいという方は「WebControls ASP .NET Object Reference」などを参照していただきたい。End of Article

カテゴリ:Webフォーム 処理対象:IE WebBrowserコントロール
使用ライブラリ:TreeViewコントロール(Microsoft.Web.UI.WebControls名前空間)
使用ライブラリ:TreeNodeCollectionクラス(Microsoft.Web.UI.WebControls名前空間)
関連TIPS:[ASP.NET]TreeViewコントロールでツリー・メニューを作成するには?
 
この記事と関連性の高い別の.NET TIPS
[ASP.NET]データベースからツリー・メニューを作成するには?
[ASP.NET]TreeViewコントロールで深階層のツリー情報を効率よく読み込むには?
TreeViewコントロールへ項目を追加するには?
[ASP.NET]TreeViewコントロールで深階層のツリー情報を効率よく読み込むには?
TreeViewコントロールで現在選択されているノードを変更するには?
TreeViewコントロールで効率的にツリーを構築するには?
[ASP.NET]フォルダ構造やドキュメントをツリー表示するには?
[ASP.NET]TreeViewコントロールでツリー・メニューを作成するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


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 記事ランキング

本日 月間