WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

TreeView の SelectedNodeStyle-ImageUrl

by WebSurfer 2014年10月20日 17:21

TreeView の SelectedNodeStyle-ImageUrl(正確には TreeView.SelectedNodeStyle プロパティで取得できる TreeNodeStyle オブジェクトの ImageUrl プロパティ)にイメージの URL を設定しても無視されます。

TreeView の SelectedNodeStyle-ImageUrl

例えば、上の画像のように、選択されたノード(上の画像の例では Topic 1.0.1)の左隣に表示される三角形は青、それ以外は白抜きの三角形にしたいとします。

その場合、NodeStyle-ImageUrl には白抜きの三角形、SelectedNodeStyle-ImageUrl に青の三角形のイメージを設定するとよさそうですが、実際にそのように設定して試すと SelectedNodeStyle-ImageUrl の方は無視されます(ノードを選択しても白抜きの三角形のまま変わりません)。

これは stackoverflow のページ およびそのページにあるリンク先に書いてあるようにバグのようです。ASP.NET 4.5 でも修正されていません。

では、どうすれば選択されたノードの左隣に表示されるイメージを、期待した通り上の画像のような青三角のイメージにできるかですが、その方法を以下に書きます。

サンプルとして、MSDN ライブラリの TreeView.SelectedNodeStyle プロパティ にあるコードに手を加えてみました。

まず、選択されてないノード用のイメージですが、各 TreeNodeStyle の ImageUrl プロパティに白抜き三角のイメージの URL を静的に設定します。

SelectedNodeStyle-ImageUrl は静的に設定しても無視されるので、TreeView の SelectedNodeChanged イベントのハンドラで SelectedNode の ImageUrl に青三角のイメージの URL を動的に設定します。

ただし、設定しっぱなしではノードの選択を変更した時に前に選択したノードのイメージが青三角のまま元に戻りません。ノードの選択が変更された場合は、前に選択されたノードのイメージを白抜き三角イメージの URL に書き戻すコードが必要になります。

そのため、選択したノードの ValuePath を ViewState に保持しておき、ノードの選択が変更になった場合は ViewState に保持したパス情報を元に前に選択されたノードを探し、その ImageUrl を書き換えます。その後、新たに選択されたノードの ValuePath を ViewState に保存します。

ちなみに、ValuePath はルートノードから選択されたノードまでの Value をつなげた文字列になります。例えば Topic 1.0.1 を選択した場合は "Table of Contents/Chapter One/Section 1.0/Topic 1.0.1" になります(サンプルコードでは Value プロパティを明示的に設定してないので Text プロパティの値が使用されます)。

修正後のコードは以下の通りです。実際に動かして試すことができるよう 実験室 にアップしましたので、興味がありましたら試してみてください。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    void Select_Change(Object sender, EventArgs e)
    {
        Message.Text = 
            "You selected: " + LinksTreeView.SelectedNode.Text;
        
        // これだけではダメ。イメージは元に戻らない。
        LinksTreeView.SelectedNode.ImageUrl = 
            "~/Images/right_selected.gif";

        // 前に選択されたノードのイメージを元に戻す。
        string valuePath = 
            (string)ViewState["TreeNodeValuePath"];
        
        if (!String.IsNullOrEmpty(valuePath))
        {
            LinksTreeView.FindNode(valuePath).ImageUrl = 
                "~/Images/right.gif";            
        }

        ViewState["TreeNodeValuePath"] = 
            LinksTreeView.SelectedNode.ValuePath;
    }
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head id="Head1" runat="server">
    <title>TreeView SelectedNodeStyle Example</title>    
