WPF使用AvalonEdit实现代码高亮显示、搜索、替换功能

news2024/9/22 13:28:06

很多工程软件拥有自己定义的脚本语言,作为程序员用惯了具有高亮显示和智能提示功能的编辑器,所以针对特定的脚本自己开发一个编辑器。主要采用WPF、C#语言以及AvalonEdit控件。

文章目录

    • AvlonEdit控件
    • 实现自定义高亮显示
    • 实现文本搜索
    • 实现文本替换
      • 自定义搜索栏用户控件
      • 实现自定义搜索
      • 实现自定义替换

AvlonEdit控件

AvalonEdit是基于WPF的代码显示控件,可以支持代码高亮显示、智能提示、代码折叠等功能。

AvalonEdit项目官网

在WPF中使用AvalonEdit非常简单,直接Nuget安装,然后引入命名空间xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit",最后直接使用即可<avalonEdit:TextEditor/>。因为本文后面要实现自定义替换,需要对源码进行修改及重新编译,所以最好直接下载源码。

实现自定义高亮显示

AvalonEdit已经内置了C#、C++、Java等常见语言的高亮显示,如果要为自定义的语言进行语法高亮需要写一个*.xshd文件,该文件的基本使用如下:

<?xml version="1.0"?>
<SyntaxDefinition name="Custom Highlighting" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
  <!--设置颜色与文本风格,如粗体,背景色等-->
  <Color name="Comment" foreground="#C6B1B1" exampleText="* comment"/>
  <Color name="Card" fontWeight="bold" foreground="#960092" exampleText="=CSTR"/>
  <Color name="Field" fontWeight="bold" foreground="#3A76D7" exampleText="CA"/>
	<!-- 主要的规则集 -->
	<RuleSet>
    <!--以//开头或者包裹在/*..*/中的文本使用Comment颜色-->
		<Span color="Comment" begin="//" />
		<Span color="Comment" multiline="true" begin="/\*" end="\*/" />
		
		<Span color="String">
			<Begin>"</Begin>
			<End>"</End>
      <!--可以定义规则子集-->
			<RuleSet>
				<Span begin="\\" end="." />
			</RuleSet>
		</Span>
		<!--定义关键词-->
		<Keywords fontWeight="bold" foreground="Blue">
			<Word>if</Word>
			<Word>else</Word>
			<!-- ... -->
		</Keywords>	
		<!-- 可以使用正则进行定义 -->
		<Rule foreground="DarkBlue">
            \b0[xX][0-9a-fA-F]+  # hex number
        |    \b
            (    \d+(\.[0-9]+)?   #number with optional floating point
            |    \.[0-9]+         #or just starting with floating point
            )
            ([eE][+-]?[0-9]+)? # optional exponent
        </Rule>
	</RuleSet>
</SyntaxDefinition>

自定义完*.xshd文件后,一定要设置文件的属性

image-20230203163254312

设置完成后,需要在程序中设置加载

 //注册自定义高亮
 IHighlightingDefinition customHighlighting;
 using (Stream s = typeof(MainWindow).Assembly.GetManifestResourceStream("NotConvertPeps.PEPSHighlighting.xshd"))
 {
     using (XmlReader reader = new XmlTextReader(s))
     {
         customHighlighting = HighlightingLoader.Load(reader, HighlightingManager.Instance);
     }
 }
//要设置一个后缀名字,在这里我设置了fre
 HighlightingManager.Instance.RegisterHighlighting("Custom Highlighting", new string[] { ".fre" }, customHighlighting);

 InitializeComponent();
//在InitializeComponent()之后使用,为txtEdit设置高亮语法
 txtEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".fre");

设置完成后,看下效果

image-20230203163618289

实现文本搜索

AvalonEdit已经具有了搜索功能,新版本只需使用ICSharpCode.AvalonEdit.Search.SearchPanel.Install(txtEditor);便可以使用Ctrl+F调出搜索栏,该搜索栏具有是否忽略大小写、是否全字匹配、是否使用正则三个设置项,而且还有背景显示、下拉框自动下拉等功能,基本满足要求。

1

实现文本替换

