- PR -

TreeViewの追加方法について教えて下さいA

投稿者投稿内容
Kimi
会議室デビュー日: 2008/10/03
投稿数: 7
投稿日時: 2008-10-03 18:25
※※※同じ件名で、書き込み途中で送付してしまいました。大変申し訳ありません。
※※※こちらのスレッドでお願い致します。

ASP.NETで開発を始めてまだ1ケ月半程の新人です。
問合せの内容に落ち度があったらご指摘下さい。

VS2005、SQLserver2005の環境で、現在社内在庫管理のプログラムを作成しています。

今までメニュー項目の表示をMENUオブジェクトで行っていたのですが、品種の多様化でメニュー項目が多くなり見づらくなってきたので、TreeViewに変更しようとしています。
TreeViewの構成はなんとか理解できたのですが、やり方が悪いのか、どうもうまくいきません。
現在、以下のように作り込みをしたのですが、子ノードの再帰(?@の箇所です)処理で時間が掛かり、タイムアウトになってしまいます。
入力ファイルはsaitemapを使用せず、自分で作成したテーブル(SQLserverです)から読込んで項目にセットしようとしています。


Private Sub CreateNode(ByVal nodes As TreeNodeCollection)
COMM = "SELECT * FROM t_zaiko WHERE hinshu = 'XXXXX' AND hinmoku = 'YYYYY'"
Using connect As New SqlConnection(DBConStr)
Dim SQLcom As New SqlCommand(COMM, connect)
Try
connect.Open()
COMMR = SQLcom.ExecuteReader
While COMMR.Read = True
Dim node As New TreeNode()
node.NavigateUrl = COMMR("url")
node.Text = COMMR("title")
node.Value = COMMR("url")
@ Me.CreateNode(COMMR("url"), node.ChildNodes) <===ここで時間が掛かっています
nodes.Add(node)
End While
Catch ex As Exception
End Try
connect.Close()
End Using
End Sub


この@の行を外すと、全てのデータが親ノードの形で作成されてしまいます(子ノードとしたいデータが子にならず、親になってしまいます)。

※1:「nodes.Add」は親ノードを追加する命令は分かったのですが、子ノードの追加命令が分かりません。。。
※2:また、ネット上の@ITさんの解説で、親ノードと子ノードの関連を親プログラム名(parents)で行うようにあったのですが、この関連付けが良く理解できていません。
一応テーブルには親プログラム名(parents)列を持ったのですが、この項目を何処に渡せばよいのかが分かりません。

初歩的な質問で申し訳ありませんが、どなたかお分かりになる方がいらしたら、ご教授をお願い致します。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2008-10-03 20:39
引用:

Kimiさんの書き込み (2008-10-03 18:25) より:

「nodes.Add」は親ノードを追加する命令は分かったのですが、子ノードの追加命令が分かりません。。。


Nodes.Add が親ノードという感覚だと気付けないのかもしれません。 親ノードであろうと子ノードであろうと同じ TreeNode クラスです。 TreeNode クラスは自分自身と同じ型 (= TreeNode クラス) のコレクションを実装しています (それが Nodes コレクション)。 そのため TreeNode はメモリが許す限り木構造を取ることができます。 つまり '子ノードの' Nodes コレクションから Add メソッドを呼び出せばその子ノードにぶら下がります。

引用:

※2:また、ネット上の@ITさんの解説で、親ノードと子ノードの関連を親プログラム名(parents)で行うようにあったのですが、この関連付けが良く理解できていません。


親プログラム名? よくわかりませんが、子から Parent を設定する必要はないと思いますね。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
Kimi
会議室デビュー日: 2008/10/03
投稿数: 7
投稿日時: 2008-10-03 23:42
じゃんぬねっとさん

親ノードや子ノードの捕らえ方が誤っていたのはすごく勉強になりました。ありがとうございました。

>つまり '子ノードの' Nodes コレクションから Add メソッドを呼び出せばその子ノードにぶら下がります。

この辺りのイメージが私としてはまだすぐに理解できない(ピンとこないような)レベルです。
色々と試してみます。。。
Kimi
会議室デビュー日: 2008/10/03
投稿数: 7
投稿日時: 2008-10-04 02:08
何度もすいません。
色々と試してみたのですが、やはりうまく出来ず悩んでいます。


以下のようなデータを2件作成し、試してみました。

・データ

url |no|title |
------+--+--------+
a.aspx|0 |ねじ
b.aspx|1 |5mm*10mm

・期待する結果

■ねじ
└5mm*10mm


上記データで下記を実行しますと、

■ねじ
└ねじ
 └ねじ
  └ねじ
   :
  100行程このようになり
   :
  最後に
    └5mm*10mm

となってしまいます。


Private Sub CreateNode(ByVal nodes As TreeNodeCollection)
COMM = "SELECT * FROM t_zaiko "
Using connect As New SqlConnection(DBConStr)
  Dim SQLcom As New SqlCommand(COMM, connect)
  Try
  connect.Open()
  COMMR = SQLcom.ExecuteReader
  While COMMR.Read = True
    Dim node As New TreeNode()
    node.NavigateUrl = COMMR("url")
    node.Text = COMMR("title")
    node.Value = COMMR("url")
  @ Me.CreateNode(COMMR("url"), node.ChildNodes)
    nodes.Add(node)
  End While
  connect.Close()
End Using
End Sub


上記@を止めると、

■ねじ

■5mm*10mm

となり、TreeViewの形になりません。


私のレベルではもうお手上げです。
どなたか助けて頂けませんでしょうか。。。

ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-10-04 15:25
コード:

