分享一个简单的资源管理器程序,主要是演示下LINQ在C#开发中的运用
以前有人在论坛里面问过,如何实现一个类似资源管理器的界面,其实运用 System.IO 下的一组API,很容易查询文件系统的文件。虽然说容易,但是还是很多人希望能看到具体的代码。下面我对其中最关键的代码作一个演示,程序尽可能简单,以便大家关注于主要问题。
先看下效果图:
代码下载 http://download.csdn.net/detail/caozhy/4169965。
本程序中使用了LINQ语法,简洁性大家可以自己体会,由于LINQ的运用,程序甚至连一个循环语句都不需要。很多人有一种误解,说到LINQ,就是数据库访问,就是ORM框架,就是转化成SQL执行等等,其实这是对LINQ的误解,我想用这个例子程序说明,LINQ没有那么神秘,它就是C# 3时代的一种简单语法,它可以融入到程序的每个角落。大家可以放心大胆地使用LINQ简化开发,书写紧凑的代码。
说一下这个程序的主要意图:
首先看到的是Form_Load,它的作用是加载根节点和驱动器列表:
treeView1.Nodes.Add(new TreeNode("Computer", DriveInfo.GetDrives() .Select(x => new TreeNode(x.Name) { Tag = x }).ToArray()) { Tag = "root" });
var rootNode = new TreeNode("Computer") { Tag = "root" }; treeView1.Nodes.Add(rootNode); foreach (var item in DriveInfo.GetDrives()) { rootNode.Nodes.Add(new TreeNode(item.Name) { Tag = item }); }
x => new TreeNode(x.Name) { Tag = x }
TreeNode ConvertDriveInfoToTreeNode(DriveInfo x){ TreeNode tn = new TreeNode(x.Name); tn.Tag = x; return tn;}
又见linq,是好工具
[解决办法]
很耐心。
[解决办法]
public class Drives : List<Drive> { public Drives() { this.AddRange(DriveInfo.GetDrives().Where(p => p.IsReady).Select(p => new Drive(p))); }}public interface Subject { string Name { get; set; } string Path { get; set; }}public class File : Subject { public FileInfo Info { get; set; } public string Name { get; set; } public string Path { get; set; } public File(string arg) : this(new FileInfo(arg)) { } public File(FileInfo arg) { this.Path = arg.FullName; this.Name = System.IO.Path.GetFileName(this.Path); }}public abstract class FileGroup : Subject { public string Name { get; set; } public string Path { get; set; } public FileGroup() { } public FileGroup(string name) { this.Name = name; } public IEnumerable<Subject> Folders { get { return LoadChildren().OfType<Folder>(); } } public IEnumerable<Subject> Children { get { return LoadChildren(); } } protected virtual IEnumerable<Subject> LoadChildren() { if (children == null) { var target = new DirectoryInfo(Path); Func<FileSystemInfo, bool> filter = p => !( p.Attributes.HasFlag(FileAttributes.System) || p.Attributes.HasFlag(FileAttributes.Hidden) ); var q = target.GetDirectories() .Where(filter) .Select(p => new Folder(p as DirectoryInfo)).Concat( target.GetFiles() .Where(filter) .Select(p => new File(p as FileInfo)) as IEnumerable<Subject> ); return q; } return children; } protected IEnumerable<Subject> children = null;}public class Drive : FileGroup { public DriveInfo Info { get; set; } public Drive(DriveInfo arg) { this.Info = arg; this.Path = arg.RootDirectory.Name; this.Name = string.Format("{0} ({1})", arg.VolumeLabel, arg.Name); }}public class Folder : FileGroup { public DirectoryInfo Info { get; set; } public Folder(string arg) : this(new DirectoryInfo(arg)) { } public Folder(DirectoryInfo arg) { this.Info = arg; this.Path = arg.FullName; this.Name = arg.Name; }}
------解决方案--------------------
纠正:
FileGroup.LoadChildren中
return q;
改为
children = q.ToList();
[解决办法]
不懂这个呢。
[解决办法]
看来我还得继续修炼,惭愧ing
[解决办法]
WPF的树好难看,怎么让树显示前面的引导线?
[解决办法]
看来要好好看看LINQ了。
[解决办法]
private void Form1_Load(object sender, EventArgs e) { treeView1.Nodes.Add(new TreeNode("Computer", (new ManagementObjectSearcher("select * from Win32_LogicalDisk").Get().Cast<ManagementObject>().Select(m => new TreeNode(m["DeviceID"] + "") { Name = m["DeviceID"].ToString()+"\\", Tag = m["CreationClassName"].ToString() }).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[] { }; string drive = x.Name.Substring(0, 2); string path = x.Name.Replace(drive, "").Replace("\\","\\\\"); if (x.Tag.ToString() == "Win32_LogicalDisk" || x.Tag.ToString() == "File Folder") { string queryTxt = @"select * from Win32_Directory where drive=""" + drive + @""" and path=""" + path + @""""; nodes = new ManagementObjectSearcher(queryTxt). Get().Cast<ManagementObject>(). Select(m => new TreeNode(m["FileName"].ToString()) { Name = m["name"].ToString() + "\\", Tag = m["FileType"].ToString() }).ToArray(); } x.Nodes.AddRange(nodes); } } catch { } }); } private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { if (e.Node.Text == "Computer") { listView1.Items.Clear(); listView1.Items.AddRange(new ManagementObjectSearcher("select * from Win32_LogicalDisk").Get().Cast<ManagementObject>().Select(m =>new ListViewItem(new string[]{ m["name"].ToString(), m["Description"].ToString(), (Convert.ToInt64(m["Size"])/ 1048576 / 1024).ToString()+"GB", ""})).ToArray()); } if (e.Node.Tag.ToString() == "Win32_LogicalDisk" || e.Node.Tag.ToString() == "File Folder") { listView1.Items.Clear(); string drive = e.Node.Name.Substring(0, 2); string path = e.Node.Name.Replace(drive, "").Replace("\\", "\\\\"); string queryText = @"select * from CIM_LogicalFile where drive=""" + drive + @""" and path=""" + path + @""""; listView1.Items.AddRange(new ManagementObjectSearcher(queryText). Get().Cast<ManagementObject>().Select(m => new ListViewItem(new string[]{ m["FileName"].ToString(), m["FileType"]+"", (Convert.ToInt64(m["FileSize"])/1024).ToString()+"KB", m["CreationDate"]+""})).ToArray()); } }
[解决办法]
碰到个问题,treeView1_BeforeExpand在展开节点的时候假如磁盘类型是可移动存储设备,并且驱动器未准备好的情况下,处理这个节点会花费相当多的时间
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; if (item.DriveType == DriveType.Removable && item.IsReady == false) { string message = "磁盘类型是可移动存储设备,并且驱动器未准备好会花费相当多的时间"; } 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 { } }); }