使用AvalonEdit自定义超链接

时间:2015-02-07 06:10:50

标签: c# wpf avalonedit

我正在尝试使用AvalonEdit创建自定义超链接。我已经创建了一个识别语法的生成器(基于样本),我可以设置一个Uri:

  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的事件处理程序,以便我可以覆盖点击行为?

1 个答案:

答案 0 :(得分:2)

我需要在AvalonEdit中使用超链接样式对象,但仅限于“跳转到定义”样式使用,而不是用于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;
    }
}

由于这些元素是在运行时动态创建和销毁的,因此我必须将click事件注册到要处理的类的静态实例。

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

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