</head>
<body>
    <form id="form1" runat="server">

    <h3>TreeView SelectedNodeStyle Example</h3>

    <asp:TreeView id="LinksTreeView"
        Font-Names= "Arial"
        ForeColor="Blue"
        SelectedNodeStyle-ForeColor="Green"
        SelectedNodeStyle-VerticalPadding="0"                
        OnSelectedNodeChanged="Select_Change"   
        runat="server">

        <LevelStyles>
            <asp:TreeNodeStyle ChildNodesPadding="10" 
                ImageUrl="~/Images/right.gif"
                Font-Bold="true" 
                Font-Size="12pt" 
                ForeColor="DarkGreen"/>
            <asp:TreeNodeStyle ChildNodesPadding="5" 
                ImageUrl="~/Images/right.gif"
                Font-Bold="true" 
                Font-Size="10pt"/>
            <asp:TreeNodeStyle ChildNodesPadding="5" 
                ImageUrl="~/Images/right.gif"
                Font-UnderLine="true" 
                Font-Size="10pt"/>
            <asp:TreeNodeStyle ChildNodesPadding="10" 
                ImageUrl="~/Images/right.gif"
                Font-Size="8pt"/>
        </LevelStyles>

        <Nodes>
            <asp:TreeNode Text="Table of Contents" 
                SelectAction="None">
                <asp:TreeNode Text="Chapter One">
                    <asp:TreeNode Text="Section 1.0">
                        <asp:TreeNode Text="Topic 1.0.1" />
                        <asp:TreeNode Text="Topic 1.0.2" />
                        <asp:TreeNode Text="Topic 1.0.3" />
                    </asp:TreeNode>

                    <asp:TreeNode Text="Section 1.1">
                        <asp:TreeNode Text="Topic 1.1.1"/>
                        <asp:TreeNode Text="Topic 1.1.2" />
                        <asp:TreeNode Text="Topic 1.1.3" />
                        <asp:TreeNode Text="Topic 1.1.4" />
                    </asp:TreeNode>
                </asp:TreeNode>

                <asp:TreeNode Text="Chapter Two">
                    <asp:TreeNode Text="Section 2.0">
                        <asp:TreeNode Text="Topic 2.0.1" />
                        <asp:TreeNode Text="Topic 2.0.2" />
                    </asp:TreeNode>
                </asp:TreeNode>
            </asp:TreeNode>
            <asp:TreeNode Text="Appendix A" />
            <asp:TreeNode Text="Appendix B" />
            <asp:TreeNode Text="Appendix C" />
        </Nodes>
    </asp:TreeView>

    <br /><br />

    <asp:Label id="Message" runat="server"/>

    </form>
</body>
</html>

Tags: ,

ASP.NET

TreeView.SelectedNode のサーバー側での特定

by WebSurfer 2011年11月13日 19:12

TreeView のノードをクリックするとポストバックが起こり、サーバー側で TreeView.SelectedNode プロパティでクリックされた TreeNode を取得できます。

TreeView の Node の選択

上の画像は、book というノードをクリックし、book ノードに含まれる子ノードの内 title ノードを取得してその Value を表示したものです。

そのコードは下に示したサンプルのとおりです。データとして使用している XML ファイルは MSDN ライブラリの チュートリアル : TreeView コントロールでの階層データの表示 のものです。

しかしながら、このコードでは、どの book ノードをクリックしても、表示されるのは一番上の book ノード下の title ノードの Value になってしまいます。

何故でしょう? 理由は以下の通りです。

どのノードがクリックさ���たかのサーバー側での判定は、root からクリックされたノードまでの Value をつなげた文字列を javascript:__doPostBack 関数の引数に設定し、ポストバックされた際にそれを取得して識別しています。

下のサンプルコードの例では、book ノードのハイパーリンクとして a 要素の href 属性に以下のように設定されます。

href="javascript:__doPostBack('TreeView1','sbookstore\\genre\\book')"

book ノードの Value はどれも同じ book ですので、__doPostBack 関数の引数はどの book ノードでも同じになってしまいます。それゆえサーバー側ではどの book がクリックされたか特定できません。だから、最初に該当する一番上の book が選択されたと判定してしまうようです。

解決策は、book ノードの Value が一意になるように TreeView の DataBindings に以下のように設定してやることです。

<asp:TreeNodeBinding DataMember="book"
    TextField="#Name" 
    ValueField="ISBN" />

