WPF 文件管理系统

时间:2022-11-02 05:15:25

简介:用WPF开发的一款简单的文件管理系统,主要用到了IO、TreeView、ListView这三样比较基础的东西,由于已有半年没有接触过WPF了,之前一直在开发Unity3D,这次开发也是因为公司需要这么一个简单的东西,所以花了一天半开发出来,刚好回忆下之前的半吊子WPF,所以写这篇博客记录一些控件的使用一些简单的设计,方便下次不用花时间去寻找,也帮助初学者一些经验,虽然我也是初学者。o(^▽^)o。

一、界面图和效果图
WPF 文件管理系统
界面比较简单,左边就是一个TreeView,右边就是ListView。如果WPF基础好的话,完全可以将这两个控件搞得漂漂亮亮的,不过我就没那个实力了,对WPF的数据绑定是云里雾里的,基本上都是从网上查阅资料和看书,看帮助文档。
二、界面中”文件夹路径”
WPF 文件管理系统
实现的功能:在“文件夹路径”中,可以通过选择的路径,查看该路径下的所有文件
设计:将此路径存在一个txt文本中,将选择的路径进行保存,这样下次就不用在此进行选择了。
核心代码:

放文件夹路径的路径
string path = AppDomain.CurrentDomain.BaseDirectory + "\\path.txt";
读取txt文件中的内容,这段代码中放入到窗体的Loading事件中
try {
string filepath = string.Empty;//文件下的路径
if(File.Exists(path)) {
//如果文件不为空
StreamReader sr = new StreamReader(path, Encoding.GetEncoding("utf-8")); //读取数据
filepath = sr.ReadToEnd().ToString().Trim();
sr.Close();//关闭文件流
txtPath.Text = filepath;

CreateDynIconTreeView(filepath, sformat);
Isload = true;
}
}
catch {
MessageBox.Show("读取文件中的数据失败");
Environment.Exit(0);//关闭程序;
}

当点击选择路径时

System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();

if(dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
txtPath.Text = dialog.SelectedPath;
}
//如果路径不为空的话,就将路径指定到文件中
if(!string.IsNullOrEmpty(txtPath.Text)) {
if(!Directory.Exists(txtPath.Text)) {
MessageBox.Show("路径不存在");
return;
}

if(File.Exists(path)) {
//如果文件存在,则删除该文件
File.Delete(path);
//之所以删除,怕出现文件重名或者文件占用问题
}

FileStream fs = new FileStream(path, FileMode.Create);//创建文件
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(txtPath.Text.Trim());
sw.Close();
fs.Close();

CreateDynIconTreeView(txtPath.Text.Trim(), sformat);//根据选择的路径,加载TreeView,这里读者可以先不用看

}

三、界面中的”格式”
图片:
WPF 文件管理系统
实现的功能:根据选择的格式,然后对路径下的所有文件进行重新排列,只显示该格式的所有文件
设计:这些格式项,是运用了枚举类,类中全部是这些格式,未来如果在进行格式添加时,直接在枚举类中加上即可。不过这个设计还不是最好的,最好的应该是将这些格式写入到一个文件中,如果需要添加其他的格式,直接在文本中添加格式名即可,比较方便,不过有个问题是每个格式对应的图标又是一个问题了,如果要想解决这个办法的话,还需要考虑更多的东西,不过这个系统的重点不是这个,所以完全没必要从这里花费时间,适可而止,以后需要改进的话,在写即可。
WPF 文件管理系统
核心代码:

cmbFormat.Items.Clear();

foreach(var item in Enum.GetValues(typeof(FileFormat))) {
string strName = Enum.GetName(typeof(FileFormat), item);
cmbFormat.Items.Add(strName);
}
cmbFormat.SelectedIndex = 0;
//FileFormat是个枚举类,这里是进行对枚举类中各个值进行遍历,然后加入到ComboBox中

四:TreeView显示文件夹和文件
功能:根据选择的途径,将路径下的所有文件和文件夹,当选择TreeView子项时的一些基本事件,比如TreeViewItem折叠、展开等等。还有选中某个子项,ListView就显示这个选择子项下的所有文件和文件夹
设计:需要实现上述功能,首先获取改路径下的所有文件夹和文件,要将这些文件夹和文件已TreeView的形式显示出来。(核心代码与设计一起说明)
1、根据路径获取所有文件夹和文件

string[] directories = Directory.GetDirectories(fPath);//根据路径,获取该路径下的文件夹,如果需要获取该路径的所有文件夹的话,就需要递归了。

