2015-02-07 119 views
1

我正在尝试使用AvalonEdit创建自定义超链接。我创建了一个发电机(基于样品),其识别语法,我可以设置一个URI:使用AvalonEdit的自定义超链接

public class LinkGenerator : VisualLineElementGenerator 
    { 
    readonly static Regex imageRegex = new Regex(@"<mylink>", RegexOptions.IgnoreCase); 

    public LinkGenerator() 
    {} 

    Match FindMatch(int startOffset) 
    { 
     // fetch the end offset of the VisualLine being generated 
     int endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset; 
     TextDocument document = CurrentContext.Document; 
     string relevantText = document.GetText(startOffset, endOffset - startOffset); 
     return imageRegex.Match(relevantText); 
    } 

    /// Gets the first offset >= startOffset where the generator wants to construct 
    /// an element. 
    /// Return -1 to signal no interest. 
    public override int GetFirstInterestedOffset(int startOffset) 
    { 
     Match m = FindMatch(startOffset); 
     return m.Success ? (startOffset + m.Index) : -1; 
    } 

    /// Constructs an element at the specified offset. 
    /// May return null if no element should be constructed. 
    public override VisualLineElement ConstructElement(int offset) 
    { 
     Match m = FindMatch(offset); 
     // check whether there's a match exactly at offset 
     if (m.Success && m.Index == 0) 
     { 
      var line = new VisualLineLinkText(CurrentContext.VisualLine, m.Length); 

      line.NavigateUri = new Uri("http://google.com"); 
      return line; 
     } 
     return null; 
    } 
} 

但是有两个问题,我似乎无法弄清楚:

  1. 什么我传递给VisualLineLinkText构造函数来简化文字说“MyLink”?

  2. 我在哪里放一个事件处理程序,它将接收RequestNavigateEventArgs,这样我就可以覆盖点击行为了?

回答

2

我需要使用AvalonEdit中的超链接样式对象,但仅限于“Jump To Definition”样式使用,不适用于Web超链接。我不想让Web浏览器启动,我需要自己在代码中捕捉超链接点击事件。

为此,我创建了一个从VisualLineText继承的新类。它包含一个CustomLinkClicked事件,并将一个字符串传递给事件处理程序。

/// <summary> 
/// VisualLineElement that represents a piece of text and is a clickable link. 
/// </summary> 
public class CustomLinkVisualLineText : VisualLineText 
{ 

    public delegate void CustomLinkClickHandler(string link); 

    public event CustomLinkClickHandler CustomLinkClicked; 

    private string Link { get; set; } 

    /// <summary> 
    /// Gets/Sets whether the user needs to press Control to click the link. 
    /// The default value is true. 
    /// </summary> 
    public bool RequireControlModifierForClick { get; set; } 

    /// <summary> 
    /// Creates a visual line text element with the specified length. 
    /// It uses the <see cref="ITextRunConstructionContext.VisualLine"/> and its 
    /// <see cref="VisualLineElement.RelativeTextOffset"/> to find the actual text string. 
    /// </summary> 
    public CustomLinkVisualLineText(string theLink, VisualLine parentVisualLine, int length) 
     : base(parentVisualLine, length) 
    { 
     RequireControlModifierForClick = true; 
     Link = theLink; 
    } 


    public override TextRun CreateTextRun(int startVisualColumn, ITextRunConstructionContext context) 
    { 
     TextRunProperties.SetForegroundBrush(Brushes.GreenYellow); 
     TextRunProperties.SetTextDecorations(TextDecorations.Underline); 
     return base.CreateTextRun(startVisualColumn, context); 
    } 

    bool LinkIsClickable() 
    { 
     if (string.IsNullOrEmpty(Link)) 
      return false; 
     if (RequireControlModifierForClick) 
      return (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; 
     else 
      return true; 
    } 


    protected override void OnQueryCursor(QueryCursorEventArgs e) 
    { 
     if (LinkIsClickable()) 
     { 
      e.Handled = true; 
      e.Cursor = Cursors.Hand; 
     } 
    } 

    protected override void OnMouseDown(MouseButtonEventArgs e) 
    { 
     if (e.ChangedButton == MouseButton.Left && !e.Handled && LinkIsClickable()) 
     { 

      if (CustomLinkClicked != null) 
      { 
       CustomLinkClicked(Link); 
       e.Handled = true; 
      } 

     } 
    } 

    protected override VisualLineText CreateInstance(int length) 
    { 

     var a = new CustomLinkVisualLineText(Link, ParentVisualLine, length) 
     {     
      RequireControlModifierForClick = RequireControlModifierForClick 
     }; 

     a.CustomLinkClicked += link => ApplicationViewModel.Instance.ActiveCodeViewDocument.HandleLinkClicked(Link); 
     return a; 
    } 
} 

当创建并在运行时动态破坏这些元素,我必须点击事件注册到一个类来处理的静态实例。

a.CustomLinkClicked += link => ApplicationViewModel.Instance.ActiveCodeViewDocument.HandleLinkClicked(Link); 

当您点击链接(如果指定使用Ctrl-点击),它将触发该事件。您可以将“链接”字符串替换为您需要的任何其他类。您需要将代码行中的'ApplicationViewModel.Instance.ActiveCodeViewDocument.HandleLinkClicked(Link)'行替换为您可以访问的内容。

+0

对不起,深入挖掘这个旧的答案,但“跳转到定义”风格导航正是我想要实现的。我只是不明白在使用VisualLineText时发生的“匹配”。我可以以某种方式将它连接到突出显示引擎? – themightylc 2017-10-30 07:38:41

+0

不要以上评论。语法突出显示在CreateInstance Sub中 – themightylc 2017-10-30 07:47:06