url |no|title |
------+--+--------+
a.aspx|0 |ねじ
b.aspx|1 |5mm*10mm



これ、「どの親」にぶら下がる、という情報が無いけどこんなんで大丈夫なの?
仮に No がインデントだとして、0,1,0,2 というデータが来たとき、2 が入る
べき親が無いでしょう?どーするんですか?

コード:

表示したいツリー構造 インデント   通し番号  親ノード
□ネジ        0        100
 ▲5mm      0?0      101  100
 ▲10mm     0?1      102  100
 ▲15mm     0?2      103  100
□逆ネジ       1        104
 ▲5mm      1?0      105  104
 ▲10mm     1?1      106  104
 ▲15mm     1?2      107  104
□ナット       2        108
 □普通のナット   2?1      109  108
  ▲5mm       1?0    110  109
  ▲10mm      1?1    111  109
  ▲15mm      1?2    112  109
 □袋ナット     2?2      113  108
  ▲5mm       2?0    114  113
  ▲10mm      2?1    115  113
  ▲15mm      2?2    116  113
□ワッシャ      3        117
 □スプリング    3?1      118  117
 □サラ       3?2      119  117

親ノードを持ってないノードがルートです。

これをSQLで書くと
親:select * from TreeTable where 親ノード='' order by 通し番号

  親ノード数分ループする。

子:select * from TreeTable where 親ノード=親[x] order by 通し番号

  子のノード数分ループする。


子の子(つまり、子の親だから これも親)...select が失敗するまで続ける
ということはつまり、ネストの最深部まで辿る、ということ。

2つのSQL文の違いを良く見ると、
親ノード=''

親ノード=親[x]
だけですね。
ってことは、右辺を再帰メソッドのパラメータとして渡してあげれば2つのループを
共通化できますね。




で、SELECT が失敗するということは、これ以上子が無いということなので
この部分に関して再帰処理を行うことで解決できそうですね。

コード:


//ダミーの親ノードを確保このノードの子全てがツリービューに表示される
//項目となる。
private root as new TreeNode()

private sub CreateTree(parent as TreeNode, nodeId as Integer)
//SQL 初期化処理
// select * from TreeTable where 親ノード=:nodeId order by 通し番号
//
while reader.read = true

//親ノード作成
dim node as new TreeNode()
//親ノード初期化

//今作成した親ノードに対して子を追加する
CreateTree(node, reader("親ノード") )

parent.add( node )

wend

end sub

protected sub Page_Load(...)

CreateTree( root, "" ) //最上位階層のノードは "" だから

for i as integer = 0 to root.items.count - 1

Me.TreeView1.controls.add( root.items(i) )

end

end sub





あとは適当にがんばってくだされ。

こんだけ書けば十分でしょう。


[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2008-10-04 15:38 ]

[ メッセージ編集済み 編集者: ぴあちゃん 編集日時 2008-10-04 15:48 ]
Kimi
会議室デビュー日: 2008/10/03
投稿数: 7
投稿日時: 2008-10-04 16:11
ぴあちゃんさん

ご丁寧な説明、コードのご提供をありがとうございました。
ご説明頂いた内容は大変分かり易く、何度か修正・トライし出来る事ができました。

今まで出来なかった根本的な原因は
1)親ノードの管理が無かったこと
2)再帰的処理の考え方がそもそも誤っていたこと
  @ Me.CreateNode(COMMR("url"), node.ChildNodes)
  で、親ノードをキーにレコードを読み直すとの認識がなありませんでした。

たいへん感激しており、本当に感謝致します。助かりました。
ありがとうございました。
ぴあちゃん
ぬし
会議室デビュー日: 2008/02/07
投稿数: 287
投稿日時: 2008-10-04 16:41
ずいぶん速いレスですね。。。試されました??というか試された?

これ、速度出ませんよ。
せいぜい1000件くらいの表示が限界かと考えます。


1万件とか10万件とかいうレベルだと子を持つ親だけ先読みしておくとか
工夫が必要になります。

件数が多い場合は、TreeNode オブジェクトによるツリー構造だけではなくて

TreeMap にルートノードだけ先読みしておき、ノードがクリックされたらその
ノードに対して動的子ノードを追加する、などと何でも動的にやったらいいの
かな、たぶん。

こうすれば再帰の必要が無くなりますからね。


Kimi
会議室デビュー日: 2008/10/03
投稿数: 7
投稿日時: 2008-10-04 17:24
ぴあちゃんさん

>ずいぶん速いレスですね。。。試されました??というか試された?

はい、やりました。
まずはTreeView形式で表示できるようにするのが先決だと思い、テストテーブルをつくり、テストデータ5件(親ノード1件でそれにぶらさがるデータ4件)で実行してできました。

ぴあちゃんさんの仰るとおりで、本番データは約28万件程あり、親−子−孫と、全体で5レベル(?)位になりますので、これからテーブルを作り直す必要があります(^o^!!!

今は(先程のお礼の返信後)この5レベルのテストデータを作っており、20件位でTree形式に出来るかをテストしようとしていた所です。。。

> 1万件とか10万件とかいうレベルだと子を持つ親だけ先読みしておくとか
> 工夫が必要になります。

また、新たなアドバイスをありがとうございました。
プログラムを作る事は今回初めてのド素人で、先輩から渡されたプログラムを参考にしながらですので、このような所まで気が回らないと言いますか、眼中にありませんでした。
まだまだ先は長いですね(笑)

あまりにも初歩的な質問で、ぴあちゃんさんを初め、皆様にはご迷惑をお掛けしました。
またスレッドを書き込んだ時はお願い致します。

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

スキルアップ/キャリアアップ(JOB@IT)