SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

ASP.NETによるインクリメンタルナビゲーションの実装

フレームワーク「Theseus」を使用したWebサイトへの実装手順

ダウンロード ソースコード (310.6 KB)

TheseusClassの詳細

 Theseusの動作をさらに理解してもらうために、TheseusClassのTreeViewコントロール(サイドメニュー)関連のコードを詳しく説明します。前述のとおり、SideMenu.ascxユーザーコントロールは、TreeViewコントロールを使ってサイドメニューを表示します。このコントロールのPage_Loadイベントハンドラは、要求されたページに必要なノードをTreeViewにロードするために、TheseusClassLoadSideMenuメソッドを呼び出します。このメソッドには、ユーザーコントロールのマークアップ部分で定義されているSiteMapDataSource(dsMenu3)とTreeViewコントロール(tvMenu3)の両方を渡します。

private TheseusClass Theseus;

protected void Page_Load(object sender, EventArgs e)
{ 
   Theseus = ((TheseusPage)Page).Theseus;
   Theseus.LoadSideMenu(dsMenu3, tvMenu3);
   // do dah
}

 LoadSideMenuメソッドは、まず、セクションメニューの選択ノードの参照を取得し、変数node2に代入します(サイドメニューは、セクションメニューから選択されたSiteMapNodeの下位ノードを表示することを思い出してください)。この選択されたセクションメニューのSiteMapNodeは、SiteMapExtensionクラスのCurrentBranchNodeメソッドにSectionMenuLevel変数を渡して呼び出すことによって取得します。SectionMenuLevel変数は、セクションメニューに表示された項目がサイトマップ階層内のどのレベルであるかを示す整数値です。このサンプルでは、この値は2に設定されていますが、TheseusClassのコンストラクタでカスタマイズできます。

public void LoadSideMenu(SiteMapDataSource dsMenu3, TreeView tv)
{ 
   // I get a reference to the Section Menu level node on the Current Branch
   // as this provides all the parameters I need to setup the Side Menu
   SiteMapNode node2 = SiteMapExtender.CurrentBranchNode(SectionMenuLevel);

   ...
}

 選択されたセクションメニューノードを取得したら、次はそのノードがnullかどうかを調べます。これは、選択されたサイトタブが葉ノードのとき、nullになります。例えば、要求されたページがホームページの場合、node2はnullになります。node2がnullでない場合は、サイドメニューのTreeViewコントロール(tvパラメータ)を表示し、適切な深さまで展開してnode2の下位ノードを表示します。

public void LoadSideMenu(SiteMapDataSource dsMenu3, TreeView tv)
{
   ...
   bool bVisible = false;

   // Always check the value returned by CurrentBranchNode for null!
   if (node2 != null)
   { 
      if (node2.HasChildNodes)
      {
         dsMenu3.StartingNodeUrl = node2.Url;
         tv.ExpandDepth = SiteMapExtender.CurrentNodeLevel;
         bVisible = true;
      }
   }
    
   // unless the Side Menu has nodes, hide it!
   tv.Visible = bVisible;
}

 SiteMapDataSourceコントロールdsMenu3StartingNodeUrlプロパティは、選択されたセクションメニューノードのURL(node2.Url)に設定します。SiteMapDataSourceのShowStartingNodeプロパティはユーザーコントロールのマークアップでfalseに設定されているので、node2の子ノードのみが返されます。

 TreeViewのExpandDepthプロパティは、既定で展開されるTreeViewノードのレベル数を示します。この値には、サイトマップ階層における現在のノードのレベル(SiteMapExtensionsクラスのCurrentNodeLevelプロパティで取得)を指定します。サイドメニューのロードに必要な作業はこれで全部です。ただし、サイドメニューの表示に必要な重要な作業が残っています。現在位置情報に基づいて、TreeViewの適切なノードを強調表示することです。

 TreeViewのノードの強調表示は、このコントロールにデータをバインドした後でなければできません。TreeViewにデータがバインドされると、TreeViewのDataBoundイベントが発生します。従って、DataBoundイベントにイベントハンドラを作成し、そこにTreeViewのノードを選択するコードを記述するのが適しています。このイベントハンドラは、SideMenu.ascxユーザーコントロールで定義しており、TheseusClassのSetNodeSideMenuメソッドにTreeViewコントロールを渡して呼び出すだけです。

