WPF 文件管理系统

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

一、界面图和效果图
显示不出来
界面比较简单,左边就是一个TreeView,右边就是ListView。如果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,这里读者可以先不用看

           }

三、界面中的”格式”
图片:

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

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个资源分。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值