WinForm TreeView学习小记(1)

简单看了下如何手工将XML文件中的数据填充到TreeView控件的操作,虽然整个过程比较简单,但还是很有必要记录一下。另外,这部分内容是通过手工填充的方式来完成数据和控件的绑定,也是将来利用数据源绑定数据的基础。


首先明确我们要解决的问题:XML文件中保存的数据存在很明显的树形结构,而这些数据用WinForm中的树控件来显示再合适不过,那么如何才能在控件中显示这些数据呢?

其次,还需要明确下我们的目标,我的想法是,

1. 指定XML文件,在树控件显示数据并保持它们的层级关系。

2. 右键单击树结点,弹出右键菜单,允许用户增加兄弟结点、子结点并允许删除结点(对兄弟结点、子结点这些名词感到陌生的话,建议先去熟悉下树的结构知识)


按照惯例,先上代码:

class CustomTreeView: TreeView
    {
//items of context menu strip
#region private enumberator
        private enum ItemsString
        {
            AddSibling=0,
            AddChild,
            Delete
            //AddAttribute
        }
#endregion

#region constructor
        public CustomTreeView()
        {
            //add items to context menu strip control attached to this control
            ContextMenuStrip cms = new ContextMenuStrip();

            foreach (String szItemsString in System.Enum.GetNames(typeof(ItemsString)))
            {
                cms.Items.Add(szItemsString);
            }
                     
            cms.Items[0].MouseDown+=new MouseEventHandler(AddSiblingNode);
            cms.Items[1].MouseDown += new MouseEventHandler(AddChildNode);
            cms.Items[2].MouseDown += new MouseEventHandler(DeleteNode);

            //set context menu strip
            ContextMenuStrip = cms;
        }
#endregion

#region public function
        /// <summary>
        /// load a xmlfile represented by a stream into a treeView
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public bool load(Stream stream)
        {
            if (stream == null) return false;
            try
            {
                XmlDocument document = new XmlDocument();
                document.Load(stream);

                XmlNode rootXmlNode = document.DocumentElement;
                TreeNode rootTreeNode = new TreeNode(rootXmlNode.Name);
                this.Nodes.Add(rootTreeNode);

                //we attach a xml file to a treeview control by recusively add xmlnode to treenode
                attachNode(rootTreeNode, rootXmlNode);
                this.ExpandAll();

                return true;
            }
            catch (System.Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }
#endregion

#region private function
        private void attachNode(TreeNode parentTreeNode, XmlNode parentXmlNode)
        {
            if (parentTreeNode == null || parentXmlNode == null)
                return;

            foreach (XmlNode childXmlNode in parentXmlNode.ChildNodes)
            {
                if (childXmlNode is XmlText)
                {
                    TreeNode childTreeNode = new TreeNode((childXmlNode as XmlText).InnerText);
                    parentTreeNode.Nodes.Add(childTreeNode);
                }
                else
                {
                    TreeNode childTreeNode = new TreeNode(childXmlNode.Name);
                    
                    //go through its attribute and generate attribute string
                    String szAttribute=" <";
                    int nCount = childXmlNode.Attributes.Count;
                    foreach (XmlAttribute attr in childXmlNode.Attributes)
                    {
                        szAttribute += attr.Name + " = " + attr.Value;
                        if (attr != childXmlNode.Attributes[nCount - 1])
                            szAttribute += ", ";
                    }
                    szAttribute += ">";

                    if (nCount == 0)
                        szAttribute = String.Empty;
                    childTreeNode.Text += szAttribute;

                    //append to the childnodes list of its parent
                    parentTreeNode.Nodes.Add(childTreeNode);
                    attachNode(childTreeNode, childXmlNode);
                }                
            }
        }

        // Summary:
        //     Represents the method that will handle the MouseDown, MouseUp, or MouseMove
        //     event of a form, control, or other component.
        //
        // Parameters:
        //   sender:
        //     The source of the event.
        //
        //   e:
        //     A System.Windows.Forms.MouseEventArgs that contains the event data.
        private void AddSiblingNode(object sender, MouseEventArgs e)
        {
            TreeNode parentNode = SelectedNode.Parent;
            if (parentNode == null)
            {
                return;
            }

            TreeNode nodeToInsert = new TreeNode();
            int nIndex = parentNode.Nodes.IndexOf(SelectedNode);
            parentNode.Nodes.Insert(nIndex + 1, nodeToInsert);

            SelectedNode = nodeToInsert;

            ContextMenuStrip.Hide();
            this.Invalidate();
        }

        // Summary:
        //     Represents the method that will handle the MouseDown, MouseUp, or MouseMove
        //     event of a form, control, or other component.
        //
        // Parameters:
        //   sender:
        //     The source of the event.
        //
        //   e:
        //     A System.Windows.Forms.MouseEventArgs that contains the event data.
        private void AddChildNode(object sender, MouseEventArgs e)
        {
            TreeNode childNode = new TreeNode();
            SelectedNode.Nodes.Add(childNode);

            SelectedNode = childNode;

            ContextMenuStrip.Hide();
            this.Invalidate();
        }

        private void deleteNodeAndItsDescendants(TreeNode node)
        {

        }

        // Summary:
        //     Represents the method that will handle the MouseDown, MouseUp, or MouseMove
        //     event of a form, control, or other component.
        //
        // Parameters:
        //   sender:
        //     The source of the event.
        //
        //   e:
        //     A System.Windows.Forms.MouseEventArgs that contains the event data.
        private void DeleteNode(object sender, MouseEventArgs e)
        {
            if(DialogResult.Yes==
                MessageBox.Show(this, "All descendants of this node will be deleted! Are you sure?", "Dangerous", MessageBoxButtons.YesNo))
            {
                this.BeginUpdate();

                TreeNode node = SelectedNode;
                if (node.Parent != null)
                    node.Parent.Nodes.Remove(node);
                else //root node
                    this.Nodes.Remove(node);

                this.EndUpdate();

                ContextMenuStrip.Hide();
            }
        }

#endregion

#region override function
        /// <summary>
        /// get a context menu strip when right-button is clicked, ans allow user to add sibling node and childnode
        /// </summary>
        /// <param name="e"></param>
        protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
        {
            base.OnNodeMouseClick(e);

            if (e.Button == MouseButtons.Right && e.Node!=null)
            {
                SelectedNode = e.Node;
                if (e.Node.Parent == null)
                    ContextMenuStrip.Items[(int)ItemsString.AddSibling].Visible = false;
                else
                    ContextMenuStrip.Items[(int)ItemsString.AddSibling].Visible = true;

                ContextMenuStrip.Show(e.Location);
            }
            //else //left button click
            //{
            //    e.Node.BeginEdit();
            //}
        }
#endregion
    }
在这里,我们定制了一个树控件,该控件派生自TreeView控件,并且完成了如下操作:

1. 在构造函数中添加了右键菜单,并订阅相应的点击事件

2. 订阅了树结点的鼠标右键点击事件处理函数,在该函数显示右键菜单供用户选择

3. 编写右键菜单的点击事件处理函数,包括增加子结点、兄弟结点以及删除结点功能,其中删除结点会将它所有的后代结点一并删除,因此在删除之前,弹窗确认。

4. 从流中加载XML文件,通过递归的方式,不断地往树中增加结点;另外,如果XML中的结点有属性,也会在树结点中以<name1=value1, name2=value2>的形式显示出来。

个人认为,整个代码还是很简单的,如果可能存在难度的地方,就是第4点中,递归地增加树结点的地方,可能需要有一点点递归的概念,在这里就不多做阐述。好了,关于TreeView的第一部分的内容就到此为止了,这部分主要是通过手工绑定的方式实现XML文件在树控件中的显示,可以看到,这种方法比较原始,需要自己去控件显示,另外,在生成整个树之后,显示的树结点和XML数据之间没有关系,对树结点所有的操作也不会被自动更新到后台的数据,如果用户希望能够动态地更新数据,需要自己来维护,因此使用起来还是不够方便,所以在下篇文章中,将继续介绍如何动态地使用绑定功能,实现数据和树控件之间的绑定,实现自动更新。另外,本文中的代码可以在这里下到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值