protected void SideMenu_DataBound(object sender, EventArgs e)
{
   Theseus.SetNodeSideMenu((TreeView)sender);
}

 SetNodeSideMenuメソッドはまず、TreeViewの全ノードを閉じます。これは、現在位置情報に基づくノードのみが展開表示されるようにするためです。次に、TreeViewのノードが選択されているかを確認し、選択されている場合はそのノードを展開します。選択されていない場合は、SiteMap.CurrentNodeを表すTreeNodeが選択されます。最後に、選択ノードの親ノードを展開し、表示ページに選択ノードが表示されるようにします。

 SetNodeSideMenuメソッドは次のようになっています。

public void SetNodeSideMenu(TreeView tv)
{
   tv.CollapseAll();

   // If a node is already selected, expand it!
   if (tv.SelectedNode != null)
      tv.SelectedNode.Expand();
   else
      SetSelectedTreeNode(tv);

   // Now that I have my selected mode,
   // I expand the nodes along the Current Branch.
   // TreeView's Expanded property is set to true!
   ExpandSideMenu(tv);
}

 最も一般的なシナリオは、ノードが選択されていない場合です。この場合は、SetSelectedTreeNodeメソッドが呼び出されます。このSetSelectedTreeNodeメソッドは、SiteMapNodeオブジェクトSiteMap.CurrentNodeを表すTreeNodeを選択します。このコードの複雑なところは、SiteMap.CurrentNodeをTreeNodeの1つに割り当てる点です。TreeViewのFindNodeメソッドを使用することによって、現在のノードのValuePathを作成するだけでこれを実現できます。

private void SetSelectedTreeNode(TreeView tv)
{
   if (SiteMap.CurrentNode != null)
   {
      // As there is more than one potential level to search for the node I want,
      // I use the property CurrentNodeValuePath to calculate the ValuePath
      TreeNode curr = tv.FindNode(SiteMapExtender.CurrentNodeValuePath(SideMenuLevel));

      if (curr != null)
         curr.Select();
   }
}

 よく見ると、このコードは現在のノードを選択しているだけだと気付くでしょう。では、現在位置情報に連なる他のノードはどうやって太字表示にしているのでしょうか。実は、何もしなくてよいのです。CSS Friendly Adaptersを使用することによって、現在位置情報を表すノードすべてに、AspNet-TreeView-ChildSelectedというCSSクラスが指定されます。従って、C#コードを一切書かなくても、CSS定義でこのような表示指定を設定できます。詳細については、~/App_Themes/ws/SideMenu.cssファイル内のCSSを参照ください。

 CurrentNodeValuePathは、SiteMapExtenderオブジェクトのCurrentBranchプロパティから作成できるのでとても簡単です。これを行うコードは、SiteMapExtensionsクラスのCurrentNodeValuePathメソッドに含まれています。

public string CurrentNodeValuePath(int startFromLevel)
{
   string s = string.Empty;
   List<SiteMapNode> ln = CurrentBranch;

   if (ln.Count > 0)
   {
      for (int i = startFromLevel; i == CurrentNodeLevel; i++)
         s = s + ln[i].Title + "/";
   }

   return s;
}

 CurrentNodeValuePathのコードはとても単純で、気をつけねばならないのは、startFromLevelパラメータを正確に処理してValuePathを確実に正しい位置から計算することだけです。

 後はExpandSideMenuメソッドのコードだけです。このメソッドは、CurrentNodeから始めて、TreeNodeオブジェクトのParentプロパティを使用してそこからツリーをさかのぼり、それぞれの親ノードを展開していきます。

private void ExpandSideMenu(TreeView tv)
{ 
   TreeNode tn = tv.SelectedNode;
   if (tn != null)
   {
      while(tn.Parent != null)
      {
         tn.Parent.Expanded = true;
         tn = tn.Parent;
      }
   }
}

次のページ
まとめ

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Andrew Wrigley(Andrew Wrigley)

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/4175 2009/08/06 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー