我正在尝试使用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;
}
}
然而,我似乎无法弄清楚两个问题:
我将什么传递给VisualLineLinkText构造函数来简化文本以说“MyLink”?
我在哪里放置一个会接收RequestNavigateEventArgs的事件处理程序,以便我可以覆盖点击行为?
答案 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)”行替换为您在代码中有权访问的内容。