.NET TIPS

[ASP.NET]データベースからツリー・メニューを作成するには?[2.0のみ、C#、VB]

山田 祥寛
2006/03/24

 「TIPS:[ASP.NET]Webフォーム上でサイト・メニュー/サイト・パスを作成するには?」では、ナビゲーション・コントロールを利用して、XML形式で記述されたサイトマップ・ファイルからツリー・メニューやリッチなメニュー、サイトマップ(パンくずリスト)を作成する方法について紹介した。

 しかし、ある程度大規模なサイトになれば、膨大なメニュー情報をXMLファイルで管理するよりも、データベース上でそのほかのコンテンツ情報と合わせて一元的に管理する方が便利なことが多い。そこで本稿では、TreeViewコントロールを利用して、データベース上で管理されたメニュー情報からツリー・メニューを生成する方法について紹介する。

 なお、本稿のサンプルを利用するには、データベース上に以下のようなsitemapテーブルを作成しておく必要がある。

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

 また、sitemapテーブルにはサンプル・データとして、以下の表のようなメニュー情報をあらかじめセットしておくものとする。

url title parent
aspnet.aspx 独習ASP.NET books.aspx
bbs.aspx Q&A掲示板 default.aspx
books.aspx 新刊書籍情報 default.aspx
conf.aspx サーバサイド環境構築設定 default.aspx
default.aspx ホーム -
e_aspnet.aspx ASP.NET conf.aspx
e_dotnet.aspx .NET Framework e_aspnet.aspx
e_iis.aspx IIS 5.0/6.0 e_aspnet.aspx
e_jsp.aspx JSP&サーブレット conf.aspx
e_php.aspx PHP conf.aspx
e_sql.aspx SQL Server 2005 e_aspnet.aspx
jsp.aspx 10日でおぼえるJSP&サーブレット入門教室 book.aspx
kisop.aspx 改訂新版 基礎PHP books.aspx
sitemapテーブルにセットするデータ(例)

 それではさっそく、具体的な構築の手順をVisual Studio 2005(以降、VS 2005)環境を前提に見ていくことにしよう。

1. TreeViewコントロールを配置する

 まずは、フォーム・デザイナからTreeViewコントロールを配置してみよう。TreeViewコントロールを利用するのに必要な主な操作は、TreeViewコントロールを配置すると(もしくは右上の三角マーク をクリックすると)表示される[TreeView タスク]メニューを選択することで行えるが、ここでは[オートフォーマット]を選択し、ツリー・ビューの外観だけを整えてみよう。いくつかデフォルトのフォーマットが用意されているが、ここでは「Windowsヘルプ」を選択しておく。

[オートフォーマット]ダイアログ
このダイアログは、TreeViewコントロールの[TreeView タスク]メニューから[オートフォーマット]を選択すると表示される。ここでは「Windowsヘルプ」を選択している。

 冒頭で示したTIPSのようにサイトマップ・ファイル(web.sitemap)を適用する場合には、[TreeView タスク]メニューの[データソースの選択]コンボボックスから[<新しいデータソース...>]を選択する。本稿ではデータベースからデータをバインドするので、ここでは特に何も行わない。

 これだけで、ツリー・メニューの外観にかかわる設定は完了だ。ここで参考までにVS 2005によって自動生成されたコードを引用しておく(ただし、<%--〜--%>は筆者コメント)。

<form id="form1" runat="server">
<div>
<asp:TreeView ID="tree" runat="server" ImageSet="WindowsHelp">
  <%--ツリーの各ノードに関するスタイルの定義--%>
  <ParentNodeStyle Font-Bold="False" />
  <HoverNodeStyle Font-Underline="True" ForeColor="#6666AA" />
  <SelectedNodeStyle BackColor="#B5B5B5" Font-Underline="False"
    HorizontalPadding="0px" VerticalPadding="0px" />
  <NodeStyle Font-Names="Tahoma" Font-Size="8pt" ForeColor="Black"
    HorizontalPadding="5px" NodeSpacing="0px" VerticalPadding="1px" />
</asp:TreeView>
</div>
</form>
VS 2005によって自動生成されたソース・コード(C#版:treeDb_cs.aspx/VB版:treeDb_vb.aspx)の抜粋

4. ツリーにデータをバインドする

 もっとも、これだけではただの抽象的なツリー・スタイルの定義にすぎないので、ページがロードされたタイミングで、データベースからあらかじめ用意しておいたメニュー情報を読み込み、TreeViewコントロールに展開する必要がある。

 以下に、その具体的なコードを見てみよう。なお、環境によって変動する可能性があるデータベース接続文字列を個々の.aspxファイルにハード・コーディングすることは好ましくない。ここではデータベース接続文字列は、構成ファイル(Web.config)上であらかじめ定義されているものとする(接続文字列の定義に関する詳細は、別稿「VS 2005で変革されたASP.NET、Windowsフォーム、ADO.NETを総覧」の「接続文字列は構成ファイルに」をご参照いただきたい)。

using System;
using System.Data;
using System.Data.Common;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class treeDb_cs : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    this.CreateNode("-", tree.Nodes);
  }

  // 指定されたURL(parent)を親ノードとするノード群をツリーに追加
  private void CreateNode(String parent, TreeNodeCollection nodes)
  {
    ConnectionStringSettings setting =
      ConfigurationManager.ConnectionStrings["db"];
    DbProviderFactory factory =
      DbProviderFactories.GetFactory(setting.ProviderName);

    using (DbConnection db = factory.CreateConnection()) {
      db.ConnectionString = setting.ConnectionString;

      // パラメータparentをキーにsitemapテーブルを検索
      // (parentで指定されたURLを親に持つコンテンツを抽出)
      DbCommand comm = factory.CreateCommand();
      comm.CommandText =
        "SELECT url,title FROM sitemap WHERE parent=@parent";
      comm.Connection = db;
      DbParameter param = factory.CreateParameter();
      param.ParameterName = "@parent";
      param.Value = parent;
      comm.Parameters.Add(param);
      db.Open();
      DbDataReader reader= comm.ExecuteReader();

      // 取得したコンテンツを新規ノードとしてツリーに追加
      // その際、そのコンテンツが最末端でない(子ノードを持つ)
      // 場合には、CreateNodeメソッドを再帰的に呼び出し、
      // 同様にノードの追加を行う
      while (reader.Read()) {
        TreeNode node = new TreeNode();
        node.NavigateUrl = reader.GetString(0);
        node.Text = reader.GetString(1);
        this.CreateNode(reader.GetString(0), node.ChildNodes);
        nodes.Add(node);
      }
    }
  }
}
Imports System.Data.Common

