C# 实现 treeView 控件 拖拽效果

时间:2024-02-18 09:52:22

引言

  近日,在工作中遇到 treeView控件 要只是 展开或收起节点实在是太单调了,如果能像window那样的拖动效果就好了,于是乎就开始折腾如何让他能实现拖拽的效果......

正文

  都说万事开头难, (就像我现在思考怎么写...#^.^#),  一开始我就在表的设计上难住了,在数据库中怎样去保存  动态 拖拽的 树节点呢???

  思考中...........................

  继续思考.......................

  在不看我下面的实现方法之前,有兴趣可以思考一下哦。

  您有想法了吗?

  我的实现方式是:设计了两个字段就OK了,一个NodeId,parentId,为了能够看得出效果,我附加了一个 Title 树节点的标题,

  NodeId不用讲( PRIMARY KEY AUTOINCREMENT)  parentId用来保存 拖动节点 所在的 父级节点NodeId 即可,似乎有些绕,举例:比如不管我怎么拖动节点a,节点a肯定会位于某个节点(就叫节点b 吧)之下,只要用节点a 的parentId保存  节点b 的NodeId即可。

 

数据库                                                       

 

  当然要是您有更好的实现方式,可以请留言,共同学习。

  在实现拖动效果前,需要知道treeView控件的一个属性和三个事件

 属性:

  1.AllowDrop  是否允许控件拖放操作,是为 true;否则为 false。默认为 false。(一定要设置为true啊~)

 事件:

  1. ItemDrag事件(当用户开始拖动节点时发生。)
  2. DragEnter事件(在将对象拖入控件的边界时发生。)
  3. DragDrop事件(在完成拖放操作时发生。)

  好了,了解这些之后我们就可以开始码代码了~

初始化数据库
 1  public void IniTable()
 2         {
 3             try
 4             {
 5                 MessageBox.Show(ComPath);
 6                 //如果不存在数据库文件,则创建该数据库文件  
 7                 if (!System.IO.File.Exists(ComPath))
 8                 {
 9                     SQLiteDBHelper.CreateDB(ComPath);
10                     SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
11                    string sql = "CREATE TABLE TTree(NodeId integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,Title  varchar(50),parentId varchar(20) )   ";
12                   //sql += "  CREATE TABLE TContent (NodeId integer NOT NULL,Title varchar(50) )";
13                db.ExecuteNonQuery(sql, null);
14                      }
15                 
16             }
17             catch (Exception)
18             {
19                 
20                 throw;
21             }
22             
23         }

 

注:数据库使用的sqllite,  有一个问题一直没有弄明白,是不是sqllite不支持  sql  = "creat table a(...)  creat table b(...)";

 string sql = "CREATE TABLE TTree(NodeId integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,Title  varchar(50),parentId varchar(20) )   ";
          sql += "  CREATE TABLE TContent (NodeId integer NOT NULL,Title varchar(50) )";
         db.ExecuteNonQuery(sql, null);

这样的语句,会报一个  create附近有错误 ,中间加了一个  go  还是 会报  go附近错误??!!不得解~

 

 

加载树
 1 #region 加载树
 2         public void IniTreeView()
 3         {
 4             treeView1.Nodes.Clear();
 5             //添加根节点
 6 
 7             string strSQL;
 8             strSQL = "select * from TTree where parentId = 0";
 9             SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
10             DataTable dt = db.ExecuteDataTable(strSQL,null);
11 
12             if (dt.Rows.Count > 0)
13             {
14                 DataView tmpDV = new DataView(dt);
15                 if (tmpDV.Count > 0)
16                 {
17                     foreach (DataRowView myView in tmpDV)
18                     {
19                         string strTreeNode = myView["Title"].ToString().Trim();
20                         TreeNode tmp = new TreeNode(strTreeNode, 0, 1);
21                         tmp.Tag = myView["NodeId"];
22                         treeView1.Nodes.Add(tmp);
23                         treeView1.SelectedNode = tmp;
24                         ChildTreeView(tmp, myView);  //递归填充树子节点
25                     }
26                 }
27             }
28         }
29 
30         private void ChildTreeView(TreeNode ParentNode, DataRowView ParentRow)
31         {
32             
33             string strNode;
34             string sParentNode = ParentRow["NodeId"].ToString().Trim();
35             SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
36             string strSQL = "select * from TTree where parentId=" + Convert.ToInt32(ParentRow["NodeId"]);
37             DataTable dtTree = db.ExecuteDataTable(strSQL,null);
38             if (dtTree.Rows.Count > 0)
39             {
40                 DataView tmpDV = new DataView(dtTree);
41                 foreach (DataRowView myRow in tmpDV)
42                 {
43                     strNode = myRow["Title"].ToString().Trim();
44                     TreeNode myNode = new TreeNode(strNode, 0, 1);
45                     myNode.StateImageIndex = 1;
46                     myNode.Tag = myRow["NodeId"];
47                     ParentNode.Nodes.Add(myNode);
48                     ChildTreeView(myNode, myRow);
49 
50                 }
51             }
52         }

 

 

  下面就是实现树节点拖拽的效果了,也就用到文章开头我提到的三个事件了;

  

  在拖拽时要注意的是:1.目标节点不能为空。2.目标节点不能被拖拽节点本身。3.目标节点不能是被拖拽节点的子节点。

 

拖拽效果 
 1         Point Position = new Point(0, 0);
 2         //当用户开始拖动节点时发生
 3         private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
 4         {
 5             DoDragDrop(e.Item, DragDropEffects.Move);
 6         }
 7 
 8         //在将对象拖入控件的边界时发生
 9         private void treeView1_DragEnter(object sender, DragEventArgs e)
10         {
11             //判断拖动的是否为树节点
12             if (e.Data.GetDataPresent(typeof(TreeNode)))
13                 e.Effect = DragDropEffects.Move;
14             else
15                 e.Effect = DragDropEffects.None;
16         }
17 
18         //在完成拖放操作时发生
19         private void treeView1_DragDrop(object sender, DragEventArgs e)
20         {
21             string Moveid = "", Dropid = "";
22 
23 
24             TreeNode myNode = null;
25             if (e.Data.GetDataPresent(typeof(TreeNode)))
26             {
27                 //获得移动节点
28                 myNode = (TreeNode)(e.Data.GetData(typeof(TreeNode)));
29                 //获得移动节点的NodeId
30                 Moveid = (string)myNode.Tag.ToString();
31 
32             }
33             else
34             {
35                 MessageBox.Show("error");
36             }
37 
38             //将树节点的位置计算成工作区坐标。
39             Position.X = e.X;
40             Position.Y = e.Y;
41             Position = treeView1.PointToClient(Position);
42 
43             //检索目标节点
44             TreeNode DropNode = this.treeView1.GetNodeAt(Position);
45             // 1.目标节点不是空。2.目标节点不是被拖拽接点的子节点。3.目标节点不是被拖拽节点本身
46             if (DropNode != null && DropNode.Parent != myNode && DropNode != myNode)
47             {
48                 //临时节点
49                 TreeNode tempNode = myNode;
50                 // 将被拖拽节点从原来位置删除。
51                 myNode.Remove();
52                 // 在目标节点下增加被拖拽节点
53                 DropNode.Nodes.Add(tempNode);
54                 //目标节点的NodeId值
55                 Dropid = (string)DropNode.Tag.ToString();
56 
57                 //数据库中更新移动节点的parentID
58                 string strSQL;
59                 strSQL = " update TTree set parentId =" + Dropid + "   where  NodeId = " + Moveid + "  ";
60                 SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
61                 int i = db.ExecuteNonQuery(strSQL,null);
62                 if (i < 0)
63                 {
64                     MessageBox.Show("请正确拖动文件");
65                 }
66 
67 
68             }
69             // 如果目标节点不存在,即拖拽的位置不存在节点,那么就将被拖拽节点放在根节点之下
70             if (DropNode == null)
71             {
72                 //parentId = 0  表示根节点
73                 string strSQL;
74                 strSQL = " update TTree set parentId = 0   where  NodeId = " + Moveid + "  ";
75                 SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
76                 int i = db.ExecuteNonQuery(strSQL, null);
77 
78                 TreeNode DragNode = myNode;
79                 myNode.Remove();
80                 treeView1.Nodes.Add(DragNode);
81             }
82         }

 

 结语:

   到目前为止基本的拖拽效果已经实现了,但还是 没有 达到windows资源管理器拖拽时能显示节点缩略图的效果,

对此暂时没有思路了.....似乎网上有说用Win32 API实现,还没有细研究,也不知道是什么东西~

 待闲下来时再去研究研究~当然这就是后话了~

 

全部代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 using FileManager;
 10 
 11 
 12 namespace DropTree
 13 {
 14     public partial class Form1 : Form
 15     {
 16 
 17         string ComPath = System.IO.Directory.GetCurrentDirectory() + "\\Test.db";
 18         public Form1()
 19         {
 20             InitializeComponent();
 21             this.Load+=new EventHandler(Form1_Load);
 22             //如果控件允许拖放操作,则为 true;否则为 false。默认为 false。
 23             treeView1.AllowDrop = true;
 24             treeView1.ItemDrag += new ItemDragEventHandler(treeView1_ItemDrag);
 25             treeView1.DragEnter += new DragEventHandler(treeView1_DragEnter);
 26             treeView1.DragDrop += new DragEventHandler(treeView1_DragDrop);
 27         }
 28 
 29         private void Form1_Load(object sender, EventArgs e)
 30         {
 31             IniTable();
 32             IniTreeView();
 33             //展开所有节点
 34             this.treeView1.ExpandAll();
 35             treeView1.SelectedNode = null;
 36         }
 37         //  在拖拽时要注意的是:1.目标节点不能为空。2.目标节点不能被拖拽节点本身。3.目标节点不能是被拖拽节点的子节点。
 38         //1.ItemDrag事件(当用户开始拖动节点时发生。)2.DragEnter事件(在将对象拖入控件的边界时发生。)3.DragDrop事件(在完成拖放操作时发生。)
 39 
 40         #region   初始化数据库
 41         public void IniTable()
 42         {
 43             try
 44             {
 45                 MessageBox.Show(ComPath);
 46                 //如果不存在数据库文件,则创建该数据库文件  
 47                 if (!System.IO.File.Exists(ComPath))
 48                 {
 49                     SQLiteDBHelper.CreateDB(ComPath);
 50                     SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
 51                     string sql = "CREATE TABLE TTree(NodeId integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,Title  varchar(50),parentId varchar(20),CreateTime datetime,UpdateTime Date )   ";
 52                     //sql += "  CREATE TABLE TContent (NodeId integer NOT NULL,Title varchar(50),Type varchar(50),Size varchar(50),Time time,CreateTime datetime,UpdateTime datetime, Content blob)";
 53                     db.ExecuteNonQuery(sql, null);
 54                 }
 55                 
 56             }
 57             catch (Exception)
 58             {
 59                 
 60                 throw;
 61             }
 62             
 63 
 64         }
 65 
 66         #endregion
 67 
 68         #region 加载树
 69         public void IniTreeView()
 70         {
 71             treeView1.Nodes.Clear();
 72             //添加根节点
 73 
 74             string strSQL;
 75             strSQL = "select * from TTree where parentId = 0";
 76             SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
 77             DataTable dt = db.ExecuteDataTable(strSQL,null);
 78 
 79             if (dt.Rows.Count > 0)
 80             {
 81                 DataView tmpDV = new DataView(dt);
 82                 if (tmpDV.Count > 0)
 83                 {
 84                     foreach (DataRowView myView in tmpDV)
 85                     {
 86                         string strTreeNode = myView["Title"].ToString().Trim();
 87                         TreeNode tmp = new TreeNode(strTreeNode, 0, 1);
 88                         tmp.Tag = myView["NodeId"];
 89                         treeView1.Nodes.Add(tmp);
 90                         treeView1.SelectedNode = tmp;
 91                         ChildTreeView(tmp, myView);  //递归填充树子节点
 92                     }
 93                 }
 94             }
 95         }
 96 
 97         private void ChildTreeView(TreeNode ParentNode, DataRowView ParentRow)
 98         {
 99             
100             string strNode;
101             string sParentNode = ParentRow["NodeId"].ToString().Trim();
102             SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
103             string strSQL = "select * from TTree where parentId=" + Convert.ToInt32(ParentRow["NodeId"]);
104             DataTable dtTree = db.ExecuteDataTable(strSQL,null);
105             if (dtTree.Rows.Count > 0)
106             {
107                 DataView tmpDV = new DataView(dtTree);
108                 foreach (DataRowView myRow in tmpDV)
109                 {
110                     strNode = myRow["Title"].ToString().Trim();
111                     TreeNode myNode = new TreeNode(strNode, 0, 1);
112                     myNode.StateImageIndex = 1;
113                     myNode.Tag = myRow["NodeId"];
114                     ParentNode.Nodes.Add(myNode);
115                     ChildTreeView(myNode, myRow);
116 
117                 }
118             }
119         }
120         #endregion
121 
122         #region  树节点拖动效果
123         Point Position = new Point(0, 0);
124         //当用户开始拖动节点时发生
125         private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
126         {
127             DoDragDrop(e.Item, DragDropEffects.Move);
128         }
129 
130         //在将对象拖入控件的边界时发生
131         private void treeView1_DragEnter(object sender, DragEventArgs e)
132         {
133             //判断拖动的是否为树节点
134             if (e.Data.GetDataPresent(typeof(TreeNode)))
135                 e.Effect = DragDropEffects.Move;
136             else
137                 e.Effect = DragDropEffects.None;
138         }
139 
140         //在完成拖放操作时发生
141         private void treeView1_DragDrop(object sender, DragEventArgs e)
142         {
143             string Moveid = "", Dropid = "";
144 
145 
146             TreeNode myNode = null;
147             if (e.Data.GetDataPresent(typeof(TreeNode)))
148             {
149                 //获得移动节点
150                 myNode = (TreeNode)(e.Data.GetData(typeof(TreeNode)));
151                 //获得移动节点的NodeId
152                 Moveid = (string)myNode.Tag.ToString();
153 
154             }
155             else
156             {
157                 MessageBox.Show("error");
158             }
159 
160             //将树节点的位置计算成工作区坐标。
161             Position.X = e.X;
162             Position.Y = e.Y;
163             Position = treeView1.PointToClient(Position);
164 
165             //检索目标节点
166             TreeNode DropNode = this.treeView1.GetNodeAt(Position);
167             // 1.目标节点不是空。2.目标节点不是被拖拽接点的子节点。3.目标节点不是被拖拽节点本身
168             if (DropNode != null && DropNode.Parent != myNode && DropNode != myNode)
169             {
170                 //临时节点
171                 TreeNode tempNode = myNode;
172                 // 将被拖拽节点从原来位置删除。
173                 myNode.Remove();
174                 // 在目标节点下增加被拖拽节点
175                 DropNode.Nodes.Add(tempNode);
176                 //目标节点的NodeId值
177                 Dropid = (string)DropNode.Tag.ToString();
178 
179                 //数据库中更新移动节点的parentID
180                 string strSQL;
181                 strSQL = " update TTree set parentId =" + Dropid + "   where  NodeId = " + Moveid + "  ";
182                 SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
183                 int i = db.ExecuteNonQuery(strSQL,null);
184                 if (i < 0)
185                 {
186                     MessageBox.Show("请正确拖动文件");
187                 }
188 
189 
190             }
191             // 如果目标节点不存在,即拖拽的位置不存在节点,那么就将被拖拽节点放在根节点之下
192             if (DropNode == null)
193             {
194                 //parentId = 0  表示根节点
195                 string strSQL;
196                 strSQL = " update TTree set parentId = 0   where  NodeId = " + Moveid + "  ";
197                 SQLiteDBHelper db = new SQLiteDBHelper(ComPath);
198                 int i = db.ExecuteNonQuery(strSQL, null);
199 
200                 TreeNode DragNode = myNode;
201                 myNode.Remove();
202                 treeView1.Nodes.Add(DragNode);
203             }
204         }
205         #endregion
206 
207     }
208 }

 

 

 

如有问题或建议,欢迎留言 ~ 博客地址:http://www.cnblogs.com/zqiang/