很遗憾AvalonEdit没有提供像搜索栏一样的功能,必须自己来实现。

自定义搜索栏用户控件

仿照VS的替换栏进行页面设计

image-20230203164735784

其中注册replaceContent、findContent、CareCase、MatchAll等依赖属性进行绑定,值得注意的是,用户控件在绑定的时候,source要用RelativeSource,否则不能实现数据更新,正确绑定方式如下:

<CheckBox
    x:Name="chxCareCase"
    IsChecked="{Binding CareCase,RelativeSource={RelativeSource AncestorType=local:ReplaceControl}}"
    Template="{StaticResource ToggleButtonControlTemplate2}"
    ToolTip="区分大小写" />

实现自定义搜索

因为替换操作仍然需要先查询再替换,所以需要自定义实现搜索。实现思路可以是得到textEditor中的text,然后使用string.index等方法进行,但是这样太麻烦,而且还需要自定义搜索结果的背景高亮以及文本选择。所以要换个思路,因为AvalonEdit已经提供了搜索功能,所以一定会有相关的接口,与查询有关的代码都存在于ICSharpCode.AvalonEdit.Search命名空间下,主要的查询方法存在于ICSharpCode.AvalonEdit.Search.SearchPanel中,其中最关键的查询方法是SearchStrategyFactory.Create(SearchPattern, !MatchCase, WholeWords, UseRegex ? SearchMode.RegEx : SearchMode.Normal);

除了该方法外,我们还需要进行上一个和下一个搜索以及搜索结果的背景高亮显示,这都和SearchResultBackgroundRenderer类相关,但是AvalonEdit官方源码中,该类的访问权限是Private,所以需要将访问权限改为public,然后重新编译。

实现自定义搜索功能C#代码

SearchResultBackgroundRenderer renderer = new SearchResultBackgroundRenderer();
void DoFind()
{
    renderer.CurrentResults.Clear();//清空已经搜索出的结果
    if (!string.IsNullOrEmpty(replaceUserControl.findContent))
    {
        //文字的背景高亮
        textArea.TextView.BackgroundRenderers.Clear();
        textArea.TextView.BackgroundRenderers.Add(renderer);
        //搜索的管件方法
        ISearchStrategy strategy = SearchStrategyFactory.Create(replaceUserControl.findContent, !replaceUserControl.CareCase, replaceUserControl.MatchAll, replaceUserControl.regex ? SearchMode.RegEx : SearchMode.Normal);
        var results = strategy.FindAll(textArea.Document, 0, textArea.Document.TextLength);
        //将搜索的结果全部加到renderer.CurrentResults中,方便后续的进行上一个、下一个搜索的展示
        foreach (SearchResult result in results)
        {
            renderer.CurrentResults.Add(result);
        }
    }
}

实现下一个

private void FindNext(object sender, RoutedEventArgs e)
{
    DoFind();
    
    SearchResult result = renderer.CurrentResults.FindFirstSegmentWithStartAfter(textArea.Caret.Offset + 1);
    if (result == null)
        result = renderer.CurrentResults.FirstSegment;
    if (result != null)
    {
        SelectResult(result);
    }
}

实现上一个

private void FindPre(object sender, RoutedEventArgs e)
{
    DoFind();
    SearchResult result = renderer.CurrentResults.FindFirstSegmentWithStartAfter(textArea.Caret.Offset);
    if (result != null)
        result = renderer.CurrentResults.GetPreviousSegment(result);
    if (result == null)
        result = renderer.CurrentResults.LastSegment;
    if (result != null)
    {
        SelectResult(result);
    }
}

实现效果

2

实现自定义替换

AvalonEdit提供了Document.Replace方法,可以直接使用

private void ReplaceNext(object sender, RoutedEventArgs e)
{
    string replace = replaceUserControl.replaceContent;
    DoFind();
    SearchResult result = renderer.CurrentResults.FindFirstSegmentWithStartAfter(textArea.Caret.Offset + 1);
    if (result == null)
        result = renderer.CurrentResults.FirstSegment;
    if (result != null)
    {
        SelectResult(result);
        this.txtEditor.Document.Replace(result.StartOffset, result.Length, replace);
        DoFind();//必须调用一次,不然查询出的字段背景色会乱
    }
}

