none
TreeView(xml)で特定ノードの親ノードを展開 RRS feed

  • 質問

  • ツリーノードの属性を指定し、そのノードとその親にあたるノードを展開したく試行しています。
    ツリーのExpandDepthは"1"に設定してありdir0までを初期の表示としています。(dir1は数が多すぎるため)
    ノードdir1の属性であるidを指定し”1”、自分と親であるdir0”AA”のノードを展開したく、以下のようにコードを描きました。
    しかしコード実行してもdir0が展開されません。
    dir0のノードをクリックして展開した後にコードを実行するとdir1”id=1”のノードは展開してくれ、dir0は選択された状態になっています(選択すると色が変わる様に設定しています)。
    どのようにしたら指定ノードとその親ノードを展開できるでしょうか?
    説明不足かもしれませんがご指導よろしくお願いします。

     protected void Button1_Click(object sender, EventArgs e)
        {   前略   
      foreach (TreeNode node in TreeView1.Nodes[0].ChildNodes[0].ChildNodes)
       if (node.Value == "1") 
                  {
                      node.Selected = true;
                      TreeView1.SelectedNode.Expand();

                    TreeView1.SelectedNode.Parent.Selected = true;
                    TreeView1.SelectedNode.Expand();
    }

    xmlファイル(dir0のnameとdir1のidが一意となっています)
    <root>
     < dir0 name="AA" >
       < dir1 name="S" id="1" >
       < /dir1 >
       <dir1 name="T" id="2" >
       </dir1 >
     < /dir0>
     <dir0 name="BB" >
       < dir1 name="S" id="3" >
       < /dir1>
     < /dir0>
    </root>

    2012年1月17日 8:13

回答

  • > for (int i = 0; i < 2; i++) // 2はdir1のすべての数の値を入れる。

    dir1 の数が変わったらそのつど i < 2 の 2 を書き換えるようなことはし
    たくないですよね。代わりに、以下のようにしたらどうですか?

    i < TreeView1.Nodes[0].ChildNodes.Count

    それより foreach を使ったほうがスマートかも。

    また、見つかった後はループを回して探し続ける必要はないので break した
    らどうですか。

    以下のような感じです。

     

    bool found = false;
    foreach (TreeNode dir0 in TreeView1.Nodes[0].ChildNodes)
    {
        foreach (TreeNode dir1 in dir0.ChildNodes)
        {
            if (dir1.Value == id)
            {
                dir1.Expand();
                dir1.Select();
                dir0.Expand();
                found = true;
                break;
            }
        }
    
        if (found)
        {
            break;
        }
    }

    • 編集済み SurferOnWww 2012年1月23日 13:01 コードの誤記訂正
    • 回答としてマーク taka_toshi 2012年1月24日 1:21
    2012年1月23日 12:50

すべての返信

  • > しかしコード実行してもdir0が展開されません。
    変ですね、自分が試した限りでは展開されますけど?
    アップされてないコードの部分でどこか間違ってませんか。コードをアップす
    る時は、そのままコピペして試せるようにしてください。
    ちなみに、今回試したのは、前のスレッドでの Q&A で検証に使ったものを流用
    して、以下のようにしました。

    aspx ファイル

    <%@ 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">
        // 2012/1/17 MSDN フォーラムの検証用
        // http://social.msdn.microsoft.com/Forums/ja-JP/vwdexpressja/thread/123f304b-9cb6-4428-a569-1a23a894acfa
    
        protected void Button1_Click(object sender, EventArgs e)
        {
            foreach (TreeNode node in TreeView1.Nodes[0].ChildNodes[0].ChildNodes)
                if (node.Value == "S")
                {
                    node.Selected = true;
                    TreeView1.SelectedNode.Expand();
    
                    TreeView1.SelectedNode.Parent.Selected = true;
                    TreeView1.SelectedNode.Expand();
                }
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:XmlDataSource ID="XmlDataSource1" 
                runat="server" 
                DataFile="~/App_Data/XMLFile3.xml">
            </asp:XmlDataSource>
            <asp:TreeView ID="TreeView1" 
                runat="server" 
                DataSourceID="XmlDataSource1" 
                ExpandDepth="1">
                <DataBindings>
                    <asp:TreeNodeBinding 
                        DataMember="dir0" 
                        TextField="name" 
                        ValueField="id" />
                    <asp:TreeNodeBinding 
                        DataMember="dir1" 
                        TextField="name" 
                        ValueField="name" />
                    <asp:TreeNodeBinding 
                        DataMember="dir2" 
                        TextField="name" 
                        ValueField="name" />
                    <asp:TreeNodeBinding 
                        DataMember="file" 
                        TextField="name" 
                        ValueField="path" />
                </DataBindings>
            </asp:TreeView>
            <asp:Button ID="Button1" 
                runat="server" 
                Text="Expand" 
                onclick="Button1_Click" />
        </div>
        </form>
    </body>
    </html>
    


    XMLFile3.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <root>
        <dir0 name="AA" id="1" >
            <dir1 name="S" >
                <file name="image1.jpg" path="/photos/image1.jpg" />
                <file name="image2.jpg" path="/photos/image2.jpg" />
            </dir1 >
    
            <dir1 name="T" >
                <file name="image3.jpg" path="/photos/image3.jpg" />
                <file name="image4.jpg" path="/photos/image4.jpg" />
            </dir1 >
        </dir0>
    
    
        <dir0 name="BB" id="2" >
            <dir1 name="S" >
                <file name="image1.jpg" path="/photos/image1.jpg" />
                <file name="image2.jpg" path="/photos/image2.jpg" />
                <file name="image3.jpg" path="/photos/image3.jpg" />
                <file name="image4.jpg" path="/photos/image4.jpg" />
    
                <dir2 name="S-1" >
                    <file name="image5.jpg" path="/photos/image5.jpg" />
                </dir2>
                <dir2 name="S-2" >
                    <file name="image3.jpg" path="/photos/image3.jpg" />
                    <file name="image4.jpg" path="/photos/image4.jpg" />
                </dir2>
            </dir1 >
    
            <dir1 name="T" >
                <file name="image1.jpg" path="/photos/image1.jpg" />
                <file name="image2.jpg" path="/photos/image2.jpg" />
            </dir1 >
        </dir0>
    
    
        <dir0 name="CC" id="3" >
            <dir1 name="S" >
                <file name="image3.jpg" path="/photos/image3.jpg" />
            </dir1 >
    
            <dir1 name="T" >
                <file name="image4.jpg" path="/photos/image4.jpg" />
                <file name="image5.jpg" path="/photos/image5.jpg" />
            </dir1 >
        </dir0>
    </root>
    

    • 編集済み SurferOnWww 2012年1月18日 12:40 見栄え修正
    2012年1月18日 12:37
  • いつもありがとうございます。
    以前のもので検証していただきありがとうございます。
    只、今回は以前のものを少し修正したものとなっています。(xmlの属性idが一つ下の階層になっています)
    もう一度新たに作り直してみたところ、(xmlもdir1の展開がわかるようdir2を追加しています)
    id=1、2をnode.Valueに指定するとAAのnodeと指定したidのdir1のnodeが展開しました。
    しかし、id=3を指定すると、BBもdir1のnodeも展開しません。
    原因はどこにあるのでしょうか? 色々全体の事もお考えくださり恐縮です。恐れ入りますがよろしくお願いします。
    <%@ 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 Button1_Click(object sender, EventArgs e)
        {
            foreach (TreeNode node in TreeView1.Nodes[0].ChildNodes[0].ChildNodes)
                if (node.Value == "3") //dir1のidの値です。
                {
                    node.Selected = true;
                    TreeView1.SelectedNode.Expand();

                    TreeView1.SelectedNode.Parent.Selected = true;
                    TreeView1.SelectedNode.Expand();
                }
        }
    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
       
        </div>
        <asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1"
            ExpandDepth="1">
            <DataBindings>
                <asp:TreeNodeBinding DataMember="dir0" TextField="name" ValueField="name" />
                <asp:TreeNodeBinding DataMember="dir1" TextField="name" ValueField="id" />
                <asp:TreeNodeBinding DataMember="dir2" TextField="name" ValueField="name" />
            </DataBindings>
            <SelectedNodeStyle BackColor="Yellow" />
        </asp:TreeView>
        <asp:XmlDataSource ID="XmlDataSource1" runat="server"
            DataFile="~/App_Data/testxml.xml"></asp:XmlDataSource>
        <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
        </form>
    </body>
    </html>

    testxml.xml
    <root name="XX">
      <dir0 name="AA" >
        <dir1 name="S" id="1" >
            <dir2 name="S-1">      
            </dir2>
        </dir1 >
        <dir1 name="T" id="2" >
            <dir2 name="T-1">
            </dir2>
        </dir1 >
      </dir0>
      <dir0 name="BB" >
        <dir1 name="U" id="3" >
            <dir2 name="U-1">
            </dir2>
        </dir1>
      </dir0>
    </root>

    2012年1月19日 7:25
  • > しかし、id=3を指定すると、BBもdir1のnodeも展開しません。
    > 原因はどこにあるのでしょうか?

    foreach 文の TreeView1.Nodes[0].ChildNodes[0].ChildNodes は
    <dir0 name="AA"> ノードに含まれる子ノードのコレクションです。

    その意味は分りますか? つまり、

    TreeView1.Nodes[0] は <root name="XX">

    <root name="XX"> の ChildNodes[0] は <dir0 name="AA">

    <dir0 name="AA"> の ChildNodes は <dir1 name="S" id="1"> と
    <dir1 name="T" id="2"> のみです。

    なので、if 文の node.Value == "3" は false となって {  } の
    中のコードは実行されず、結果何も起きないという訳です。

    ちなみに、TreeView1.Nodes[0].ChildNodes[1].ChildNodes とする
    と node.Value == "3" で目的のノードが展開されると思います。
    でも、そうすると、"1" と "2" の場合がダメですが。


    一体何をしたいのですか? 局所的な問題だけでなく、全体が分る
    シナリオ的なことを少しは書いたほうが有益なアドバイスが得られ
    ると思いますよ。

    2012年1月19日 12:07
  • ありがとうございます。

    実はNodes[0]、ChildNodes[0]の意味がいまいち解りませんでした。

     dir1のidの値は別ページのGridViewで抽出したrow.Cells[1].Textの値を割り当てています。

    そしてTreeViewで,抽出されたidの値(=row.Cells[1].Textの値)のノードとその親ノードを展開したいと考えています。

    結論として、変数にあたるidの値でどのノードからも展開できることを考えていますが、無理でしょうか?

     GridViewからの値はTreeviewの方で以下のように受け取っています。ですのでこの後に今回のことができればと思っています。

    いつも済みませんがよろしくお願いします。

      protected void Button6_Click(object sender, EventArgs e)
        {
             String ww = Request.QueryString["Text"]; //wwがidの値となります。
            XDocument xdoc = XDocument.Load(MapPath("App_Data/testxml.xml"));
            var query = from xdir in xdoc.Descendants("dir1")
                        where (string)xdir.Attribute("id") == ww
                        select xdir;
            foreach (var xdir in query)
                Label5.Text = xdir.LastAttribute.Value; // 確認用


    2012年1月20日 2:04
  • > 実はNodes[0]、ChildNodes[0]の意味がいまいち解りませんでした。

    そのあたりのごく基本的なことが分かってないと話が通じないので、掲示
    板で解決するのは無理ですよ。この問題が解決しても、すぐ次の問題が出
    てきて、いつまで経っても終わらない・・・というようなことは前にも言
    いましたよね。そろそろ何とかしませんか?


    > 結論として、変数にあたるidの値でどのノードからも展開できることを
    > 考えていますが、無理でしょうか?

    id が xml ファイルの中で一意で、それが dir1 の TreeNode の Value
    に設定してあり、root - dir0 - dir1 という階層構造になっているとい
    う条件で、以下のようにすれば可能でしょう。

    (1) 指定した id の Value を持つ TreeNode を TreeView1 の中から検
    索する。木構造なので再帰を使えば簡単に検索できるでしょう。

    (2) 上記 (1) で検索できた TreeNode と、その Parent に Expand メ
    ソッドを実行する。

    たぶん (1) が問題でしょうが、少し勉強すれば分かると思います。

     


    • 編集済み SurferOnWww 2012年1月20日 13:46 誤字訂正
    2012年1月20日 13:45
  • 前言訂正します。

    今回の場合、dir1 だけ探せばよいし dir1 は深い位置にないので、再帰
    を使わなくても、foreach を入れ子にしたループで探して簡単にできそ
    うです。

    foreach を入れ子にしたループで目的の id の値を Value に持つ dir1
    を探す方法を検討してください。

    2012年1月21日 8:41
  • ありがとうございます。

    とりあえず以下のようにしてでき、うまく動いていると思うのですが、どこか間違っていましたらご指摘お願いします。

    if (TreeView1.Nodes.Count > 0)
                for (int i = 0; i < 2; i++) // 2はdir1のすべての数の値を入れる。
            foreach (TreeNode node in TreeView1.Nodes[0].ChildNodes[i].ChildNodes)
                if (node.Value == "3") // idの値。
                {
                    node.Selected = true;
                    TreeView1.SelectedNode.Expand();
                    node.Parent.Expand();

     


    2012年1月22日 23:47
  • > for (int i = 0; i < 2; i++) // 2はdir1のすべての数の値を入れる。

    dir1 の数が変わったらそのつど i < 2 の 2 を書き換えるようなことはし
    たくないですよね。代わりに、以下のようにしたらどうですか?

    i < TreeView1.Nodes[0].ChildNodes.Count

    それより foreach を使ったほうがスマートかも。

    また、見つかった後はループを回して探し続ける必要はないので break した
    らどうですか。

    以下のような感じです。

     

    bool found = false;
    foreach (TreeNode dir0 in TreeView1.Nodes[0].ChildNodes)
    {
        foreach (TreeNode dir1 in dir0.ChildNodes)
        {
            if (dir1.Value == id)
            {
                dir1.Expand();
                dir1.Select();
                dir0.Expand();
                found = true;
                break;
            }
        }
    
        if (found)
        {
            break;
        }
    }

    • 編集済み SurferOnWww 2012年1月23日 13:01 コードの誤記訂正
    • 回答としてマーク taka_toshi 2012年1月24日 1:21
    2012年1月23日 12:50
  • ありがとうございます。

    i < TreeView1.Nodes[0].ChildNodes.Count に直してみましたが無事に動きました。

    おっしゃるように書き換える必要がなくこちらの方が良いですね。

    foreachのほうも問題なく動作しました。

    Nodeの使い方、foreachのいれ子が判り勉強になりました。

    foundの役割がいまいち解りませんが勉強したいと思います。

    いつもお付き合いくださり感謝しております。

    本当にありがとうございました。

    *私の書いた for (int i = 0; i < 2; i++) // 2はdir1のすべての数の値を入れる。のdir1はdir0の間違いでした。あしからず。

    2012年1月24日 1:20