if(string.IsNullOrEmpty(format)) {
files = Directory.GetFiles(fPath, “*”);//所有格式
}
else {
files = Directory.GetFiles(fPath, “*.” + format);//文件格式
}
根据格式,搜索路径下的所有该格式的文件

2、TreeView的显示
既然路径已经获取到了,现在就需要将路径中的文件夹和文件显示在TreeView中。
先把重要核心代码贴出来,如果不懂得话,可以去下载源码
xaml:

添加一级节点
DirectoryInfo info = new DirectoryInfo(path);//获取路径目录的文件夹名
TreeViewItem Nodes = new TreeViewItem() { Header = CreateTreeViewItem1(info.Name) };//TreeView节点的小图标,锦上添花,具体的话可看源码
![](http://img.blog.csdn.net/20160408172001079)
Nodes.Expanded += Node_Expanded;//双击展开
Nodes.Collapsed += Node_Collapsed;//双击折叠,这两个事件不懂得话。可以去看官方帮助文档

//自定义类,用户纪录每个节点的对象和该节点文件夹的路径,之所以这样子做是因为当鼠标选中某个子项时,获取到该子项的对象,即可获取到对应的路径,这样ListView才会展示改路径下的所有文件和文件夹,如果有更好的办法,请您一定给我留言,我觉得一定有更好的办法,只是限于我对WPF的了解不足。

public List<TVItems> listItems = new List<TVItems>();//定义的一个全局泛型,用于存所有TVItem对象和路径
TVItems items = new TVItems() {
ViewItem = Nodes,
path = path
};

getDirectories(path, Nodes,format);//添加文件夹节点
getfiles(path, Nodes, format);//添加文件节点
Nodes.IsExpanded = true;//子项展开

tvMain.Items.Add(Nodes);//将子项添加到TreeView控件中

SetListView(path, format);//加载ListView先把这四行代码贴出来,担心读者没有这几行代码看的云里雾里,虽然我知道思路可能没那么清楚,本人也是第一次写博客,特别是这么长的,请谅解。后面我会对这四行代码有个详细的介绍,就当是先做个铺垫吧!!!o(^▽^)o

添加二级节点
添加文件夹节点
getDirectories()方法就是加载路径下的所有文件夹和文件,并且创建一个TreeViewItem,将其加入到上一个TreeViewItem中,这里用到了递归。 format参数就是格式
private void getDirectories(string fPath, TreeViewItem aNode,string format)
{
//读取我选择的路径下的文件和目录
string[] directories = Directory.GetDirectories(fPath);//文件夹集合

foreach(string pathString in directories) {
DirectoryInfo info = new DirectoryInfo(pathString);
TreeViewItem Node = new TreeViewItem() {
Header = CreateTreeViewItem1(info.Name),
};

TVItems items = new TVItems() {
ViewItem = Node,
path = pathString
};
listItems.Add(items);

//添加节点
aNode.Items.Add(Node);
aNode.Expanded += Node_Expanded;
aNode.Collapsed += Node_Collapsed;
//添加文件夹的所有文件
getfiles(pathString, Node, format);

if(Directory.GetDirectories(pathString) != null) {
getDirectories(pathString, Node,format);
}
}
}
添加文件节点
private void getfiles(string fPath, TreeViewItem aNode,string format)
{
string[] files;
if(string.IsNullOrEmpty(format)) {
files = Directory.GetFiles(fPath, "*");//文件格式
}
else {
files = Directory.GetFiles(fPath, "*." + format);//文件格式
}

foreach(string filePath in files) {
TreeViewItem Node = new TreeViewItem() { Header = CreateTreeViewItem2(Path.GetFileName(filePath)) };
aNode.Items.Add(Node);
}
}
文件节点不需要添加TVItems,为什么呢,之前我说过创建TVItems类的主要目的是为了当鼠标单击TreeView下TreeViewItem节点时,ListView已列表的形式显示该TreeViewItem下的所有节点(文件夹和文件)这里针对的是单击文件夹,如果单击了文件其实意义并不大,因为单击了文件,它一个单体,没必要再ListView中在此显示了。

五:ListView列表的显示
功能:ListView列表的主要功能是根据选中的TreeView节点,然后显示该节点下的所有文件和文件夹
设计:既然需要显示选中节点下的所有文件和文件夹,首先必须知道选中了那个节点(这个简单),其实需要知道选中节点的路径(选中文件夹的路径),所以我设计了一个TVItems类,并且定义了两个属性,就是存储所有文件夹的节点对象和该文件夹的路径

/// <summary>
/// 需要加载的ListViewItem项
/// </summary>
public class TVItems {
/// <summary>
/// TreeView子项
/// </summary>
public TreeViewItem ViewItem {
get; set;
}

/// <summary>
/// 该子项的路径
/// </summary>
public string path {
get; set;
}

public TVItems()
{
}
}

其实当鼠标单击了TreeView子项时

 private void tvMain_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
TreeViewItem item = (TreeViewItem)e.NewValue;//获取到选中的TreeViewItem对象
//根据对象,往泛型中查找这个节点对象,并且获取节点对象所在的类对象,主要用到了泛型中的Find()方法,我也是最近才知道,以前一直都不知道,以前都是用foreach,用foreach查看对象一点都不好,而且效率低,占内存(我是U3D开发),代码可读性差,今天终于找到这个了
TVItems tvItems = listItems.Find(delegate (TVItems tv) {
return (tv.ViewItem.Equals(item));
});

if(tvItems == null) {
return;
}
SetListView(tvItems.path, sformat);//设置ListView显示
}

