博客
关于我
基于异步方式的语法着色器
阅读量:572 次
发布时间:2019-03-11

本文共 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(List
fileList) { 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 List
LoadFileByName() { 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             List
list = 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/

你可能感兴趣的文章
记录-基于springboot+vue.js实现的超大文件分片极速上传及流式下载
查看>>
JavaScript高级程序设计第四版学习记录-第九章代理与反射
查看>>
怎么解决Windows 10文件/文件夹正在使用无法删除
查看>>
F28335第九篇——通用IO
查看>>
STM32F429第十一篇之数据类型
查看>>
web项目开发记录
查看>>
matlab函数:sprintf详解
查看>>
matlab函数:fix 向0取整
查看>>
ORCAD创建元件库时,格点对不起怎么办
查看>>
Allegro中如何消除器件本身Pin间距报错
查看>>
AD中拖动器件,无法移动在一起如何解决
查看>>
linux--练习001-基础类型
查看>>
python内存地址和编译字节码
查看>>
Flask--简介
查看>>
Flask模板--过滤器与测试器
查看>>
16 python基础-恺撒密码
查看>>
06.1 python基础--结构控制
查看>>
Frame--Api框架
查看>>
Frame--WEB框架
查看>>
idea 在Debug 模式中运行语句中函数的方法
查看>>