本文共 7810 字,大约阅读时间需要 26 分钟。
首先说明一下,我这里的异步方式是指获取代码文件的时候,采用的是异步方式,其原因就是我要搜索C:\Program Files文件夹下面的含有关键字为scyGroupBox的代码文件。那么,从我的描述就可以知道,这是一个相当费时的操作,而如果利用程序来遍历这个文件夹,其结果就是将要耗费数秒钟或者更长的时间,并且同步操作会导致界面在搜索完毕后才出来,这样用户就不得不等待几秒钟甚至是数十秒钟,这种体验是相当不友好的。
那么如何解决这种方式呢?
其实,利用委托方式结合其BeginInvoke和EndInvoke方法,可以先显示出界面,然后再加载搜索结果,这样一来,就大大提高了用户体验,具体方式如下:
在程序中,我需要将搜索到的代码文件加载到ListView控件中显示出来,这样就需要有一个函数来添加ListViewItem,代码文件如下:
////// filter the filename from some files and attach them to ListView control /// /// public void LoadFileIntoForm(ListfileList) { List myFiles = fileList; AddListViewCrossThreads(null,deleteFlag); // remove all the items for (int i = 0; i < myFiles.Count; i++) { FileInfo file = myFiles[i]; ListViewItem lvi = new ListViewItem(); lvi.Text = GetFileName.GetFileName(file.FullName); lvi.Tag = file.FullName; // store the fullname AddListViewCrossThreads(lvi,addFlag); } }
而我们读取那个耗时的代码文件的函数如下:
////// this function is the target to make async. /// because it takes a long time to load. /// ///public List LoadFileInfoAsync() { return LoadFiles.LoadFileByName(); }
需要注意的是,这个LoadFileInfoAsync函数需要耗费数秒甚至是数十秒来搜索文件,其具体实现如下:
public ListLoadFileByName() { string keyWords = "scyGroupBox"; // file name contains words string searchPath = @"C:\Program Files\"; // file path DirectoryInfo directory = new DirectoryInfo(searchPath); var result = from p in directory.GetFiles("*.cs",SearchOption.AllDirectories).ToList() where p.Name.Contains(keyWords) select p; List files = result.ToList(); // transfer filenames into list collection return files; // return the result }
其中SearchOption.AllDirectories表明搜索父文件夹下的子文件夹。
如何对LoadFileByName函数实现异步操作呢?
这个需要定义个委托,用委托来对这个函数进行异步操作:
////// this is the Begin Invoke method /// public void InvokeListView() { //delegate the funtion that perform long running operation AddListViewDelegate asyncAdd = new AddListViewDelegate(LoadFileInfoAsync); //start to load the funtion asynchorous., GetFileInfoResult is the end process IAsyncResult iar = asyncAdd.BeginInvoke(new AsyncCallback(GetFileInfoResult), asyncAdd); //perform loading notification AddListViewCrossThreads(AddNotification(),addFlag); }
利用Delegate的BeginInvoke可以实现异步操作,在异步操作的过程中,我们可以向用户显示提示信息,比如说“正在加载,请稍等….”,这样能达到一种比较好的用户体验,至于这种提示信息,我们在函数AddNotification中实现:
////// add the loading notification /// ///public ListViewItem AddNotification() { ListViewItem lvi = new ListViewItem(); lvi.Text = "Loading now, please wait..."; lvi.Tag = 1; return lvi; }
但是现在遇到一个比较严重的问题,由于采用了异步,导致线程和界面发生了交互,这样就会产生exception,怎么解决呢,当然是利用Invoke方式来判断当前界面控件是否需要线程交互,如果需要,则利用委托方式来进行调用:
////// used to avoid the cross threads exception /// ///listview item ///0:add 1:delete public void AddListViewCrossThreads(ListViewItem lvi,int action) { if (lsvName.InvokeRequired) { AddListViewCrossThreadDelegate addlistviewdelegate = new AddListViewCrossThreadDelegate(AddListViewCrossThreads); lsvName.Invoke(addlistviewdelegate, lvi,action); } else { if (addFlag == action) { this.lsvName.Items.Add(lvi); } else if (deleteFlag == action) { this.lsvName.Items.Clear(); } } }
这样当异步进行完毕,我们就可以还原异步对象为当前代理对象,然后获取返回值了。
////// Invoke Async Complete /// /// public void GetFileInfoResult(IAsyncResult iar) { AddListViewDelegate asyncAdd = (AddListViewDelegate)iar.AsyncState; // get the operation object Listlist = asyncAdd.EndInvoke(iar); // get the async result LoadFileIntoForm(list); // add the ListViewItem result to ListView control }
-----------------------------------------------------华丽的分割线--------------------------------------------------------
下面来说语法高亮,这个主要是采用了正则表达式,由于我写的不太完整,还请见谅,下面是主要代码,需要注意的是,在代码着色过程中,需要涉及到懒惰匹配法,意思就是最小匹配。需要用到(?i)来实现:
public static void RichTextBoxEx(this RichTextBox richTextBox,string input) { richTextBox.Text = input; input = input.Replace("\r\n","~"); //注意,\r\n会被认为是4字节,其实他只是一个字节,所以替换为一个字符来表示 //匹配关键字 string regexGrammer = @"using|namespace| public|partial| class|private|protected| if|else| int|string|double| return|override|void|this|null|virtual"; MatchCollection mc = GetMatchedValue(regexGrammer, input); foreach (Match match in mc) { int length = match.Length; int index = match.Index; richTextBox.Select(index, length); richTextBox.SelectionColor = Color.Blue; } //匹配对象 string classGrammer = @"color|GraphicsPath|rectangle|Graphics|pen|LinearGradientBrush"; MatchCollection classMc = GetMatchedValue(classGrammer,input); foreach (Match match in classMc) { int length = match.Length; int index = match.Index; richTextBox.Select(index, length); richTextBox.SelectionColor = Color.FromArgb(43,145,175); } //匹配注释符号-->//这里使用了懒惰匹配(?i) string commentGrammer = @"(?i)\//.*?~"; MatchCollection commentMC = GetMatchedValue(commentGrammer,input); foreach (Match match in commentMC) { int length = match.Length; int index = match.Index; richTextBox.Select(index, length); richTextBox.SelectionColor = Color.Green; } //匹配#号 string regionGrammer = @"(?i)\#.*?~"; MatchCollection regionMC = GetMatchedValue(regionGrammer, input); foreach (Match match in regionMC) { int length = match.Length; int index = match.Index; richTextBox.Select(index, length); Font f = new Font(new Font("宋体",12), FontStyle.Bold); richTextBox.SelectionFont = f; } //匹配数字 string digitGrammer = "[0-9]"; MatchCollection digitMC = GetMatchedValue(digitGrammer, input); foreach (Match match in digitMC) { int length = match.Length; int index = match.Index; richTextBox.Select(index, length); richTextBox.SelectionColor = Color.Red; } } private static MatchCollection GetMatchedValue(string grammer,string input) { Regex digitRegex = new Regex(grammer, RegexOptions.IgnoreCase | RegexOptions.Singleline); MatchCollection matchCollection = digitRegex.Matches(input); return matchCollection; }
好了,介绍到这里,基本上就完了,附上效果图:
转载地址:http://eflvz.baihongyu.com/