---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
前言:很多时候,用户并不会像我们想的那样去把每个选项都填对
既然世上没有完美的用户,那么,我们唯有让软件拥有更优秀的容错能力。
接下来我将讲解和分析这个软件到底具有多强的容错能力。(若有大神路过请轻拍。。)
1.首先我在ColorString发布了一个TextChanged事件,这个事件在修改ColorString类型的Text属性(也就是当用户输入)时会被触发,它将用于检查用户的输入是否正确。
/// <summary>
/// 这个类用于创建带有颜色的文本
/// </summary>
public class ColorString : INotifyPropertyChanged
{
public delegate void TextHelper();
public event TextHelper TextChanged;
/// <summary>
/// 每次对Text修改都会触发事件,检查输入
/// </summary>
public string Text // 文本属性
{
get { return text; }
set
{
text = value;
if (TextChanged != null)
{
TextChanged();
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Text"));
}
}
}
}
2.提供函数注册ColorString成员的事件,当我们修改文件类型和文件名时,程序会检查这些输入是否正确,并给出响应。
private Rename()
{
customName = new ColorString() { Color = ColorString.TextColor.Black, Text = null, Visibility = true };
specifiedType = new ColorString() { Color = ColorString.TextColor.Black, Text = null, Visibility = true };
customName.TextChanged += CheckCustomName;
specifiedType.TextChanged += CheckSpecifiedType;
}
但并不是所有成员都需要注册事件,因为帮助消息和目录路径都需要合法的途径才能修改,所以不需要检查它们。
public FileOperator()
{
message = new ColorString() { Color = ColorString.TextColor.Red, Text = null, Visibility = false };
directoryPath = new ColorString() { Color = ColorString.TextColor.Black, Text = null, Visibility = true };
}
3.接下来我将逐一讲解这些容错算法,并演示它们
首先是对目录路径的判断,由于我把它设置为只能通过Cofd.ShowDialog()修改,不能通过直接在文本框输入来修改,所以我们只需要判断这个目录是否为空即可。如果目录为空,显示消息提醒用户。
/// <summary>
/// 使用CommonOpenFileDialog类打开包含要重命名文件的文件夹
/// </summary>
public void GetTheDirectory()
{
// Add reference from Windows API code pack :
// Microsoft.WindowsAPICodePack
// Microsoft.WindowsAPICodePack.Shell
//
// using Microsoft.WindowsAPICodePack.Dialogs;
// Down Link : http://archive.msdn.microsoft.com/WindowsAPICodePack/Release/ProjectReleases.aspx?ReleaseId=4906#VoteBreakdown
// 这些程序集的安装文件已下载到解决方案中,解压即可用
using (Cofd = new CommonOpenFileDialog())
{
Cofd.IsFolderPicker = true; // true: 文件夹, false: 文件
Cofd.Title = "选择一个文件夹"; // 标题
Cofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); // 初始路径
// 如果成功打开目录
if (Cofd.ShowDialog() == CommonFileDialogResult.Ok)
{
// 为路径赋值
DirectoryPath.Text = Cofd.FileName;
// 检查目录是否为空
CheckTheDirectory();
}
}
}
public void CheckTheDirectory()
{
// 文件夹是否为空
IsInputRightOrWrong(Directory.GetDirectories(DirectoryPath.Text).Length <= 0 && Directory.GetFiles(DirectoryPath.Text).Length <= 0,
string.Format("*提醒:①{0}为空文件夹!", System.IO.Path.GetFileName(DirectoryPath.Text)), ref directoryPath);
}
/// <summary>
/// 根据条件是否正确显示不同的信息
/// </summary>
/// <param name="condition">条件</param>
/// <param name="warning">如果条件正确,将打印消息</param>
/// <param name="input">如果条件正确,用户的输入变为红色</param>
public void IsInputRightOrWrong(bool condition, string warning, ref ColorString input)
{
if (condition)
{
// 显示消息提醒用户
Message.Visibility = true;
Message.Color = ColorString.TextColor.Red;
Message.Text = warning;
// 输入变为红色,提醒用户
input.Color = ColorString.TextColor.Red;
}
else
{
// 输入为黑色
input.Color = ColorString.TextColor.Black;
// 判断其他所有输入都正确
AllGreen();
}
}
演示:
4.接下来是对文件类型输入的判断。在这里我只做了简单的判断:首先输入不能小于2,并且输入的开始必须是"*."
如果用户输入的类型符合上面要求,但实际上不存在这个类型(如*.abcdefg),程序还是会正常执行,最终的结果是当用户单击"一键完成",会提示用户成功重命名0个文件,很明显这不是用户想要的。我很遗憾我只做到了这个地步,因为要与所有的类型作判断需要我花很多的精力去研究,现阶段我只能先放弃,把重点放在其他地方上,如果有人想到更好的算法,请一定联系我,与我分享。
/// <summary>
/// 检查用户输入的文件类型的拼写是否正确,错误将弹出提示
/// </summary>
private void CheckSpecifiedType()
{
// 把输入转换为小写(暂时删除事件确保赋值操作不会造成无限循环)
specifiedType.TextChanged -= CheckSpecifiedType;
specifiedType.Text = specifiedType.Text.ToLower();
specifiedType.TextChanged += CheckSpecifiedType;
// 如果输入小于2或文件类型的拼写不正确
IsInputRightOrWrong(SpecifiedType.Text.Length <= 1 || SpecifiedType.Text.Substring(0, 2) != "*.",
"*提醒:②文件类型的填写格式不正确!", ref specifiedType);
}
5.再来是对输入的文件名的判断,我在这上面花了差不多一天的时间去研究
在上代码前,我先分析一下文件名的构成:文件名必须包含[n1,n2],n1表示文件的起始序号,n2表示序号最小位数,n1的位数小于n2自动用前导0补充。示例:Photo_[1,3]
private int n1, n2; // 代表用户输入的2个参数
private string brackets; // 用于从startLeftParenthesis中截取参数列表
/// <summary>
/// 判断用户的输入是否包含参数列表[n1,n2],如果不包含将弹出提示
/// </summary>
private void CheckCustomName()
{
bool ParameterListFormatIsRight = false; // 代表用户输入的参数列表格式是否正确
string startLeftParenthesis = ""; // 截取一个从‘[’开始到输入结尾的字符串
int indexOfLeftParenthesis = -1; // 左括号的索引
int indexOfRightParenthesis = -1; // 右括号的索引
bool isStringHaveParameterList = false; // 检查是否搜到参数列表(但不保证格式是否正确)
// 搜索第一对括号所在的索引:如果能搜索到‘[',尝试搜索‘]’
if ((indexOfLeftParenthesis = customName.Text.IndexOf('[')) != -1)
{
// 尝试搜索‘]’
indexOfRightParenthesis = customName.Text.Substring(indexOfLeftParenthesis).IndexOf(']');
// 如果搜索到‘]’,isStringHaveParameterList为true
isStringHaveParameterList = indexOfRightParenthesis != -1;
// 截取一个从‘['开始到输入结尾的字符串
startLeftParenthesis = customName.Text.Substring(indexOfLeftParenthesis);
}
#region 如果customName包含参数列表,判断customName是否有包含格式正确的参数列表
while (isStringHaveParameterList == true)
{
// 截取参数列表
brackets = startLeftParenthesis.Substring(0, startLeftParenthesis.IndexOf(']') + 1);
// 把用户可能输入的","改为","(根据用户习惯,废除这项容错功能。用户一般不会在输入'['后输入',',因为这需要切换中英文输入法)
//brackets.Replace(',', ',');
#region 如果参数列表没有","
if (brackets.Contains(',') == false)
{
// 没有",",说明该参数列表不符合规范,搜索下一个参数列表
IsNewStringHaveParameterList(ref startLeftParenthesis, ref indexOfLeftParenthesis, ref indexOfRightParenthesis,
ref isStringHaveParameterList);
continue;
}
#endregion
#region 如果参数列表有",",检查2个参数
else
{
// 截取参数列表第一个参数
string s1 = brackets.Substring(1, brackets.IndexOf(',') - 1);
// 截取参数列表第二个参数
string s2 = brackets.Substring(brackets.IndexOf(',') + 1, brackets.IndexOf(']') - brackets.IndexOf(',') - 1);
// isN1AInt表示第一个参数是否为数字
bool isN1AInt = int.TryParse(s1, out n1);
// isN2AInt表示第二个参数是否为数字
bool isN2AInt = int.TryParse(s2, out n2);
// 如果参数列表包含的不是数字
if (isN1AInt == false || isN2AInt == false)
{
// 该参数列表不符合规范,搜索下一个参数列表
IsNewStringHaveParameterList(ref startLeftParenthesis, ref indexOfLeftParenthesis, ref indexOfRightParenthesis,
ref isStringHaveParameterList);
continue;
}
// 如果参数列表格式完全正确
else
{
// 退出循环
ParameterListFormatIsRight = true;
break;
}
}
#endregion
}
#endregion
// 如果customName不包含格式正确的参数列表,将显示消息提醒用户
IsInputRightOrWrong(ParameterListFormatIsRight == false,
"*提醒:③缺少参数列表或参数列表格式不正确,参数列表是否缺少\",\"或输入了不合法字符?", ref customName);
}
private static void IsNewStringHaveParameterList(ref string startLeftParenthesis,
ref int indexOfLeftParenthesis, ref int indexOfRightParenthesis, ref bool isStringHaveParameterList)
{
// 这个参数列表格式不正确,去掉当前的'[',检查这段字符串
string stringWithOutOldLeftParenthesis = startLeftParenthesis.Substring(1);
// 检查stringWithOutOldLeftParenthesis是否包含'['
indexOfLeftParenthesis = stringWithOutOldLeftParenthesis.IndexOf('[');
// 如果stringWithOutOldLeftParenthesis包含'['
if (indexOfLeftParenthesis != -1)
{
// 更新startLeftParenthesis,以便下次截取
startLeftParenthesis = stringWithOutOldLeftParenthesis.Substring(indexOfLeftParenthesis);
// 尝试搜索']'
indexOfRightParenthesis = startLeftParenthesis.IndexOf(']');
// 判断是否存在参数列表
isStringHaveParameterList = indexOfRightParenthesis != -1;
}
else
{
isStringHaveParameterList = false;
}
}
这里采取的判断是:
经测试容错性能非常好:(这里的测试改为搜索第一个有效参数列表的'['索引,搜索不到返回-1)
容错算法的讲解就到这里。
下一篇文章将讲解Run()的实现。
---------------------- <a href="http://www.itheima.com"target="blank">ASP.Net+Unity开发</a>、<a href="http://www.itheima.com"target="blank">.Net培训</a>、期待与您交流! ----------------------
详细请查看:<a href="http://www.itheima.com" target="blank">www.itheima.com</a>