【原创】TreeView控件实现拖拉、添加以及删除结点操作类库
1
using System;2
using System.Collections.Generic;3
using System.Linq;4
using System.Text;5

6
using System.Collections;7
using System.ComponentModel;8
using System.Data;9
using System.Diagnostics;10
using System.Drawing;//Point11
using System.Windows.Forms;//TreeNode12

13

14
namespace upLibrary.upControls15


{16

/**//// <summary>17
/// 实现了拖放操作处理,并且每一个结点的添加和移除都能引发事件的TreeView。18
/// </summary>19

20
public class upTreeViewBase : System.Windows.Forms.TreeView21

{22
private System.ComponentModel.Container components = null;23
private TreeNode _DragNode;24
private bool _MoveNode = false;25
private bool _CopyNode = false;26
//private bool _CanDropDrag = false;27

28

/**//// <summary>29
/// 删除节点事件句柄(sender 是父结点或为空,e.Node是子结点)30
/// </summary>31

32
public delegate void NodeDeleteHandler(object Sender, upLibrary.upControls.TreeNodeEventArgs e);33

34

/**//// <summary>35
/// 增加节点事件句柄(sender 是父结点或为空,e.Node是子结点)36
/// </summary>37

38
public delegate void NodeAddHandler(object Sender, upLibrary.upControls.TreeNodeEventArgs e);39

40

/**//// <summary>41
/// 在删除或增加节点之间浏览子节点事件句柄(sender 是父结点或为空,e.Node是子结点)42
/// </summary>43

44
public delegate void BrowseTreeNodesEventHandler(object Sender, TreeNodeEventArgs e);45

46

/**//// <summary>47
/// 在拖放操作中改变父结点事件句柄(sender 是父结点或为空,e.Node是子结点)48
/// </summary>49

50
public delegate void ParentChangByDrapDropHandler(object Sender, TreeNodeEventArgs e);51

52

控件事件声明#region 控件事件声明53

54
[Description("在拖放操作中改变结点的父之前发生此事件")]55

56
public event ParentChangByDrapDropHandler ParentChangingByDrapDrop;57

58
[Description("在拖放操作中改变了结点的父之后发生此事件")]59

60
public event ParentChangByDrapDropHandler ParentChangedByDrapDrop;61

62
[Description("sender所代表的节点将被移除,通常在移动拖放操作之前后发生,或树已加载后再移除之前发生")]63

64
public event NodeDeleteHandler NodeDeleting;65

66
[Description("sender所代表的节点将被添加,通常在移动或复制拖放操作完成后发生,或树已加载后再新增之前发生")]67

68
public event NodeAddHandler NodeAdding;69

70
[Description("sender所代表的节点被移除,通常在移动拖放操作完成后发生,或树已加载后再移除节点后发生")]71

72
public event NodeDeleteHandler NodeDeleted;73

74
[Description("sender所代表的节点被添加,通常在移动或复制拖放操作完成后发生,或树已加载后再新增节点后发生")]75

76
public event NodeAddHandler NodeAdded;77

78
[Description("当调用BrowseNodes时从最低层开始遍历到指定node时发生此事件")]79

80
public event BrowseTreeNodesEventHandler InverseBrowseTreeNodes;81

82
[Description("向下遍历到指定node时发生此事件")]83

84
public event BrowseTreeNodesEventHandler DownBrowseTreeNodes;85

86
#endregion 87

88
public upTreeViewBase()89

{90
InitializeComponent();91
}92

93

组件设计器生成的代码#region 组件设计器生成的代码94

95

/**//// <summary>96
/// 设计器支持所需的方法 - 不要使用代码编辑器修改97
/// 此方法的内容。98
/// </summary>99

100
private void InitializeComponent()101

{102
components = new System.ComponentModel.Container();103
}104

105
#endregion106

107

"拖放相关"#region "拖放相关"108

109

/**//// <summary>110
/// 是否移动型拖放111
/// </summary>112

113
public bool CanMoveNode114

{115

get
{ return _MoveNode; }116
set117

{118
this.ItemDrag -= new System.Windows.Forms.ItemDragEventHandler(TreeView_ItemDrag);119
this.DragEnter -= new System.Windows.Forms.DragEventHandler(TreeView_DragEnter);120
this.DragDrop -= new System.Windows.Forms.DragEventHandler(TreeView_DragDrop);121
_MoveNode = value;122
if (_MoveNode)123

{124
this.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(TreeView_ItemDrag);125
this.DragEnter += new System.Windows.Forms.DragEventHandler(TreeView_DragEnter);126
this.DragDrop += new System.Windows.Forms.DragEventHandler(TreeView_DragDrop);127
}128
}129
}130

131

/**//// <summary>132
/// 是否复制型拖放133
/// </summary>134

135
public bool CanCopyNode136

{137

get
{ return _CopyNode; }138
set139

{140
this.ItemDrag -= new System.Windows.Forms.ItemDragEventHandler(TreeView_ItemDrag);141
this.DragEnter -= new System.Windows.Forms.DragEventHandler(TreeView_DragEnter);142
this.DragDrop -= new System.Windows.Forms.DragEventHandler(TreeView_DragDrop);143
_CopyNode = value;144
if (_CopyNode)145

{146
this.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(TreeView_ItemDrag);147
this.DragEnter += new System.Windows.Forms.DragEventHandler(TreeView_DragEnter);148
this.DragDrop += new System.Windows.Forms.DragEventHandler(TreeView_DragDrop);149
}150
}151
}152

153

/**//// <summary>154
/// 开始拖放155
/// </summary>156
/// <param name="sender"></param>157
/// <param name="e"></param>158

159
protected void TreeView_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e)160

{161
this._DragNode = (TreeNode)e.Item;162
string strItem = e.Item.ToString();163
if (_CopyNode && _MoveNode)164
DoDragDrop(strItem, DragDropEffects.Move | DragDropEffects.Copy);165
else if (_CopyNode)166
DoDragDrop(strItem, DragDropEffects.Copy);167
else if (_MoveNode)168
DoDragDrop(strItem, DragDropEffects.Move);169
}170

171

/**//// <summary>172
/// 拖入到控件边界内时173
/// </summary>174
/// <param name="sender"></param>175
/// <param name="e"></param>176

177
protected void TreeView_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)178

