当前位置:网站首页 / WPF / 正文

ay wpf avalonedit【2/3】

时间:2022年02月14日 | 作者 : aaronyang | 分类 : WPF | 浏览: 444次 | 评论 0

验证xml,把当前的xml内容用XmlDocument. Load 加载文本,报的异常来验证xml

https://github.com/ay2015/avaedit/


效果图

image.png


下面2个接口,对文字背景修改,一个应该是线

IBackgroundRenderer, IVisualLineTransformer

定义一个外观的文本块,继承TextSegment

 public sealed class TextMarker : TextSegment
        {
            public TextMarker(int startOffset, int length)
            {
                StartOffset = startOffset;
                Length = length;
            }

            public Color? BackgroundColor { get; set; }
            public Color MarkerColor { get; set; }
            public string ToolTip { get; set; }
        }
 public sealed class TextMarker : TextSegment
    {
        public TextMarker(int startOffset, int length)
        {
            StartOffset = startOffset;
            Length = length;
        }

        public Color? BackgroundColor { get; set; }
        public Color MarkerColor { get; set; }
        public string ToolTip { get; set; }
    }

    public class TextMarkerService : IBackgroundRenderer, IVisualLineTransformer
    {
        private readonly TextEditor textEditor;
        private readonly TextSegmentCollection<TextMarker> markers;

        public TextMarkerService(TextEditor textEditor)
        {
            this.textEditor = textEditor;
            markers = new TextSegmentCollection<TextMarker>(textEditor.Document);
        }

        public void Draw(TextView textView, DrawingContext drawingContext)
        {
            if (markers == null || !textView.VisualLinesValid)
            {
                return;
            }
            var visualLines = textView.VisualLines;
            if (visualLines.Count == 0)
            {
                return;
            }
            int viewStart = visualLines.First().FirstDocumentLine.Offset;
            int viewEnd = visualLines.Last().LastDocumentLine.EndOffset;
            foreach (TextMarker marker in markers.FindOverlappingSegments(viewStart, viewEnd - viewStart))
            {
                if (marker.BackgroundColor != null)
                {
                    var geoBuilder = new BackgroundGeometryBuilder { AlignToWholePixels = true, CornerRadius = 3 };
                    geoBuilder.AddSegment(textView, marker);
                    Geometry geometry = geoBuilder.CreateGeometry();
                    if (geometry != null)
                    {
                        Color color = marker.BackgroundColor.Value;
                        var brush = new SolidColorBrush(color);
                        brush.Freeze();
                        drawingContext.DrawGeometry(brush, null, geometry);
                    }
                }
                foreach (Rect r in BackgroundGeometryBuilder.GetRectsForSegment(textView, marker))
                {
                    Point startPoint = r.BottomLeft;
                    Point endPoint = r.BottomRight;

                    var usedPen = new Pen(new SolidColorBrush(marker.MarkerColor), 1);
                    usedPen.Freeze();
                    const double offset = 2.5;

                    int count = Math.Max((int)((endPoint.X - startPoint.X) / offset) + 1, 4);

                    var geometry = new StreamGeometry();

                    using (StreamGeometryContext ctx = geometry.Open())
                    {
                        ctx.BeginFigure(startPoint, false, false);
                        ctx.PolyLineTo(CreatePoints(startPoint, endPoint, offset, count).ToArray(), true, false);
                    }

                    geometry.Freeze();

                    drawingContext.DrawGeometry(Brushes.Transparent, usedPen, geometry);
                    break;
                }
            }
        }

        public KnownLayer Layer
        {
            get { return KnownLayer.Selection; }
        }

        public void Transform(ITextRunConstructionContext context, IList<VisualLineElement> elements)
        { }

        private IEnumerable<Point> CreatePoints(Point start, Point end, double offset, int count)
        {
            for (int i = 0; i < count; i++)
            {
                yield return new Point(start.X + (i * offset), start.Y - ((i + 1) % 2 == 0 ? offset : 0));
            }
        }

        public void Clear()
        {
            foreach (TextMarker m in markers)
            {
                Remove(m);
            }
        }

        private void Remove(TextMarker marker)
        {
            if (markers.Remove(marker))
            {
                Redraw(marker);
            }
        }

        private void Redraw(ISegment segment)
        {
            textEditor.TextArea.TextView.Redraw(segment);
        }

        public void Create(int offset, int length, string message)
        {
            var m = new TextMarker(offset, length);
            markers.Add(m);
            m.MarkerColor = Colors.Red;
            m.ToolTip = message;
            Redraw(m);
        }

        public IEnumerable<TextMarker> GetMarkersAtOffset(int offset)
        {
            return markers == null ? Enumerable.Empty<TextMarker>() : markers.FindSegmentsContaining(offset);
        }
    }



新建一个用户控件AvaEditor.xaml

前台代码

<UserControl x:Class="avaedit.AvaEditor"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:avaedit"
             mc:Ignorable="d"   xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.CommandBindings>
        <CommandBinding Command="local:AvaEditor.ValidateCommand" Executed="Validate"/>
    </UserControl.CommandBindings>
    <Grid>
        <avalonEdit:TextEditor  x:Name="textEditor" SyntaxHighlighting="XML" ShowLineNumbers="True" >
            <avalonEdit:TextEditor.ContextMenu>
                <ContextMenu>
                    <MenuItem Command="Undo" />
                    <MenuItem Command="Redo" />
                    <Separator/>
                    <MenuItem Command="Cut" />
                    <MenuItem Command="Copy" />
                    <MenuItem Command="Paste" />
                    <Separator/>
                    <MenuItem Command="local:AvaEditor.ValidateCommand" />
                </ContextMenu>
            </avalonEdit:TextEditor.ContextMenu>
        </avalonEdit:TextEditor>
    </Grid>
</UserControl>


后台代码:

  public partial class AvaEditor : UserControl
    {

        private static readonly ICommand validateCommand = new RoutedUICommand("验证XML", "Validate", typeof(AvaEditor),
       new InputGestureCollection { new KeyGesture(Key.V, ModifierKeys.Control | ModifierKeys.Shift) });

        public static ICommand ValidateCommand
        {
            get { return validateCommand; }
        }

        public AvaEditor()
        {
            InitializeComponent();
            Loaded += AvaEditor_Loaded;
        }

        private ToolTip toolTip;
        private TextMarkerService textMarkerService;

        private void AvaEditor_Loaded(object sender, RoutedEventArgs e)
        {
            Loaded -= AvaEditor_Loaded;


            textMarkerService = new TextMarkerService(textEditor);
            var textView = textEditor.TextArea.TextView;
            textView.BackgroundRenderers.Add(textMarkerService);
            textView.LineTransformers.Add(textMarkerService);
            textView.Services.AddService(typeof(TextMarkerService), textMarkerService);

            textView.MouseHover += MouseHover;
            textView.MouseHoverStopped += TextEditorMouseHoverStopped;
            textView.VisualLinesChanged += VisualLinesChanged;
        }

        private void MouseHover(object sender, MouseEventArgs e)
        {
            var pos = textEditor.TextArea.TextView.GetPositionFloor(e.GetPosition(textEditor.TextArea.TextView) + textEditor.TextArea.TextView.ScrollOffset);
            bool inDocument = pos.HasValue;
            if (inDocument)
            {
                TextLocation logicalPosition = pos.Value.Location;
                int offset = textEditor.Document.GetOffset(logicalPosition);

                var markersAtOffset = textMarkerService.GetMarkersAtOffset(offset);
                TextMarker markerWithToolTip = markersAtOffset.FirstOrDefault(marker => marker.ToolTip != null);

                if (markerWithToolTip != null)
                {
                    if (toolTip == null)
                    {
                        toolTip = new ToolTip();
                        toolTip.Closed += ToolTipClosed;
                        toolTip.PlacementTarget = this;
                        toolTip.Content = new TextBlock
                        {
                            Text = markerWithToolTip.ToolTip,
                            TextWrapping = TextWrapping.Wrap
                        };
                        toolTip.IsOpen = true;
                        e.Handled = true;
                    }
                }
            }
        }

        void ToolTipClosed(object sender, RoutedEventArgs e)
        {
            toolTip = null;
        }

        void TextEditorMouseHoverStopped(object sender, MouseEventArgs e)
        {
            if (toolTip != null)
            {
                toolTip.IsOpen = false;
                e.Handled = true;
            }
        }

        private void VisualLinesChanged(object sender, EventArgs e)
        {
            if (toolTip != null)
            {
                toolTip.IsOpen = false;
            }
        }

        private void Validate(object sender, ExecutedRoutedEventArgs e)
        {
            IServiceProvider sp = textEditor;
            var markerService = (TextMarkerService)sp.GetService(typeof(TextMarkerService));
            markerService.Clear();

            try
            {
                var document = new XmlDocument { XmlResolver = null };
                document.LoadXml(textEditor.Document.Text);
            }
            catch (XmlException ex)
            {
                DisplayValidationError(ex.Message, ex.LinePosition, ex.LineNumber);
            }
        }

        private void DisplayValidationError(string message, int linePosition, int lineNumber)
        {
            if (lineNumber >= 1 && lineNumber <= textEditor.Document.LineCount)
            {
                int offset = textEditor.Document.GetOffset(new TextLocation(lineNumber, linePosition));
                int endOffset = TextUtilities.GetNextCaretPosition(textEditor.Document, offset, System.Windows.Documents.LogicalDirection.Forward, CaretPositioningMode.WordBorderOrSymbol);
                if (endOffset < 0)
                {
                    endOffset = textEditor.Document.TextLength;
                }
                int length = endOffset - offset;

                if (length < 2)
                {
                    length = Math.Min(2, textEditor.Document.TextLength - offset);
                }

                textMarkerService.Create(offset, length, message);
            }
        }
    }



然后找一个页面使用下就行了

  <local:AvaEditor Grid.Row="1"/>


加个背景色

 public void Create(int offset, int length, string message)
        {
            var m = new TextMarker(offset, length);
            markers.Add(m);
            m.MarkerColor = Colors.Red;
            m.BackgroundColor = Colors.Yellow;
            m.ToolTip = message;
            Redraw(m);
        }

image.png


自定义高亮规则

官方示例

<SyntaxDefinition name="Custom Highlighting" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
	<Color name="Comment" foreground="#FF00FF" />
	<Color name="String" foreground="Blue" />
	
	<!-- This is the main ruleset. -->
	<RuleSet>
		<Span color="Comment" begin="//" />
		<Span color="Comment" multiline="true" begin="/\*" end="\*/" />
		
		<Span color="String">
			<Begin>"</Begin>
			<End>"</End>
			<RuleSet>
				<!-- nested span for escape sequences -->
				<Span begin="\\" end="." />
			</RuleSet>
		</Span>
		
		<Keywords fontWeight="bold" foreground="Blue">
			<Word>if</Word>
			<Word>else</Word>
			<!-- ... -->
		</Keywords>
		
		<Keywords fontWeight="bold" fontStyle="italic" foreground="Red">
			<Word>AvalonEdit</Word>
		</Keywords>
		
		<!-- Digits -->
		<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>

给颜色取名字,下方定义规则


下面定义个lua的高亮规则

新建个txt,改名字lua.xshd  文件类型改为 嵌入的资源,你也可以是资源,主要嵌入到程序还能读取xml内容

<?xml version="1.0"?>
<SyntaxDefinition name="SharpLua" extensions=".slua;.lua" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
	<!-- The named colors 'Comment' and 'String' are used in SharpDevelop to detect if a line is inside a multiline string/comment -->
	<Color name="Comment" foreground="#ff999999" exampleText="-- comment" />
	<Color name="String" foreground="#fff99157" />
	<Color name="Punctuation" />
	<Color name="MethodCall" foreground="#ffffcc66" fontWeight="bold"/>
	<Color name="NumberLiteral" foreground="#ff99cc99"/>
	<Color name="NilKeyword" fontWeight="bold"/>
	<Color name="Keywords" fontWeight="bold" foreground="#ff6699cc" />
	<Color name="GotoKeywords" foreground="#ffcc99cc" />
	<Color name="Visibility" fontWeight="bold" foreground="#fff99157"/>
	<Color name="TrueFalse" fontWeight="bold" foreground="#ff66cccc" />

	<RuleSet name="CommentMarkerSet">
		<Keywords fontWeight="bold" foreground="#fff2777a">
			<Word>TODO</Word>
			<Word>FIXME</Word>
		</Keywords>
		<Keywords fontWeight="bold" foreground="#fff2777a">
			<Word>HACK</Word>
			<Word>UNDONE</Word>
		</Keywords>
	</RuleSet>

	<!-- This is the main ruleset. -->
	<RuleSet>

		<Span color="Comment">
			<Begin color="XmlDoc/DocComment">---</Begin>
			<RuleSet>
				<Import ruleSet="XmlDoc/DocCommentSet"/>
				<Import ruleSet="CommentMarkerSet"/>
			</RuleSet>
		</Span>


		<Span color="Comment" ruleSet="CommentMarkerSet" multiline="true">
			<Begin>--\[[=]*\[</Begin>
			<End>\][=]*]</End>
		</Span>


		<Span color="Comment" ruleSet="CommentMarkerSet">
			<Begin>--</Begin>
		</Span>

		<Span color="String">
			<Begin>"</Begin>
			<End>"</End>
			<RuleSet>
				<!-- span for escape sequences -->
				<Span begin="\\" end="."/>
			</RuleSet>
		</Span>

		<Span color="String">
			<Begin>'</Begin>
			<End>'</End>
			<RuleSet>
				<!-- span for escape sequences -->
				<Span begin="\\" end="."/>
			</RuleSet>
		</Span>

		<Span color="String" multiline="true">
			<Begin color="String">\[[=]*\[</Begin>
			<End>\][=]*]</End>
		</Span>

		<Keywords color="TrueFalse">
			<Word>true</Word>
			<Word>false</Word>
		</Keywords>

		<Keywords color="Keywords">
			<Word>and</Word>
			<Word>break</Word>
			<Word>do</Word>
			<Word>else</Word>
			<Word>elseif</Word>
			<Word>end</Word>
			<Word>false</Word>
			<Word>for</Word>
			<Word>function</Word>
			<Word>if</Word>
			<Word>in</Word>
			<Word>local</Word>
			<!--<Word>nil</Word>-->
			<Word>not</Word>
			<Word>or</Word>
			<Word>repeat</Word>
			<Word>return</Word>
			<Word>then</Word>
			<Word>true</Word>
			<Word>until</Word>
			<Word>while</Word>
			<Word>using</Word>
			<Word>continue</Word>
		</Keywords>

		<Keywords color="GotoKeywords">
			<Word>break</Word>
			<Word>return</Word>
		</Keywords>

		<Keywords color="Visibility">
			<Word>local</Word>
		</Keywords>

		<Keywords color="NilKeyword">
			<Word>nil</Word>
		</Keywords>

		<!-- Mark previous rule-->
		<Rule color="MethodCall">
			\b
			[\d\w_]+  # an identifier
			(?=\s*\() # followed by (
		</Rule>
		<Rule color="MethodCall">
			\b
			[\d\w_]+  # an identifier
			(?=\s*\") # followed by "
		</Rule>
		<Rule color="MethodCall">
			\b
			[\d\w_]+  # an identifier
			(?=\s*\') # followed by '
		</Rule>
		<Rule color="MethodCall">
			\b
			[\d\w_]+  # an identifier
			(?=\s*\{) # followed by {
		</Rule>
		<Rule color="MethodCall">
			\b
			[\d\w_]+  # an identifier
			(?=\s*\[) # followed by [
		</Rule>

		<!-- Digits -->
		<Rule color="NumberLiteral">
			\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>

		<Rule color="Punctuation">
			[?,.;()\[\]{}+\-/%*&lt;&gt;^+~!|&amp;]+
		</Rule>
	</RuleSet>
</SyntaxDefinition>

然后在后台找个loaded的地方指定SyntaxHighlighting属性

  string name = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + ".lua.xshd";
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            using (System.IO.Stream s = assembly.GetManifestResourceStream(name))
            {
                using (XmlTextReader reader = new XmlTextReader(s))
                {
                    var xshd = HighlightingLoader.LoadXshd(reader);
                    textEditor.SyntaxHighlighting = HighlightingLoader.Load(xshd, HighlightingManager.Instance);
                }
            }

运行后,粘贴lua代码

image.png

-- 以只读方式打开文件
file = io.open("test.lua", "r")

-- 设置默认输入文件为 test.lua
io.input(file)

-- 输出文件第一行
print(io.read())

-- 关闭打开的文件
io.close(file)

-- 以附加的方式打开只写文件
file = io.open("test.lua", "a")

-- 设置默认输出文件为 test.lua
io.output(file)

-- 在文件最后一行添加 Lua 注释
io.write("--  test.lua 文件末尾注释")

-- 关闭打开的文件
io.close(file)


image.png

你也可以设置文件为资源

        using (XmlTextReader xmlTextReader = new XmlTextReader(Application.GetResourceStream(new Uri("pack://application:,,,/avaedit;component/lua.xshd")).Stream))

            {

                textEditor.SyntaxHighlighting = HighlightingLoader.Load(xmlTextReader, HighlightingManager.Instance);

            }


加载文件textEditor.Load(filename);


官方写法,可以给个名字,注册文件后缀和 高亮规则,那么就可以直接指定这个名字了,而不是传递一些 高亮规则的xml

			IHighlightingDefinition customHighlighting;
			using (Stream s = typeof(Window1).Assembly.GetManifestResourceStream("AvalonEdit.Sample.CustomHighlighting.xshd")) {
				if (s == null)
					throw new InvalidOperationException("Could not find embedded resource");
				using (XmlReader reader = new XmlTextReader(s)) {
					customHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.
						HighlightingLoader.Load(reader, HighlightingManager.Instance);
				}
			}
			// and register it in the HighlightingManager
			HighlightingManager.Instance.RegisterHighlighting("Custom Highlighting", new string[] { ".cool" }, customHighlighting);			
			




增加搜索面板

SearchPanel.Install(textEditor.TextArea);

运行后按  Ctrl+F ,面板有点丑,自己可以修改源码改外观

image.png




=============2022 02 16 ============================== www.ayjs.net==================================









推荐您阅读更多有关于“avaloneditwpf,”的文章

猜你喜欢

额 本文暂时没人评论 来添加一个吧

发表评论

必填

选填

选填

必填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

  查看权限

抖音:wpfui 工作wpf,目前主maui

招聘合肥一枚WPF工程师,跟我一个开发组,10-15K,欢迎打扰

目前在合肥市企迈科技就职

AYUI8全源码 Github地址:前往获取

杨洋(AaronYang简称AY,安徽六安人)AY唯一QQ:875556003和AY交流

高中学历,2010年开始web开发,2015年1月17日开始学习WPF

声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费

不是从我处购买的ayui7源码,我不提供任何技术服务,如果你举报从哪里买的,我可以帮你转正为我的客户,并送demo

查看捐赠

AYUI7.X MVC教程 更新如下:

第一课 第二课 程序加密教程

标签列表