WinForm TreeView 上逐层加载数据
TreeView 是一个很好的表达树形结构的控件。如果要加载的数据比较多的话,就需要逐层加载数据。要实现逐层加载数据,首先想到的就是TreeView 的 BeforeExpand 事件,它在节点展开前触发。但问题是BeforeExpand 事件每次展开时都会触发。有没有只在首次展开才触发的事件呢,可惜没找到。没关系,我们
复制C#代码保存代码/// <summary>
/// 自定义节点类,继承于系统的 TreeNode 类
/// 自定义节点类的目的就是给节点增加一个 IsFirstExpand 属性
/// </summary>
public class DirNode : TreeNode
{
// 该节点是否首次被展开
private bool isFirstExpand = true;
public DirNode()
: base()
{ }
public DirNode(string text)
: base(text)
{ }
/// <summary>
/// 该节点是否首次被展开
/// 因为 TreeNode 没有该属性,那我们自己定义吧!
/// </summary>
public bool IsFirstExpand
{
get { return isFirstExpand; }
set { isFirstExpand = value; }
}
}自定义一个 TreeView 节点类,给它加一个是否首次被展开的属性。
自定义 TreeView 节点类有了“是否首次被展开”的属性之后,逐层展开 TreeView 节点的算法如下:
1) 在 Form_Load 时,先加载前两层节点(只是加载,不用展开)。
2) BeforeExpand 事件,判断该节点“是否首次被展开”。
如果该节点“是否首次被展开”,那么我们就给该节点的“每个子节点”,再添加“子节点”(如果有的话)。
下面是一个加载目录树程序的完整代码:
复制C#代码保存代码using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
namespace DirectoryTree
{
public partial class DirectoryTreeForm : Form
{
public DirectoryTreeForm()
{
InitializeComponent();
}
private void DirectoryTreeForm_Load(object sender, EventArgs e)
{
// 列出所有盘符:C:,D:,E:
string[] drivers = Environment.GetLogicalDrives();
for (int i = 0; i < drivers.Length; i++)
{
if (PlatformInvokeKernel32.GetDriveType(drivers[i]) == PlatformInvokeKernel32.DRIVE_FIXED)
{
DirNode root = new DirNode(drivers[i]);
treeView1.Nodes.Add(root);
// 添加一级目录
AddChildNotes(root);
}
}
}
/// <summary>
/// 节点展开之前事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
DirNode node = (DirNode) e.Node;
// 判断该节点是否首次被展开
if (node.IsFirstExpand)
{
// 为 e.Node 下的每个子节点,添加子节点
for (int i = 0; i < node.Nodes.Count; i++)
{
// 添加子节点
AddChildNotes(node.Nodes[i]);
}
node.IsFirstExpand = false;
}
}
/// <summary>
/// 添加 node 的子节点
/// </summary>
/// <param name="node"></param>
private void AddChildNotes(TreeNode node)
{
try
{
DirectoryInfo dir = new DirectoryInfo(GetPathFromNode(node));
DirectoryInfo[] e = dir.GetDirectories();
FileInfo[] f = dir.GetFiles();
string name;
for (int i = 0; i < e.Length; i++)
{
name = e[i].Name;
if (!name.Equals(".") && !name.Equals(".."))
{
node.Nodes.Add(new DirNode(name));
}
}
for (int i = 0; i < f.Length; i++)
{
name = f[i].Name;
node.Nodes.Add(new DirNode(name));
}
}
catch
{ }
}
/// <summary>
/// 获得该节点的完整路径
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
private string GetPathFromNode(TreeNode node)
{
if (node.Parent == null)
{
return node.Text;
}
return Path.Combine(GetPathFromNode(node.Parent), node.Text);
}
}
/// <summary>
/// 目录节点类,继承于系统的 TreeNode 类
/// 自定义节点类的目的就是给节点增加一个 IsFirstExpand 属性
/// </summary>
public class DirNode : TreeNode
{
// 该节点是否首次被展开
private bool isFirstExpand = true;
public DirNode()
: base()
{ }
public DirNode(string text)
: base(text)
{ }
/// <summary>
/// 该节点是否首次被展开
/// 因为 TreeNode 没有该属性,那我们自己定义吧!
/// </summary>
public bool IsFirstExpand
{
get { return isFirstExpand; }
set { isFirstExpand = value; }
}
}
/// <summary>
/// API 函数
/// </summary>
public class PlatformInvokeKernel32
{
[DllImport("KERNEL32", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetDriveType(string lpRootPathName);
public const int DRIVE_FIXED = 3;
}
}
复制C#代码保存代码/// <summary>
/// 自定义节点类,继承于系统的 TreeNode 类
/// 自定义节点类的目的就是给节点增加一个 IsFirstExpand 属性
/// </summary>
public class DirNode : TreeNode
{
// 该节点是否首次被展开
private bool isFirstExpand = true;
public DirNode()
: base()
{ }
public DirNode(string text)
: base(text)
{ }
/// <summary>
/// 该节点是否首次被展开
/// 因为 TreeNode 没有该属性,那我们自己定义吧!
/// </summary>
public bool IsFirstExpand
{
get { return isFirstExpand; }
set { isFirstExpand = value; }
}
}自定义一个 TreeView 节点类,给它加一个是否首次被展开的属性。
自定义 TreeView 节点类有了“是否首次被展开”的属性之后,逐层展开 TreeView 节点的算法如下:
1) 在 Form_Load 时,先加载前两层节点(只是加载,不用展开)。
2) BeforeExpand 事件,判断该节点“是否首次被展开”。
如果该节点“是否首次被展开”,那么我们就给该节点的“每个子节点”,再添加“子节点”(如果有的话)。
下面是一个加载目录树程序的完整代码:
复制C#代码保存代码using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
namespace DirectoryTree
{
public partial class DirectoryTreeForm : Form
{
public DirectoryTreeForm()
{
InitializeComponent();
}
private void DirectoryTreeForm_Load(object sender, EventArgs e)
{
// 列出所有盘符:C:,D:,E:
string[] drivers = Environment.GetLogicalDrives();
for (int i = 0; i < drivers.Length; i++)
{
if (PlatformInvokeKernel32.GetDriveType(drivers[i]) == PlatformInvokeKernel32.DRIVE_FIXED)
{
DirNode root = new DirNode(drivers[i]);
treeView1.Nodes.Add(root);
// 添加一级目录
AddChildNotes(root);
}
}
}
/// <summary>
/// 节点展开之前事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
DirNode node = (DirNode) e.Node;
// 判断该节点是否首次被展开
if (node.IsFirstExpand)
{
// 为 e.Node 下的每个子节点,添加子节点
for (int i = 0; i < node.Nodes.Count; i++)
{
// 添加子节点
AddChildNotes(node.Nodes[i]);
}
node.IsFirstExpand = false;
}
}
/// <summary>
/// 添加 node 的子节点
/// </summary>
/// <param name="node"></param>
private void AddChildNotes(TreeNode node)
{
try
{
DirectoryInfo dir = new DirectoryInfo(GetPathFromNode(node));
DirectoryInfo[] e = dir.GetDirectories();
FileInfo[] f = dir.GetFiles();
string name;
for (int i = 0; i < e.Length; i++)
{
name = e[i].Name;
if (!name.Equals(".") && !name.Equals(".."))
{
node.Nodes.Add(new DirNode(name));
}
}
for (int i = 0; i < f.Length; i++)
{
name = f[i].Name;
node.Nodes.Add(new DirNode(name));
}
}
catch
{ }
}
/// <summary>
/// 获得该节点的完整路径
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
private string GetPathFromNode(TreeNode node)
{
if (node.Parent == null)
{
return node.Text;
}
return Path.Combine(GetPathFromNode(node.Parent), node.Text);
}
}
/// <summary>
/// 目录节点类,继承于系统的 TreeNode 类
/// 自定义节点类的目的就是给节点增加一个 IsFirstExpand 属性
/// </summary>
public class DirNode : TreeNode
{
// 该节点是否首次被展开
private bool isFirstExpand = true;
public DirNode()
: base()
{ }
public DirNode(string text)
: base(text)
{ }
/// <summary>
/// 该节点是否首次被展开
/// 因为 TreeNode 没有该属性,那我们自己定义吧!
/// </summary>
public bool IsFirstExpand
{
get { return isFirstExpand; }
set { isFirstExpand = value; }
}
}
/// <summary>
/// API 函数
/// </summary>
public class PlatformInvokeKernel32
{
[DllImport("KERNEL32", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetDriveType(string lpRootPathName);
public const int DRIVE_FIXED = 3;
}
}