考えてみれば、Windows アプリとは違って、ブラウザの画面に表示されているノードはインスタンスを指していないので、当たり前ですね。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  protected void TreeView1_SelectedNodeChanged(
    object sender, EventArgs e)
  {
    TreeNode selectedNode = TreeView1.SelectedNode;

    if (selectedNode.Text == "book")
    {
      foreach (TreeNode child in selectedNode.ChildNodes)
      {
        if (child.Text == "title")
        {
          Label1.Text = 
            "選択した本のタイトル: " + child.Value;
          break;
        }
      }
    }
    else
    {
      Label1.Text = String.Empty;
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title></title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:TreeView ID="TreeView1" 
      runat="server" 
      DataSourceID="XmlDataSource1"
      OnSelectedNodeChanged="TreeView1_SelectedNodeChanged">
      <DataBindings>
        <asp:TreeNodeBinding DataMember="title" 
            TextField="#Name" 
            ValueField="#InnerText" />
      </DataBindings>
    </asp:TreeView>
    <asp:XmlDataSource ID="XmlDataSource1" 
      runat="server" 
      DataFile="~/App_Data/Bookstore.xml">
    </asp:XmlDataSource>
    <br />
    <br />
    <asp:Label ID="Label1" runat="server">
    </asp:Label>
  </div>
  </form>
</body>
</html>

Tags: ,

ASP.NET

TreeView のノードの上下スペーシング

by WebSurfer 2011年10月30日 15:16

TreeView に表示されるノードの上下のスペーシングを調整するにはどうすればいいでしょうか。

TreeView のノード間のスペーシングを調整

子ノードを親ノードに接続する線を表示しない(TreeView.ShowLines プロパティが false)なら NodeStyle-NodeSpacing か NodeStyle-VerticalPadding で設定可能です。

しかし、接続線を表示する場合はそれではうまくいきません。

下の画像は、NodeStyle-VerticalPadding を 10px に設定した TreeView を表示している IE9 とその開発者ツールです(重ねて表示しています)。

NodeStyle-VerticalPadding を 10px に設定

NodeStyle-VerticalPadding を 10px に設定したことにより、td 要素の上下の padding が 10px に設定されてスペーシングは広がったものの、接続線の画像がデフォルトのままなので、線がつながっていません。

線がつながるようにするには、接続線の画像のサイズを大きくする必要があります。(というより、NodeStyle-NodeSpacing や NodeStyle-VerticalPadding は使わないで、画像のサイズだけでスペーシングを調整するようにします。)

接続線の画像は、デフォルトでは TreeView コントロールの埋め込みリソースから 19 x 20 サイズの GIF ファイルがダウンロードされるようになっていますが、以下の手順で変更可能です。

  1. デザイン画面で TreeView の > 印をクリック。
  2. 「TreeView タスク」メニューが表示されるので、[線のイメージのカスタマイズ ...]をクリック。
  3. 「ASP.NET TreeView ラインイメージジェネレーター」ダイアログが表示されるので、Height を指定する(デフォルトは 20)。必要なら、幅も Width の設定で変えられます(デフォルトは 19)。
  4. TreeLineImages フォルダ(存在しなければ自動生成される)の中に、上記 3 で指定したサイズの接続線の GIF イメージファイルが自動的に生成され、配置される(既存の画像ファイルがあれば置き換えられる)。

下の画像は、上記の手順で Height x Width を 40 x 40 に設定して自動生成した接続線の GIF イメージの一部です。

40 x 40 に設定して自動生成した接続線の GIF イメージ

TreeView.LineImagesFolder プロパティに上記 4 の TreeLineImages フォルダを設定し(自動的に設定されます)、上記 3 で画像の幅(Width)を変更していたら TreeView.NodeIndent をそれに合わせて調整します。

でも、これだけではまだ一部で線がつながりません(これはデフォルトの時でも同じです)。下の画像を見てください。

一部で線がつながりません

上の画像が示すように、TreeView.NodeIndent プロパティで設定した幅のインデントを設けるため、td 要素の中に div 要素が配置されています。その場所に接続線がある場合は、その div 要素の中に img 要素を配置して接続線の GIF イメージを表示します。

この例では、NodeIndent="40" としたので div 要素の style 属性で width: 40px; となっています。しかし、height は常に 1px になります。

インデントだけなら height が 1px でも問題ありませんが、接続線を表示する場合は 1px ではダメです。

その問題を解決するには、以下のようなスタイルを定義して、TreeView.CssClass に設定してやります。その結果が一番上の画像です。

<style type="text/css">
    .treeview table td div
    {
        height: 100% !important;
    }    
</style>

Tags: ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar