买了本大话设计模式,看的饶有兴致,于是也想来实践一下. 做个什么东西玩玩
想到自己文件(尤其的音乐文件)很多,有时候这些文件的文件名又是没有规范的,
于是想到做一个文件名管理器.
顺便也来练练设计模式.
以循序渐进的方式来吧.
先给出我想实现的第一版的功能需求:
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),
如果我现在想要增加一些功能
比如:
以不同方式的编号来给文件夹改名,例如 带括弧的编号,
以保留原始文件名的方式给文件加上编号.
另外还有保留的那块音乐文件信息的处理
如果将所有代码都写到主文件里面
这将是一件很恐怖的事情.
因此这周我将这个程序用一些简单的设计模式来重构,以便日后来扩展它的功能