img

文章目录

    • AvlonEdit控件
    • 实现自定义高亮显示
    • 实现文本搜索
    • 实现文本替换
      • 自定义搜索栏用户控件
      • 实现自定义搜索
      • 实现自定义替换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/196346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

磁疗效果因“病”而异,坚持=胜利!

磁疗在我国具有悠久的历史早在春秋战国时期&#xff0c;就有神医扁鹊运用磁疗治病的记载。 北京军区总医院理疗科主任&#xff0c;中华生物磁学研究会秘书长周万松认为&#xff0c;关于磁场改善血液循环这一点是肯定的&#xff0c;磁场可以扩张血管、加速血流、改善血液循环。但…

【H5游戏】-整一个简单的解压小游戏【抽纸巾】

专栏简介 &#x1f492;个人主页 &#x1f4f0;专栏目录 点击上方查看更多内容 &#x1f4d6;心灵鸡汤&#x1f4d6;社会不相信庸俗&#xff0c;成功需要汗水和寂寞铸就。无数次的质疑或是嘲笑&#xff0c;这些都无所谓&#xff0c;记住自己是谁&#xff0c;自己想要什么就…

Django的信号机制解读

Django的信号 Django的信号机制不同于Linux的信号机制&#xff0c;Django 中的信号用于在框架执行操作时解耦。当某些动作发生的时候&#xff0c;系统会根据信号定义的函数执行相应的操作 Django的信号主要包含以下三个要素&#xff1a; 发送者&#xff08;sender&#xff0…

网络隔离后的文件传输怎么解决?深度解析4种主流方案

网络隔离对于很多企业来说并不陌生&#xff0c;出于数据安全的考虑&#xff0c;为了隔离有害的网络和可能的网络攻击&#xff0c;越来越多的企业在内部进行了网络隔离。隔离的形态和方式有多种&#xff0c;总体上主要以物理隔离和逻辑隔离为主。网络隔离可以一定程度上甚至彻底…

功能测试环境搭建

前言新年好呀大家&#xff0c;大家都复工了吗~小编已经在搬砖中了&#x1f636;在假期中小编学习了一点功能测试方面知识&#xff0c;打算写篇博客记录下来&#xff0c;希望这篇博客可以帮到需要的朋友。流程图一、测试计划测试计划需要在所有的测试工作之前进行&#xff0c;一…

HTTP协议(2)

1)当我们在浏览器上面输入一个搜狗搜索的网址之后&#xff0c;浏览器就会给搜狗的服务器发送了一个HTTP请求&#xff0c;这样咱们的搜狗的服务器就会返回一个HTTP响应&#xff1b; 2)当这个响应结果被浏览器解析之后&#xff0c;就展示成了我们目前所看到的页面内容&#xff0c…

20230203英语学习

What Is a Dog Anyway? 狗的争议性起源&#xff1a;到底怎么定义“狗” The geographer Jared Diamond has called domestication the worst mistake humans ever made. And yet, the first domestication — the turning of wolves into dogs — was an impressive feat.Hu…

java对象的比较

上一章中关于PriorityQueue的使用要注意&#xff1a; 1. PriorityQueue中放置的元素必须要能够比较大小&#xff0c;不能插入无法比较大小的对象&#xff0c;否则会抛出 ClassCastException异常 2. 不能插入null对象&#xff0c;否则会抛出NullPointerException 3. 没有容量限制…

C/C++ 内存泄漏检测

C/C 内存泄漏检测内存泄漏的两个问题使用宏定义覆盖 malloc 和 free 函数使用 hook 钩子最近学习了 C/C 内存泄漏检测的相关知识&#xff0c;写博客记录一下。 内存泄漏的两个问题 是否有内存泄漏&#xff1f;内存泄漏是在代码的哪一行&#xff1f; 检测内存泄漏主要从上面两…

数据库系统概念 | 第十三章:事务管理 | 事务特性(ACID)| 冲突可串行化

