treeviewのノードをClickしたらそのデータの明細を別Windowに表示させたいのですが、コードを保持しておくことはできるのでしょうか?
(treeviewにコードは表示させない。)
可能であればノードを選択したときのコードの取得方法も教えていただますでしょうか。
よろしくお願いします。
http://madia.world.coocan.jp/cgi-bin/vbnet/wwwlng.cgi?print+200706/07060012.txt
をご覧ください。
各ノードに、名称(Textプロパティ)だけでなく、
[コード]や[親コード]も保持させるサンプルとなっています。
> 可能であればノードを選択したときのコードの取得方法も教えていただますでしょうか。
選択されたノードは、SelectedNode プロパティから取得できます。
SelectedNode.textでtreeviewに表示されているデータは取得できるんですが、keyに当たるデータが取得できないんです。
何度も申し訳ありません。
NodeのNameプロパティから取得できると思うのですが。
Nameプロパティでは何も取得できなかったんですが?
> Nameプロパティでは何も取得できなかったんですが?
それはつまり、
>> keyに当たるデータ
と書いておきながら、その Key を登録し忘れていた、という事なのでは。
Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
TreeView1.Nodes.Add("Key01", "キーつきノード1")
TreeView1.Nodes.Add("Key02", "キーつきノード2")
TreeView1.Nodes.Add("キー無しノード1")
TreeView1.Nodes.Add("キー無しノード2")
End Sub
Sub TreeView1_AfterSelect(ByVal sender As Object, ByVal e As TreeViewEventArgs) Handles TreeView1.AfterSelect
Label1.Text = "[" & e.Node.Name & "]"
Label2.Text = "[" & e.Node.Text & "]"
End Sub
>> treeviewに表示されているデータは取得できるんですが
いや、表示されていないデータも取得できるはずですよ。
先のサンプルを使っているのであれば、
Dim node As NodeItem = DirectCast(TreeView1.SelectedItem, NodeItem)
If node IsNot Nothing Then
Label1.Text = node.Code
Label2.Text = node.ParentCode
Label3.Text = node.Text
End If
という感じで、ノードの詳細情報を取れますし、また、
Public Class NodeItem
Inherits TreeNode
End Class
の定義を変更すれば、他の項目も保持できるようになるわけで。
先日教えて頂いた方法でしているのですが、「e.Node.Name」だと親のノードのkeyが取得できないです。(rootNodes.Add(item)でkeyを指定しようとするとエラーになります。)
Dim node As NodeItem = DirectCast(TreeView1.SelectedNode, NodeItem)
は子ノードの情報を取得しようとするとエラーになります・・
(SelectedItemというのはなかったのですが、SelectedNodeでいいんですよね?)
'親子関係を構築
Dim rootNodes As New List(Of NodeItem)()
For Each item As NodeItem In nodes.Values
If nodes.ContainsKey(item.ParentID) Then
nodes(item.ParentID).Nodes.Add(item.ProductID, item.Text)
Else
rootNodes.Add(item) ←ここでkey指定はできなかっです。
End If
Next
> SelectedNodeでいいんですよね?
そのとおりです。失礼しました。m(_ _)m
> ←ここでkey指定はできなかっです。
KG さんの発言から、Key の実態がノードの Name プロパティである、ということは既に理解されていますよね。
ということは、必ずしも Add メソッドの時点で Key を指定しなければならないわけでは無い、ということです。
Key を持つのは、あくまで「それぞれのノード」であり、ノードの Name プロパティを設定すれば、それが Key となるわけです。
Dim node As TreeNode
'-------
TreeView1.Nodes.Add("キー無しノード1")
node = New TreeNode()
node.Text = "キー無しノード2"
TreeView1.Nodes.Add(node)
node = New TreeNode("キー無しノード3")
TreeView1.Nodes.Add(node)
'-------
TreeView1.Nodes.Add("Key1", "キーつきノード1")
node = New TreeNode("キーつきノード2")
node.Name = "Key2"
TreeView1.Nodes.Add(node)
node = New TreeNode("キーつきノード3")
node.Name = "Key3"
TreeView1.Nodes.Add(node)
'-------
しかも、TreeNode は継承なクラスですから、ノードの機能を自分で拡張することさえもできます。
たとえば、登録すべき情報が Text や Name だけで足りなくなれば、自分で新たな項目を追加することもできるわけです。
# 私のサンプルでは、追加情報として「コード」と「親コード」を持たせていますね。
> TreeNode は継承なクラスですから
「継承可能なクラス」の間違いです。(;_;)
重ね重ね失礼しました。
> node = New TreeNode("キーつきノード2")
> node.Name = "Key2"
> TreeView1.Nodes.Add(node)
下記のようにも書けます。
node = New TreeNode()
node.Text= "キーつきノード2"
node.Name = "Key2"
TreeView1.Nodes.Add(node)
何度もすいません。m(_ _)m
いまいち訳がわからない状態になっています。
Dim node As NodeItem = DirectCast(TreeView1.SelectedNode, NodeItem)
は子ノードの情報を取得しようとするとエラーになります・・
親ノードだと取得はできるのですが・・・・
提示のサンプルを貼り付けて、AfterSelect イベントに
Dim node As NodeItem = DirectCast(e.Node, NodeItem)
Label1.Text = "Name=[" & node.Name & "]"
Label2.Text = "Text=[" & node.Text & "]"
Label3.Text = "親CD=[" & node.ParentCode & "]"
Label4.Text = "Code=[" & node.Code & "]"
と書いてみましたが、親子いずれのノードを選択しても、特にエラーにはなりませんでしたよ。
> エラーになります・・
どのようなエラーですか?
InvalidCastException なら、ノードの登録処理に問題があることになりますし、
NullReferenceException なら、ノード未選択の時に取得しようとしたのが原因でしょうね。
InvalidCastException です。子ノード選択時にエラーになります。
長くて申し訳ありません。実コーディングです。
Friend Class frmCreateProduct
'----------------------------------------------------------------
' (表示処理)
'----------------------------------------------------------------
Public Class NodeItem
Inherits TreeNode
Public ReadOnly Code As String
Public ReadOnly ProductID As String
Public ReadOnly ParentID As String
Public Sub New(ByVal row As DataRow)
MyClass.Text = row("名称").ToString()
Code = row("コード").ToString()
ProductID = row("ID").ToString()
ParentID = row("親ID").ToString()
End Sub
End Class
Private Sub 表示処理()
Dim dataTable1 As New DataTable
Try
str_sql = "select * from ProductCatM"
rs = cnn.Execute(str_sql)
If rs.EOF Then Exit Sub
rs.MoveFirst()
dataTable1.Columns.Add("コード")
dataTable1.Columns.Add("名称")
dataTable1.Columns.Add("ID")
dataTable1.Columns.Add("親ID")
Do Until rs.EOF
dataTable1.Rows.Add(rs.Fields("ProductCatCode").Value, rs.Fields("ProductCatName").Value, rs.Fields("ProductCatID").Value, rs.Fields("ParentCatID").Value)
rs.MoveNext()
Loop
rs.Close()
dataTable1.AcceptChanges()
'親子関係無しでノードを作成
Dim nodes As New Dictionary(Of String, NodeItem)()
For Each row As DataRow In dataTable1.Rows
Dim item As New NodeItem(row)
nodes.Add(item.ProductID, item)
Next
'親子関係を構築
Dim rootNodes As New List(Of NodeItem)()
For Each item As NodeItem In nodes.Values
If nodes.ContainsKey(item.ParentID) Then
nodes(item.ParentID).Nodes.Add(item.ProductID, item.Text)
Else
rootNodes.Add(item)
End If
Next
'画面に反映
trvProduct.Nodes.AddRange(rootNodes.ToArray())
Catch ex As Exception
MsgBox("「" & Err.Description & "」" & vbCrLf & "異常終了しました。管理者に連絡してください。", MsgBoxStyle.OkOnly)
Throw
Finally
End Try
End Sub
end class
本題とは無関係ですが、もしかして ADO を使用していますか?
もしそうなら、ActiveX 版では、COM オブジェクトの解放のために、逐次、
ReleaseComObject メソッドの呼び出しが必要とされますので、
http://support.microsoft.com/kb/321415/ja
PIA が使用されているかを確認しておいてください。
http://support.microsoft.com/kb/318559/ja
なお、ADO の Recordset を使っている場合には、
Dim da As New OleDb.OleDbDataAdapter()
da.Fill(dataTable1, rs)
のような構文を用いて、それを DataTable や DataSet に取り込むこともできます。
> InvalidCastException です。子ノード選択時にエラーになります。
ということは、つまり、
>> InvalidCastException なら、ノードの登録処理に問題があることになりますし、
という事になりますね。順に見ていきましょう。
まず最初に、
> Dim item As New NodeItem(row)
にて「拡張版ノード」である NodeItem クラスを生成していますよね。
そしてこの拡張版ノードは、「名称(Text)、コード(Code)、ID(ProductID)、親ID(ParentID)」の
4 つの情報を保持しています。ここまでは宜しいでしょうか。
ここで、はなこさんのコードを見てみますと、
> If nodes.ContainsKey(item.ParentID) Then
> nodes(item.ParentID).Nodes.Add(item.ProductID, item.Text)
> Else
> rootNodes.Add(item)
> End If
と書かれています。
これはつまり、親ノードの登録時には、
.Add(item)
で、『拡張版ノードそのもの』を登録しているにも関わらず、子ノードに対しては
.Add(item.ProductID, item.Text)
新たに Key(すなわちNameプロパティ) と Text だけを指定して、
新たに『標準版ノードを作成しなおしている』ということになります。
親ノードの実態は、「名称(Text)、コード(Code)、ID(ProductID)、親ID(ParentID)」を持った拡張版ノード(NodeItem)。
子ノードの実態は、「ID(Name) と 名称(Text)」しか持たない標準版ノード(TreeNode)という状況。
これでは、子ノードのキャストが失敗するのも当然ですよね。
-----
ということで:
TreeNode にノードを登録後、AfterSelect イベントや SelectedNode プロパティから得られる情報が、
(1) [ID]と[名称]だけで充分
(2) [ID]と[名称]だけでなく、[コード] [親ID] なども欲しい
のいずれかで、今後の方針が異なってきます。
(1) だというならば、今のように .Nodes.Add( "ID", "名称") で登録しておいて、
取得時には (DirectCast したりせずに)、TreeNode をそのまま使うだけで充分です。
キーである Name プロパティからは[ID]、Text プロパティからは[名称]を得られるでしょう。
(2) だというのであれば、.Nodes.Add( item ) で、拡張版ノードを登録しましょう。
ノードを DirectCast で型変換すれば、拡張したプロパティやフィールドも使えます。
さらに、TreeView1.Nodes.Find などにて、「キー検索」も行いたいのであれば、
NodeItem クラスの生成時に、
ProductID = row("ID").ToString()
MyClass.Name = ProductID
のように、Name プロパティも一緒に割り当てておけばよいわけです。
できました!
やっと少し理屈がわかってきたような気がします。
長い時間お手を取らせてすいませんでした。
ありがとうございました。
ADOの件もご指摘ありがとうございました。
ツイート | ![]() |