{179
if (e.Data.GetDataPresent(DataFormats.Text))180

{181
if ((e.KeyState & 4) == 4 && (e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)182
e.Effect = DragDropEffects.Move; // SHIFT KeyState for move.183
else if ((e.KeyState & 8) == 8 && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)184
e.Effect = DragDropEffects.Copy; // CTRL KeyState for copy.185
else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)186
e.Effect = DragDropEffects.Move; // By default, the drop action should be move, if allowed.187
else188
e.Effect = DragDropEffects.None;189
}190
else191
e.Effect = DragDropEffects.None;192
}193

194

/**//// <summary>195
/// 拖放完成196
/// </summary>197
/// <param name="sender"></param>198
/// <param name="e"></param>199
200
protected void TreeView_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)201

{202
upLibrary.upControls.TreeNodeEventArgs args = null;203
bool cancel = false;204
Point Position = new Point(e.X, e.Y);205
Position = this.PointToClient(Position);206
TreeNode DropNode = this.GetNodeAt(Position); //承载结点207
if (_DragNode.Parent == DropNode) return; //没有变嘛208
TreeNode oldparent = _DragNode.Parent;209

210
if ((e.Effect & DragDropEffects.Move) == DragDropEffects.Move) //如果是移动型就只是改一下父结点211

{212
if (ParentChangingByDrapDrop != null)213

{214
args = new upLibrary.upControls.TreeNodeEventArgs(_DragNode, oldparent, DropNode, TreeNodeOperateType.Modify, ref cancel);215
ParentChangingByDrapDrop(this, args);216
if (args.Cancel == true) return;217
}218
_DragNode.Remove();219

220
if (DropNode != null)221
DropNode.Nodes.Add(_DragNode); //如果树节点位于根级别,Parent 属性即为空引用222
else223
this.Nodes.Add(_DragNode);224

225
if (ParentChangedByDrapDrop != null)226

{227
args = new upLibrary.upControls.TreeNodeEventArgs(_DragNode, oldparent, DropNode, TreeNodeOperateType.Modify, ref cancel);228
ParentChangedByDrapDrop(this, args);229
}230
}231
else //否则是复制型的话则要在承载结点处新增结点232

{233
TreeNode tNode = (TreeNode)_DragNode.Clone(); //是复制型的当然要新做一个啦,复制的部分包括克隆的树节点及其以下的树结构234
this.AddNode(DropNode, tNode); //tNode及其子node都会在事件中去加入235
}236
}237

238
#endregion239

240

"增加和移除Node并引发事件"#region "增加和移除Node并引发事件"241

242

/**//// <summary>243
/// 加一个新Node至指定的上级Node244
/// </summary>245
/// <param name="newParent"></param>246
/// <param name="nodeText"></param>247
/// <returns>表示成功与否</returns>248

249
public bool AddNode(TreeNode newParent, string nodeText)250

{251
return AddNode(newParent, new TreeNode(nodeText));252
}253

254

/**//// <summary>255
/// 加一个Node至指定的上级Node256
/// </summary>257
/// <param name="newParent"></param>258
/// <param name="node"></param>259
/// <returns>表示成功与否</returns>260

261
public bool AddNode(TreeNode newParent,TreeNode node)262

{263
bool cancel = false;264
if (node != null)265

{266
this.DownBrowseTreeNodes += new BrowseTreeNodesEventHandler(upTreeViewBase_BrowseTreeNodesByAdd);267
TreeNodeEventArgs args = new TreeNodeEventArgs(node, node.Parent, newParent, TreeNodeOperateType.AddNew, ref cancel);268
this.OnAdownBrowseTreeNodes(args); //让在事件中去一级级地处理269
this.DownBrowseTreeNodes -= new BrowseTreeNodesEventHandler(upTreeViewBase_BrowseTreeNodesByAdd);270
}271
return !cancel;272
}273

274
private void upTreeViewBase_BrowseTreeNodesByAdd(object Sender, TreeNodeEventArgs e)275

{276
if (e.OperateType == TreeNodeOperateType.AddNew)277

{278
if (this.NodeAdding != null)279

{280
NodeAdding(this, e);281
if (e.Cancel) return;282
}283
e.Node.Remove();284
if (e.NewParent != null)285
e.NewParent.Nodes.Add(e.Node);286
else287
this.Nodes.Add(e.Node);288
if (this.NodeAdded != null)289
NodeAdded(this, e);290
}291
}292

293

/**//// <summary>294
/// 删除用户选定的当前Node295
/// </summary>296
/// <returns>表示成功与否</returns>297

298
public bool DeleteNode()299

{300
TreeNode node = this.SelectedNode;301
if (node != null)302

{303
return DeleteNode(node);304
}305
return false;306
}307

308

/**//// <summary>309
/// 删除参数指定的Node及其子Node,从最低层开始,并在删除Node之前后分别引发事件NodeDeleting 和 NodeDeleted310
/// </summary>311
/// <param name="node"></param>312
/// <returns>表示成功与否</returns>313

314
public bool DeleteNode(TreeNode node)315

{316
bool cancel = false;317
if (node != null)318

{319
this.InverseBrowseTreeNodes += new BrowseTreeNodesEventHandler(upTreeViewBase_BrowseTreeNodesByDelete);320
TreeNodeEventArgs args = new TreeNodeEventArgs(node, node.Parent, null, TreeNodeOperateType.Delete, ref cancel);321
this.OnInverseBrowseTreeNodes(args); //让在事件中去一级级地处理322
this.InverseBrowseTreeNodes -= new BrowseTreeNodesEventHandler(upTreeViewBase_BrowseTreeNodesByDelete);323
}324
return !cancel;325
}326

327
private void upTreeViewBase_BrowseTreeNodesByDelete(object Sender, TreeNodeEventArgs e)328

{329
if (e.OperateType == TreeNodeOperateType.Delete)330

{331
if (this.NodeDeleting != null)332

{333
NodeDeleting(this, e);334
if (e.Cancel) return;335
}336
e.Node.Remove();337
if (this.NodeDeleted != null)338
NodeDeleted(this, e);339
}340
}341

342
#endregion343

344

遍历并引发事件#region 遍历并引发事件345

346

/**//// <summary>347
/// 逆向遍历参数NODEX代表的节点及其所有子节点,从最底层起一层一层地引发BrowseChildNode事件348
/// </summary>349
350
protected void OnInverseBrowseTreeNodes(TreeNodeEventArgs args)351