Partial Class treeDb_vb
  Inherits System.Web.UI.Page

  Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    Me.CreateNode("-", tree.Nodes)
  End Sub

  ' 指定されたURL(parent)を親ノードとするノード群をツリーに追加
  Private Sub CreateNode(ByVal parent As String, ByVal nodes As TreeNodeCollection)
    Dim setting As ConnectionStringSettings = _
        ConfigurationManager.ConnectionStrings("db")
    Dim factory As DbProviderFactory = _
        DbProviderFactories.GetFactory(setting.ProviderName)

    Using db As DbConnection = factory.CreateConnection()
      db.ConnectionString = setting.ConnectionString

      ' パラメータparentをキーにsitemapテーブルを検索
      ' (parentで指定されたURLを親に持つコンテンツを抽出)
      Dim comm As DbCommand = factory.CreateCommand()
      comm.CommandText = _
        "SELECT url,title FROM sitemap WHERE parent=@parent"
      comm.Connection = db
      Dim param As DbParameter = factory.CreateParameter()
      param.ParameterName = "@parent"
      param.Value = parent
      comm.Parameters.Add(param)
      db.Open()
      Dim reader As DbDataReader = comm.ExecuteReader()

      ' 取得したコンテンツを新規ノードとしてツリーに追加
      ' その際、そのコンテンツが最末端でない(子ノードを持つ)
      ' 場合には、CreateNodeメソッドを再帰的に呼び出し、
      ' 同様にノードの追加を行う
      Do While reader.Read()
        Dim node As New TreeNode()
        node.NavigateUrl = reader.GetString(0)
        node.Text = reader.GetString(1)
        Me.CreateNode(reader.GetString(0), node.ChildNodes)
        nodes.Add(node)
      Loop
    End Using
  End Sub
End Class
データベースから動的にツリー・メニューを生成するWebフォーム(上:treeDb_cs.aspx.cs/下:treeDb_vb.aspx.vb)

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

 本サンプル・プログラムでは、

ツリー最上位のノード(parentフィールドが“-”であるノード)を基点として、順に下位ノードの追加処理を行い、それぞれのノードについてさらに子ノードが存在する場合には該当するノードの追加処理を行う。そして、さらにその下位ノードが存在する場合には、孫ノードを追加する……

というように、再帰的な処理を最下位のノードまで繰り返すことで、ツリー・メニューを生成しているわけだ。これによって、ノード階層が必ずしも特定できない本稿のようなケースでも、これだけコンパクトなコードで処理を記述することができる。

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

 以上を理解したら、さっそく、サンプル・プログラムを実行してみよう。

サンプル・プログラム(treeDb_cs.aspx/treeDb_vb.aspx)の実行結果

 データベースに格納した内容に従って、このような結果を得られれば成功だ。End of Article

利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:Webフォーム 処理対象:ナビゲーション
使用ライブラリ:TreeViewコントロール(Microsoft.Web.UI.WebControls名前空間)
使用ライブラリ:TreeNodeCollectionクラス(Microsoft.Web.UI.WebControls名前空間)
関連TIPS:[ASP.NET]Webフォーム上でサイト・メニュー/サイト・パスを作成するには?

この記事と関連性の高い別の.NET TIPS
[ASP.NET]データベースからツリー・メニューを生成するには?
[ASP.NET]TreeViewコントロールで深階層のツリー情報を効率よく読み込むには?
[ASP.NET]データベースからリッチなメニューを作成するには?
[ASP.NET]TreeViewコントロールで深階層のツリー情報を効率よく読み込むには?
TreeViewコントロールで現在選択されているノードを変更するには?
TreeViewコントロールへ項目を追加するには?
TreeViewコントロールで効率的にツリーを構築するには?
[ASP.NET]フォルダ構造やドキュメントをツリー表示するには?
[ASP.NET]任意のXMLファイルからサイト・メニューを作成するには?
[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 記事ランキング

本日 月間