文章目录&#x1f4da;事务的概念&#x1f407;事务定义&#x1f407;事务界定&#x1f407;事务特性&#xff08;ACID&#xff09;&#x1f407;一个简单的事务模型&#x1f4da;存储器结构&#x1f4da;事务的原子性和持久性&#x1f407;几种常见的事务状态&#x1f407;事务…

MDA260-16-ASEMI整流模块MDA260-16

编辑-Z MDA260-16在MDA封装里采用的2个芯片&#xff0c;是一款单臂共阳极整流模块。MDA260-16的浪涌电流Ifsm为11000A&#xff0c;漏电流(Ir)为15mA&#xff0c;其工作时耐温度范围为-40~150摄氏度。MDA260-16采用GPP硅芯片材质&#xff0c;里面有2颗芯片组成。MDA260-16的电性…

转行大数据开发应该怎么学习

转行进入大数据&#xff0c;首先需要了解的就是大数据是做什么&#xff0c;工作内容&#xff0c;然后就是找个完整的学习路线跟着去学习了&#xff0c;大数据的学习内容也是不少的~ 简单来说&#xff0c;分为6步&#xff0c;大数据开发入门&#xff0c;大数据核心基础&#xf…

【iHooya】2023年2月2日寒假作业解析

#include <bits/stdc.h> using namespace std;int main() {int n, r; //n个人&#xff0c;r个水龙头cin >> n >> r;int time[n];for (int a 0; a < n; a){cin >> time[a];}sort(time, time n); //时间从小到大排序int minx 0, lt_time[10001], j…

程序全过程:觉醒(序)

程序全过程序很惭愧&#xff0c;写了几年的程序&#xff0c;技术的功力没有太大增长&#xff0c;只是在项目的熟悉程度上有不少进步。因为上学时没好好学&#xff0c;很多现在工作中用到的编程技能都是在工作中边学边用的&#xff0c;相当于一直处于临时抱佛脚的状态&#xff0…

iptables端口复用

环境&#xff1a; 攻击主机&#xff1a;Kali -- 192.168.218.135 目标主机&#xff1a;RHEL8 -- 192.168.218.129 什么是端口复用 端口复用是指不同的应用程序使用相同端口使用相同端口进行通讯。 场景 目标主机是Linux系统&#xff0c;目标主机防火墙有严格的限制&#…

【FAQ】申请运动健康服务验证环节常见问题及解答

华为 HMS Core 运动健康服务&#xff08;HUAWEI Health Kit&#xff09;提供原子化数据开放。应用在获取用户数据授权后&#xff0c;可通过接口访问运动健康数据&#xff0c;对用户数据进行读写等操作&#xff0c;为用户提供运动健康类数据服务。 开发者应用在开发和测试阶段访…

SGI STL二级空间配置器源码剖析(2)

接着上回&#xff0c;这节开始说allocte内存分配的实现 目录 allocate源码流程&#xff1a; _S_refill 的实现&#xff1a; _S_chunk_alloc的实现&#xff1a; deallocate&#xff1a; reallocate&#xff1a; 二级空间配置器的逻辑步骤&#xff1a;假如现在申请n个字节&…

选择计算机专业,必看的10条自学建议

选择了计算机专业&#xff0c;很迷茫&#xff0c;没事&#xff01;&#xff01;博主整理了关于学习计算机的十条自学经验&#xff0c;从各个方面阐述了如何学习计算机专业。 1、学会使用Google搜索&#xff0c;放弃百度&#xff0c;你会发现Google 会搜出更多有用的答察&#x…

车规级MCU缺货持续2年多,上海航芯持续加码市场

MCU是传统燃油车的重要芯片之一&#xff0c;在电动车领域&#xff0c;MCU也有着广泛的应用&#xff0c;且随着汽车电子化的持续发展&#xff0c;车用MCU的市场规模还将随之持续扩大&#xff0c;据 IC insights 数据显示&#xff0c;至2026年&#xff0c;全球车规级MCU的市场规模…

C++——函数重载,引用

✅<1>主页&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;C &#x1f525;<3>创作者&#xff1a;我的代码爱吃辣 ☂️<4>开发环境&#xff1a;Visual Studio 2022 &#x1f4ac;<5>前言&#xff1a;补充C语言语法的不足&#…