目录
一、实验要求
使用windows 应用程序模板,编写一个简易的文件管理器。通过本次实验,练习 TreeView、ListView 和SplitContainer 控件的使用,同时熟悉 C#文件系统的操作方法以及 File 类和 Directory类的使用。
(1)窗体上添加 SplitContainer、TreeView、ListView 等控件,设置属性。将 TreeView 控件的 Dock 属性设置为 Fill,ListView 控件的 Dock 属性设置为 Fill,MultiSelect 属性设置为False,View 属性设置为 List。
(2)在 Form1.cs 中,添加对命名空间 using System.IO 的引用。
(3)在Treeview控件中,能够以树状展示我的电脑,各驱动器,驱动器下各个目录等信息。点击目录能打开此目录下的目录和文件,并在ListView中展示。
(4)在ListView 等控件,能够展示Treeview中当前驱动器或目录下的目录和文件,双击目录能继续展示目录中的目录和文件。
(我自己还加了一个 label 用于显示 listview 展示的目录的路径)
二、实验步骤
1、按实验提示设计界面
- 这个很简单,就不写了。
- 说一下命名:我给 listview 和 treview 的名字分别是 lVDir 和 tVDir,label 叫 lbLocation。
2、编写Form1_Load函数。
- 在窗体加载的时候给treeview添加设置根节点此电脑,并在listview同步显示。
- 由于此电脑无法匹配路径,手动在此电脑下添加C盘和D盘两个子节点。
- 为了C盘和D盘能够顺利展开,再给C盘和D盘分别添加两个虚拟节点。
private void Form1_Load(object sender, EventArgs e)
{
tVDir.Nodes.Clear();
lVDir.Items.Clear();
//添加此电脑树节点
TreeNode root = tVDir.Nodes.Add("此电脑");
root.ImageIndex = 0;
ListViewItem lv1 = lVDir.Items.Add("此电脑");
lv1.ImageIndex = 0;
lbLocation.Text = "当前位置:此电脑";
//添加C、D盘树节点
TreeNode nodec = root.Nodes.Add("C:\\");
nodec.ImageIndex = 1;
TreeNode noded = root.Nodes.Add("D:\\");
noded.ImageIndex = 1;
//给C、D盘加上空白子节点
TreeNode node1 = nodec.Nodes.Add("虚假子节点");
TreeNode node2 = noded.Nodes.Add("虚假子节点");
}
3、编写tVDir_BeforeExpand()函数。
- 首先清除listview的项。
- 然后判断要展开的是不是此电脑节点,
- 如果是
- 那treeview就不用进行其他操作,因为此电脑节点的子节点已经设置好了,直接展开就行,只需要把listview更新一下。
- 如果不是
- 那么先删去要展开节点的所有子节点(因为这可能是虚拟子节点)
- 然后获取当前路径(记得删去多余的“此电脑”)
- 最后获取路径下所有文件及文件夹
- 注意获取文件夹的时候判断文件夹里是否有东西,有东西的话要往文件夹节点下增添一个虚拟子节点,保证这个文件夹节点能展开
- 如果是
注:由于权限问题,每一次获取文件/文件夹名称的时候要使用try-catch,否则程序可能无法运行。
private void tVDir_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
//使选中节点为被展开的节点,方便listview找到路径
TreeNode selectnode = e.Node;
tVDir.SelectedNode = e.Node;
lVDir.Items.Clear();
//如果是此电脑目录,不需要清除treeview
if (selectnode.ImageIndex == 0)
{
ListViewItem lv2 = lVDir.Items.Add("C:");
lv2.ImageIndex = 1;
ListViewItem lv3 = lVDir.Items.Add("D:");
lv3.ImageIndex = 1;
return;
}
selectnode.Nodes.Clear();
//获取当前路径,记得删去多余的“此电脑”
string path = e.Node.FullPath.Remove(0, 4);
lbLocation.Text = "当前位置:" + path;
//获取当前路径的文件夹
string[] dirs = Directory.GetDirectories(path);
foreach (string dir in dirs)
{
try
{
string name = Path.GetFileName(dir);
TreeNode subnode = selectnode.Nodes.Add(name);
subnode.ImageIndex = 2;
ListViewItem lvsub = lVDir.Items.Add(name);
lvsub.ImageIndex = 2;
//如果文件夹下有东西,就创建一个虚假子节点保证这个节点能展开
int num = Directory.GetFiles(dir).Length + Directory.GetDirectories(dir).Length;
if (num > 0)
{
TreeNode subnodesub = subnode.Nodes.Add("虚假子节点");
}
}
catch (UnauthorizedAccessException) { }
}
//获取当前路径的文件
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
try
{
string name = Path.GetFileName(file);
TreeNode subnode = selectnode.Nodes.Add(name);
subnode.ImageIndex = 3;
ListViewItem lvsub = lVDir.Items.Add(file);
lvsub.ImageIndex = 3;
}
catch(UnauthorizedAccessException) { }
}
}
4、编写tVDir_BeforeSelect函数。
- 书写代码使节点被选中时图标不变,其实本来该让节点选中前后发生点变化,但是我懒得找图。浅浅放个代码吧。
private void tVDir_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
e.Node.SelectedImageIndex = e.Node.ImageIndex;
}
5、编写tVDir_BeforeCollapse函数
- treeview 不用管,主要是 listview 得有点变化。这个也比较简单,看代码注释就行。
private void tVDir_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
{
lVDir.Items.Clear();
TreeNode father = e.Node.Parent;
//如果没有父目录,直接展示此电脑
if (father == null)
{
ListViewItem lv1 = lVDir.Items.Add("此电脑");
lv1.ImageIndex = 0;
lbLocation.Text = "当前位置:此电脑";
return;
}
//在未进入C/D盘时,也算在此电脑,所以要多一个if-else
if (father.ImageIndex == 0)
lbLocation.Text = "当前位置:此电脑";
else
lbLocation.Text = "当前位置" + father.FullPath.Remove(0, 4);
//如果有父目录,展示同级的所有目录
foreach(TreeNode node in father.Nodes)
{
ListViewItem lv2 = lVDir.Items.Add((string)node.Text);
lv2.ImageIndex = node.ImageIndex;
}
}
6、编写lVDir_DoubleClick函数
- 主要实现双击listview的可打开文件夹时能打开文件夹。
- 这个我感觉主席是也写得比较详尽了,看注释吧(希望哪天我回顾的时候不要后悔)
private void lVDir_DoubleClick(object sender, EventArgs e)
{
/*双击展开目录,利用treeview的选中节点(上一次被改变状态的节点)
不过这里要注意,有可能连续双击,那么选中节点就不是想要的节点了,
所以在展开节点的同时要把选中节点更改一下
详见tVDir_BeforeExpand()函数第一行*/
ListViewItem selectlv = lVDir.SelectedItems[0];
TreeNode selectnode = tVDir.SelectedNode;
/*如果选中节点展开了,说明上一次的操作是展开节点,
所以listview展示的是当前节点的子目录,要展开的节点为当前节的子节点*/
if(selectnode.IsExpanded)
{
foreach (TreeNode node in selectnode.Nodes)
{
if(node.Text == selectlv.Text)
{
node.Expand();
return;
}
}
}
//如果选中节点未展开,listview展示的是父节点的子目录,要展开的节点与当前节点同级
else
{
//如果当前节点是此电脑,那它只能是此电脑,这一级只有一个节点
if(selectnode.Parent == null)
selectnode.Expand();
//如果不是此电脑,那就在同级节点中搜寻出将展开的节点,然后展开
else
{
foreach (TreeNode node in selectnode.Parent.Nodes)
{
if (node.Text == selectlv.Text)
{
node.Expand();
return;
}
}
}
}
}
总结
给代码写注释确实很有利于理清代码思路,特别是学习新知识时,写代码很有助于防止写着写着不知道自己在干什么。这个实验简直是我学计算机以来写注释最多的一次。