treeviewのノードにKeyはもてますか?

解決


はなこ  2007-06-13 05:05:14  No: 143634

treeviewのノードをClickしたらそのデータの明細を別Windowに表示させたいのですが、コードを保持しておくことはできるのでしょうか?
(treeviewにコードは表示させない。)

可能であればノードを選択したときのコードの取得方法も教えていただますでしょうか。

よろしくお願いします。


魔界の仮面弁士  2007-06-13 07:03:23  No: 143635

http://madia.world.coocan.jp/cgi-bin/vbnet/wwwlng.cgi?print+200706/07060012.txt

をご覧ください。
各ノードに、名称(Textプロパティ)だけでなく、
[コード]や[親コード]も保持させるサンプルとなっています。

> 可能であればノードを選択したときのコードの取得方法も教えていただますでしょうか。
選択されたノードは、SelectedNode プロパティから取得できます。


はなこ  2007-06-13 10:14:17  No: 143636

SelectedNode.textでtreeviewに表示されているデータは取得できるんですが、keyに当たるデータが取得できないんです。

何度も申し訳ありません。


KG  2007-06-13 17:58:51  No: 143637

NodeのNameプロパティから取得できると思うのですが。


はなこ  2007-06-13 22:30:14  No: 143638

Nameプロパティでは何も取得できなかったんですが?


魔界の仮面弁士  2007-06-13 23:22:32  No: 143639

> 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
の定義を変更すれば、他の項目も保持できるようになるわけで。


はなこ  2007-06-13 23:57:23  No: 143640

先日教えて頂いた方法でしているのですが、「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


魔界の仮面弁士  2007-06-14 01:11:20  No: 143641

> 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 だけで足りなくなれば、自分で新たな項目を追加することもできるわけです。
# 私のサンプルでは、追加情報として「コード」と「親コード」を持たせていますね。


魔界の仮面弁士  2007-06-14 01:51:53  No: 143642

> 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)


はなこ  2007-06-14 02:06:42  No: 143643

何度もすいません。m(_ _)m
いまいち訳がわからない状態になっています。

Dim node As NodeItem = DirectCast(TreeView1.SelectedNode, NodeItem)
は子ノードの情報を取得しようとするとエラーになります・・
親ノードだと取得はできるのですが・・・・


魔界の仮面弁士  2007-06-14 03:21:56  No: 143644

提示のサンプルを貼り付けて、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 なら、ノード未選択の時に取得しようとしたのが原因でしょうね。


はなこ  2007-06-14 03:30:48  No: 143645

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


魔界の仮面弁士  2007-06-14 05:27:18  No: 143646

本題とは無関係ですが、もしかして 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 プロパティも一緒に割り当てておけばよいわけです。


はなこ  2007-06-14 06:20:50  No: 143647

できました!

やっと少し理屈がわかってきたような気がします。
長い時間お手を取らせてすいませんでした。
ありがとうございました。


はなこ  2007-06-14 06:23:53  No: 143648

ADOの件もご指摘ありがとうございました。


※返信する前に利用規約をご確認ください。




  


  このエントリーをはてなブックマークに追加