买了本大话设计模式,看的饶有兴致,于是也想来实践一下. 做个什么东西玩玩
想到自己文件(尤其的音乐文件)很多,有时候这些文件的文件名又是没有规范的,
于是想到做一个文件名管理器.
顺便也来练练设计模式.
以循序渐进的方式来吧.
先给出我想实现的第一版的功能需求:
1, 用一个列表框,来加载当前加载到程序中的文件的文件名,
2,添加不同种类的编号,如 01,02格式或1,2,3,或001,002等格式,添加为前缀或者后缀形式
3, 主面板使用常见编号方式以及更改某一文件属性形式
4,音乐文件因为包含很多特殊信息如ID3信息,放在第二版制作用一个选项卡来占位
第一版我打算不用任何设计模式,只按目前直觉上的一些过程化设计来做.
首先是画界面(小菜一个,WPF也是刚刚接触,基础基本为零哈,见谅见谅)
< Window x:Class ="文件名管理器_ver1.MainWindow"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Title ="文件名管理器 ver 1.0" Height ="376" Width ="701" Icon ="透明head.png" >
< Grid Margin ="3 3 3 3" >
< Label Content ="文件列表:" Margin ="0,0,88,0" Name ="label1" HorizontalAlignment ="Right" Height ="40" VerticalAlignment ="Top" />
< TabControl Name ="tabControl1" Margin ="0,0,147,0" >
< TabItem Header ="普通文件" Name ="tabOrdinaryFile" >
< Grid >
< GroupBox Header ="文件信息" Margin ="6,6,6,69" Name ="groupBox1" >
< GroupBox.ContextMenu >
< ContextMenu >
< MenuItem Header ="aaa" />
< MenuItem Header ="aaa" />
< MenuItem Header ="aaa" />
</ ContextMenu >
</ GroupBox.ContextMenu >
< Grid >
< Label Content ="文件名:" Name ="lstFilename" Height ="24" Width ="60" Margin ="6,20,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Top" />
< Label Content ="大小:" Name ="labSizeTitle" Height ="24" Width ="60" Margin ="6,50,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Top" />
< Label Content ="路径:" Name ="labPathTitle" Height ="24" Width ="60" Margin ="6,80,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Top" />
< Label Content ="属性:" Name ="labAttributeTitle" Height ="24" Width ="60" Margin ="6,110,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Top" />
< TextBox Height ="23" HorizontalAlignment ="Left" Margin ="72,22,0,0" Name ="txtFileName" VerticalAlignment ="Top" Width ="120" />
< CheckBox ToolTip ="编号为2时,编号形式为01,02,以此类推" Content ="启用编号? 位数:" Height ="16" HorizontalAlignment ="Left" Margin ="198,25,0,0" Name ="checkBox1" VerticalAlignment ="Top" Click ="checkBox1_Checked" />
< TextBox IsEnabled ="False" Height ="23" HorizontalAlignment ="Left" Margin ="305,19,0,0" Name ="txtDigit" VerticalAlignment ="Top" Width ="25" Text ="2" />
< RadioButton Content ="编号前缀" ToolTip ="将编号添加为前缀形式,如001.XXX" Height ="16" HorizontalAlignment ="Left" Margin ="346,26,0,0" Name ="rdoPrefix" GroupName ="Method" VerticalAlignment ="Top" IsEnabled ="False" IsChecked ="True" />
< RadioButton Content ="编号后缀" ToolTip ="将编号添加为后缀,如XXX.001" Height ="16" HorizontalAlignment ="Left" Margin ="416,26,0,0" Name ="rdoPostfix" GroupName ="Method" VerticalAlignment ="Top" IsEnabled ="False" />
< Label Content ="--" Height ="28" HorizontalAlignment ="Left" Margin ="72,50,0,0" Name ="labSize" VerticalAlignment ="Top" />
< Label Content ="--" Height ="28" HorizontalAlignment ="Left" Margin ="72,80,0,0" Name ="labPath" VerticalAlignment ="Top" />
< CheckBox Content ="只读" Height ="16" HorizontalAlignment ="Left" Margin ="72,115,0,0" Name ="chkReadonly" VerticalAlignment ="Top" IsEnabled ="False" IsChecked ="False" />
< CheckBox Content ="隐藏" Height ="16" HorizontalAlignment ="Left" Margin ="119,115,0,0" Name ="chkHide" VerticalAlignment ="Top" IsEnabled ="False" IsChecked ="False" />
</ Grid >
</ GroupBox >
< Button Content ="将更改批量修改到文件" HorizontalAlignment ="Left" Margin ="353,0,0,6" Name ="btnBatch" Width ="137" IsEnabled ="False" Height ="30" VerticalAlignment ="Bottom" Click ="btnBatch_Click" />
< Button Content ="保存信息到当前文件" HorizontalAlignment ="Left" Margin ="210,0,0,6" Name ="btnSingle" Width ="137" Height ="30" VerticalAlignment ="Bottom" Click ="btnSingle_Click" />
< Button Content ="打开文件" HorizontalAlignment ="Left" Margin ="12,0,0,6" Name ="btnOpen" Width ="66" Height ="30" VerticalAlignment ="Bottom" Click ="btnOpen_Click" />
< Button Content ="打开文件夹" Height ="30" HorizontalAlignment ="Left" Margin ="84,0,0,6" Name ="button1" VerticalAlignment ="Bottom" Width ="66" Click ="button1_Click" />
</ Grid >
</ TabItem >
< TabItem Header ="音乐文件" Name ="tabMusicFile" >
< Grid />
</ TabItem >
</ TabControl >
< ListBox Name ="lstFilelist" SelectionMode ="Extended" HorizontalAlignment ="Right" Width ="146" Margin ="0,21,0,0" DragOver ="lstFilelist_DragOver" IsEnabled ="True" SelectionChanged ="lstFilelist_SelectionChanged" >
< ListBox.ContextMenu >
< ContextMenu >
< MenuItem Header ="添加文件" />
< MenuItem Header ="添加文件夹" />
< MenuItem Header ="删除选定条目" />
< MenuItem Header ="清空整个列表" />
</ ContextMenu >
</ ListBox.ContextMenu >
</ ListBox >
</ Grid >
</ Window >
因为基础太差,因此在画界面的时候完全是摸索着来的,没有系统看过任何关于WPF的教程,如果有时间得系统学学WPF哈
界面画出来是这样的:
比较丑哈,仅仅为实现功能用.
说说一步步实现的思路吧:
主要用到的FCL中的数据结构和类
List<FileInfo> 用来存放加载的文件信息
FolderBrowserDialog 用来做文件夹浏览
OpenFileDialog 用来做文件浏览
首先是该程序可以加载一个或多个文件到列表框中,
本来想用一个按钮实现打开文件和打开文件夹的功能,
但是发现FCL提供的类库里面没有这样一个东东,
而且即使在具体操作上也很难实现,
比如,你不能确定,当前双击一个文件夹,
究竟是打开该文件夹好,还是加载该文件夹的内容好.
网上搜索了很久也没发现类似的东西,因此就分开做了俩按钮,一个用于打开文件夹,一个用于打开一个或多个文件。
(由于时间关系,目前只做了打开一个或多个文件的功能)
打开一个或多个文件的代码如下:
// 打开文件
private void btnOpen_Click( object sender, RoutedEventArgs e)
{
ofd.Multiselect = true ;
if (ofd.ShowDialog() == true )
{
for ( int i = 0 ; i < ofd.SafeFileNames.Length; i ++ )
{
// 判断当前列表中是否已经存在该文件信息
if ( ! curAddedFiles.Contains( new FileInfo(ofd.FileNames[i])))
{
curAddedFiles.Add( new FileInfo(ofd.FileNames[i]));
}
}
/* 最初做数据绑定的时候,
* 思路是用一个Dictionary来存放文件名以及该文件的完整路径,在加载文件时,然后遍历
* 但是发现这样做有很多麻烦的事情会发生,比如我需要在ListBox的SelectionChanged事件类似于
* ((KeyValuePair<string, string>)((sender as ListBox).SelectedItem)).Key
* 这样的转型语句来获取到文件信息,这样做编码量和效率应该都很低 */
lstFilelist.Items.Refresh(); // 注意,必须要重新创建视图。否则不会在该listbox中显示新的数据源
lstFilelist.ItemsSource = curAddedFiles;
lstFilelist.DisplayMemberPath = " Name " ; // 以FileInfo类中的Name字段来作为显示的源,但是listbox里面存的是一条条的FileInfo对象
}
}
当在listbox中加载了该文件后,就要实现在每在listbox中选一个条目的时候,左边的详细信息应该予以绑定才行.
这个可以用Listbox的SelectionChanged事件来实现
private void lstFilelist_SelectionChanged( object sender, SelectionChangedEventArgs e)
{
curSelectedFiles = e.AddedItems as List < FileInfo > ;
curFileInf = e.AddedItems[ 0 ] as FileInfo;
// *这种方法同样可以实现*/ txtFileName.Text = ((KeyValuePair<string, string>)((sender as ListBox).SelectedItem)).Key;
txtFileName.Text = System.IO.Path.GetFileNameWithoutExtension(curFileInf.FullName); // 此函数可以去掉文件名的扩展名和路径,这样用户更改文件名时也不用考虑扩展名的问题
labPath.Content = curFileInf.DirectoryName;
chkReadonly.IsChecked = curFileInf.Attributes.HasFlag(FileAttributes.ReadOnly); // HasFlag其实是对FileAttributes的一组位运算,因为文件属性本来就是以位信息来存的
chkHide.IsChecked = curFileInf.Attributes.HasFlag(FileAttributes.Hidden);
labSize.Content = FormatFileSize(curFileInf.Length); // FormatFileSize是一个格式化文件大小的函数,网上看到的.
}
这样,我们就实现了将文件选入程序,并且查看单个文件的信息的功能
更改单个文件只需要在button事件里 写一句代码:
curFileInf.MoveTo(curFileInf.DirectoryName +"\\"+ txtFileName.Text);
就搞定了
批量更改:
// 批量更改
private void btnBatch_Click( object sender, RoutedEventArgs e)
{
if ( string .IsNullOrEmpty(txtFileName.Text))
{
MessageBox.Show( " 请先指定一个文件名 " );
return ;
}
if (MessageBox.Show( " 该功能将以您输入的文件名为标准 为所选定的文件加上您指定的前缀或后缀 " , " 注意! " ,MessageBoxButton.YesNo) == MessageBoxResult.No)
{
return ;
}
string setDigit = "" ;
for ( int i = 0 ; i < int .Parse(txtDigit.Text); i ++ )
{
setDigit += " 0 " ;
}
if (rdoPrefix.IsChecked == true )
{
// 以前缀形式添加
for ( int i = 0 ; i < curAddedFiles.Count; i ++ )
{
curAddedFiles[i].MoveTo(curFileInf.DirectoryName + " \\ " +
string .Format( " {0: " + setDigit + " } " , i) + txtFileName.Text + curFileInf.Extension);
// ↑ 拼接一段格式化字符串 比如如果你设置的是两位那么拼接的结果就是 ("{0:00"} ", i) 那么文件名也将显示为 01,02,下同
}
}
else if (rdoPostfix.IsChecked == true )
{
// 以后缀形式添加
for ( int i = 0 ; i < curAddedFiles.Count; i ++ )
{
string name = curFileInf.DirectoryName + " \\ " + txtFileName.Text +
string .Format( " {0: " + setDigit + " } " , i) + curFileInf.Extension;
curAddedFiles[i].MoveTo(name);
}
}
}
当点击“启用编号”复选框后 “将更改批量修改到文件” “编号位数”“前后缀等” 也设置为可用,
这个只需要checkbox的一个click事件,在里面判断一下就可以解决。很简单 不贴代码了
至此,整个程序的初版功能就到此为止,虽然简单,但是也花了我好几个晚上的时间,看来还需大大努力啊.效果如下图
但是这个程序还有非常严重的问题
代码异常 "脏乱差" ,没有任何架构和设计可言,仅仅是简单的实现了我在第一版需求的功能而已(并且还有不少bug ;D),
如果我现在想要增加一些功能
比如:
以不同方式的编号来给文件夹改名,例如 带括弧的编号,
以保留原始文件名的方式给文件加上编号.
另外还有保留的那块音乐文件信息的处理
如果将所有代码都写到主文件里面
这将是一件很恐怖的事情.
因此这周我将这个程序用一些简单的设计模式来重构,以便日后来扩展它的功能