既然获取到了鼠标单击TreeView的节点对象了,剩下就简单了,需要知道ListView显示的列是些什么信息,我这里随便显示了一些东西。用到了数据绑定。
ListView xaml:

<ListView Name="lvMain" MouseDoubleClick="lvMain_MouseDoubleClick">
<ListView.View>
<GridView>
<GridViewColumn Width="30">
<GridViewColumn.Header>
<TextBlock></TextBlock>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Image Source="{Binding ImgPath}" Width="18"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="文件名" Width="200" DisplayMemberBinding="{Binding Path=Name}"/>
<GridViewColumn Header="类型" Width="100" DisplayMemberBinding="{Binding Path=Type}"/>
<GridViewColumn Header="大小" Width="100" DisplayMemberBinding="{Binding Path=Size}"/>
<GridViewColumn Header="路径" Width="450" DisplayMemberBinding="{Binding Path=Path}"/>

</GridView>
</ListView.View>

</ListView>
ListView的数据绑定,对于这个我也不是很了解,所以就不详细说明了,就不误人子弟了,不过还需要定义一个类
public class LVItem: INotifyPropertyChanged {
private string _Name;
private string _Type;
private string _Size;
private string _Path;
private string _ImgPath;
public string Name {
get {
return _Name;
}
set {
_Name = value;
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public string Type {
get {
return _Type;
}
set {
_Type = value;
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("Type"));
}
}
}
public string Size {
get {
return _Size;
}
set {
_Size = value;
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("Size"));
}
}
}
public string Path {
get {
return _Path;
}
set {
_Path = value;
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("Path"));
}
}
}
public string ImgPath {
get {
return _ImgPath;
}
set {
_ImgPath = value;
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("ImgPath"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
OK ListView的准备工作已经做完了。
运用最重要的东西,定义一个泛型,用来存储这个类的值,也就是ListView列表需要显示的值,这些类的赋值就是根据路径获取到该路径下的所有文件夹和文件,具体可以看源码,或者看前面的,其实也差不多,异曲同工。

listLVItem.Clear();
lvMain.ItemsSource = null;
/*
这里的代码就是获取路径下的文件夹和文件,然后添加到listLVItem泛型中
*/
lvMain.ItemsSource = listLVItem;
可能会有疑惑为什么要lvMain.ItemsSource = null;之后又lvMain.ItemsSource = listLVItem;这是因为当我们重新选择路径,或者选择某个节点或者格式限制时,ListView都需要重新刷新,如果不将ItemsSource不为空的话,那么就不会刷新。

其他的方法
获取文件夹的大小
/// <summary>
/// 获取文件夹的大小
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
long GetDicrectoryLenght(string path)
{
if(!Directory.Exists(path)) {
return 0;
}
DirectoryInfo info = new DirectoryInfo(path);
long lenght = 0;
foreach(var fi in info.GetFiles()) {
lenght += fi.Length;
}
DirectoryInfo[] dis = info.GetDirectories();
if(dis.Length > 0) {
for(int i = 0; i < dis.Length; i++) {
lenght += GetDicrectoryLenght(dis[i].FullName);
}
}
return lenght;
}
文件大小
FileInfo fileInfo = new FileInfo(pathString);
long len = fileInfo.lenght

TreeView的实现是我参考了另一个WPF开发者,从网上下的一个demo.http://download.csdn.net/detail/xgr66/8585917
源码下载:http://download.csdn.net/detail/iothua/9485116 下载需要5个资源分。