{352
bool cancel = false;353
TreeNode ChildNode = null, BrotherNode = null;354
TreeNode Nodex = args.Node;355
if (Nodex == null) return;356

357
if (Nodex.Nodes.Count > 0)358

{359
ChildNode = Nodex.Nodes[0]; //能执行到此,表示有子节点360
while (ChildNode != null && !args.Cancel) //兄弟节点可能有多个361

{362
BrotherNode = ChildNode.NextNode;363
TreeNodeEventArgs arg = new TreeNodeEventArgs(ChildNode, ChildNode.Parent, ChildNode.Parent, args.OperateType, ref cancel);364
OnInverseBrowseTreeNodes(arg);365
args.Cancel = arg.Cancel;366
if (arg.Cancel) return;367
ChildNode = BrotherNode;368
}369
}370

371
if (!args.Cancel) //如果下一级的事件中指定了取消,就不引发本级的事件了372

{373
if (InverseBrowseTreeNodes != null)374
InverseBrowseTreeNodes(this, args); //当没有子节点时,该节点就是末节,在事件中去处理吧,375
}376
}377

378

/**//// <summary>379
/// 正向遍历参数NODEX代表的节点及其所有子节点,在事件中的操作不可逆,Cancel为真只能停止遍历380
/// </summary>381
382
protected void OnAdownBrowseTreeNodes(TreeNodeEventArgs args)383

{384
bool cancel = false;385
TreeNode ChildNode = null, BrotherNode = null;386
TreeNode Nodex = args.Node;387

388
if (Nodex != null)389

{390
if (DownBrowseTreeNodes != null)391
DownBrowseTreeNodes(this, args); //首先处理自己392
if (args.Cancel) return; //要求取消,不用管下一级了393
if (Nodex.Nodes.Count <= 0) return; //根本就没有下一级了394

395
ChildNode = Nodex.Nodes[0]; //能执行到此,表示有子节点396
while (ChildNode != null && !args.Cancel) //兄弟节点可能有多个397

{398
BrotherNode = ChildNode.NextNode;399
TreeNodeEventArgs arg = new TreeNodeEventArgs(ChildNode, ChildNode.Parent, ChildNode.Parent, args.OperateType, ref cancel);400
OnAdownBrowseTreeNodes(arg);401
args.Cancel = arg.Cancel;402
if (arg.Cancel) return;403
ChildNode = BrotherNode;404
}405
}406
}407

408
#endregion409
}410

411

/**//// <summary>412
/// 遍历指定的node及其子node时的操作类型413
/// </summary>414

415
public enum TreeNodeOperateType416

{417
BrowseOnly = 1, AddNew, Modify, Delete418
}419

420
public class TreeNodeEventArgs : System.EventArgs421

{422
private TreeNode _Node, _OldParent, _NewParent;423
private bool _Cancel;424
private TreeNodeOperateType _OperateType;425

426

/**//// <summary>427
/// 使用此事件数据时,Sender 应是Node的Parent428
/// </summary>429
/// <param name="Node">要加入到Sender所代表的Nodes的Node</param>430
/// <param name="OperateType">发起遍历的操作类型</param>431
/// <param name="Cancel">在事件处理中是否要求出污</param>432

433
public TreeNodeEventArgs(TreeNode Node, TreeNode oldParent, TreeNode newParent, TreeNodeOperateType OperateType, ref bool Cancel)434
: base()435

{436

437
_OldParent = oldParent;438

439
_NewParent = newParent;440

441
_Node = Node;442

443
_Cancel = Cancel;444

445
_OperateType = OperateType;446

447
}448

449
public TreeNode OldParent450

{451

452

get
{ return _OldParent; }453

454

set
{ _OldParent = value; }455

456
}457

458
public TreeNode NewParent459

{460

461

get
{ return _NewParent; }462

463

set
{ _NewParent = value; }464

465
}466

467
public TreeNode Node468

{469

470

get
{ return _Node; }471

472

set
{ _Node = value; }473

474
}475

476
public TreeNodeOperateType OperateType477

{478

479

get
{ return _OperateType; }480

481

set
{ _OperateType = value; }482

483
}484

485
public bool Cancel486

{487

488
get489

{490

491
return _Cancel;492

493
}494

495
set496

{497

498
_Cancel = value;499

500
}501

502
}503

504
}505

506
}507

宠辱不惊,闲看庭前花开花落;去留无意,漫随天外云卷云舒。
浙公网安备 33010602011771号