以前有人在论坛里面问过,如何实现一个类似资源管理器的界面,其实运用 System.IO 下的一组API,很容易查询文件系统的文件。虽然说容易,但是还是很多人希望能看到具体的代码。下面我对其中最关键的代码作一个演示,程序尽可能简单,以便大家关注于主要问题。
本程序中使用了LINQ语法,简洁性大家可以自己体会,由于LINQ的运用,程序甚至连一个循环语句都不需要。很多人有一种误解,说到LINQ,就是数据库访问,就是ORM框架,就是转化成SQL执行等等,其实这是对LINQ的误解,我想用这个例子程序说明,LINQ没有那么神秘,它就是C# 3时代的一种简单语法,它可以融入到程序的每个角落。大家可以放心大胆地使用LINQ简化开发,书写紧凑的代码。
很多人用过SQL,知道用select可以从表中选定某几列,在数学上,这个操作叫投影,通俗地说,就是对集合中的每一个元素做这样一种变换(什么变换由select子句决定),让每个元素成为另一种类型的元素,得到一个新的集合。
从数据中选择几列只是select操作的特例,在LINQ中,Select操作可以方便地将某个类型转换成另一个类型,在这里我们把查询出来的DriveInfo类型对象转换为Nodes.Add()方法理解的TreeNode类型。为此我们使用了一个Lambda表达式:
之后看到的是treeView1_BeforeExpand事件,它的作用是在展开节点的时候加载下面每个子节点再下一层的节点,为什么要子节点再下一层呢?这样可以让那些包含再下一层元素的节点提前出现“+”号,在展开的时候可以看到。这种按需加载TreeNode的技术很常用,希望新手们熟练掌握。
然后我们看到的是另一个事件处理函数treeView1_AfterSelect,它的作用是在点了某个节点的时候在ListView里面加载这个文件夹下的文件夹和文件。按照Windows习惯,先显示文件夹再显示文件。而且分别对文件夹和文件排序。请问这个如何实现?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
treeView1.Nodes.Add(new TreeNode("Computer", DriveInfo.GetDrives()
.Select(x => new TreeNode(x.Name) { Tag = x }).ToArray()) { Tag = "root" });
}
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
e.Node.Nodes.Cast<TreeNode>().ToList().ForEach(x =>
{
try
{
if (x.Nodes.Count == 0)
{
TreeNode[] nodes = new TreeNode[] { };
if (x.Tag.GetType() == typeof(DriveInfo))
{
var item = x.Tag as DriveInfo;
nodes = Directory.GetDirectories(item.Name)
.Select(y => new DirectoryInfo(y))
.Select(y => new TreeNode(y.Name) { Tag = y })
.ToArray();
}
if (x.Tag.GetType() == typeof(DirectoryInfo))
{
var item = x.Tag as DirectoryInfo;
nodes = Directory.GetDirectories(item.FullName)
.Select(y => new DirectoryInfo(y))
.Select(y => new TreeNode(y.Name) { Tag = y })
.ToArray();
}
x.Nodes.AddRange(nodes);
}
}
catch { }
});
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
if (e.Node.Tag.GetType() == typeof(string) && e.Node.Text == "Computer")
{
listView1.Items.AddRange(DriveInfo.GetDrives()
.Select(x => new ListViewItem(new string[] { x.Name, x.DriveType.ToString(), x.DriveType == DriveType.Fixed ? (x.TotalSize / 1048576 / 1024).ToString() + "GB" : "" }))
.ToArray());
}
if (e.Node.Tag.GetType() == typeof(DriveInfo))
{
listView1.Items.Clear();
listView1.Items.AddRange(Directory.GetDirectories((e.Node.Tag as DriveInfo).Name)
.Select(x => new DirectoryInfo(x)).OrderBy(x => x.Name)
.Select(x => new ListViewItem(new string[] { x.Name, "Folder", "", x.CreationTime.ToString()})).ToArray());
listView1.Items.AddRange(Directory.GetFiles((e.Node.Tag as DriveInfo).Name, "*.*", SearchOption.TopDirectoryOnly)
.Select(x => new FileInfo(x)).OrderBy(x => x.Name)
.Select(x => new ListViewItem(new string[] { x.Name, "File", (x.Length / 1024).ToString() + "KB", x.CreationTime.ToString() })).ToArray());
}
if (e.Node.Tag.GetType() == typeof(DirectoryInfo))
{
listView1.Items.Clear();
listView1.Items.AddRange(Directory.GetDirectories((e.Node.Tag as DirectoryInfo).FullName)
.Select(x => new DirectoryInfo(x)).OrderBy(x => x.Name)
.Select(x => new ListViewItem(new string[] { x.Name, "Folder", "", x.CreationTime.ToString() })).ToArray());
listView1.Items.AddRange(Directory.GetFiles((e.Node.Tag as DirectoryInfo).FullName, "*.*", SearchOption.TopDirectoryOnly)
.Select(x => new FileInfo(x)).OrderBy(x => x.Name)
.Select(x => new ListViewItem(new string[] { x.Name, "File", (x.Length / 1024).ToString() + "KB", x.CreationTime.ToString() })).ToArray());
}
}
}
}