【问题标题】:Capture RichTextBlock Hyperlink events捕获 RichTextBlock 超链接事件
【发布时间】:2017-04-06 15:41:44
【问题描述】:

我正在尝试在动态生成的 RichTextBlock 中捕获超链接的点击事件。

我正在动态生成富文本块的内容,然后使用XamlReader 应用它们。内容可能会有很大差异,因此我无法手动解析 xaml 并在那时连接事件。

我的基本想法是,一旦加载了richtextblock,找到其中的所有超链接并在那里连接他们的点击事件。这是我当前的代码:

    public class HookUpEvents()
    {
        foreach (var child in FindVisualChildren<Hyperlink>(richtxtblock))
        {
            child.Click += MyFunction;
        }
    }

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

显然,它不起作用。看起来 FindVisualChildren 函数没有返回任何超链接。关于如何实现这一目标的任何想法?

【问题讨论】:

  • RichTextBlock也是XamlReader生成的吗?如果没有,我能知道你为什么通过XamlReader 加载内容吗?你有 API 做对了吗?
  • 我使用 XamlReader 加载内容,因为我使用 xslt 将 HTML 转换为 XAML。

标签: c# xaml uwp richtextblock


【解决方案1】:

好吧,我肯定迟到了,但RichTextBlock 不会将他的Blocks 和他们的Inlines 放在VisualTree 中。要查找所有基于 Inline 的元素 (Run,Span,Bold etc.),您需要通过访问每个 Block 和随后的 Inline 来遍历所有内容。我会建议这样的事情:

public static IEnumerable<T> GetAllTextElements<T>(this RichTextBlock rtb) where T : TextElement
{
    var result = new List<T>();

    var blocks = rtb.Blocks;

    foreach (var block in blocks)
    {
        if (block is T)
        {
            result.Add(block as T);
            continue;
        }

        var inlines = ((Paragraph)block).Inlines;

        var res = TraverseInline<T>(inlines);
        if (res != null && res.Any())
            result.AddRange(res);
    }

    return result;
} 

private static IEnumerable<T> TraverseInline<T>(IEnumerable<Inline> inlines) where T : TextElement
{
    var result = new List<T>();

    foreach (var item in inlines)
    {
        if (item is T)
        {
            result.Add(item as T);
            continue;
        }
        else if (item is Span) // first Inline derived class to have own `Inlines`
        {
            var spanItem = item as Span;
            var spanInlines = spanItem.Inlines;
            var results = TraverseInline<T>(spanInlines);

            if (results != null && results.Any())
                result.AddRange(results);
        }
    }

    return result;
}

因此,您可以使用它查找任何TextElement 派生的项目。 用法类似于:

var textHyperlinks = myRichTextBlock.GetAllTextElements<Hyperlink>();

只要您不使用InlineUIContainer,就可以这样做。这种Inline 的行为方式不同,因为您可以将任何基于UIElement 的东西作为Child 属性放置。在这种情况下,您的初始方法应该有效。

【讨论】:

    【解决方案2】:

    这里有几件事:

    如果您尝试在 RichTextBlock 中查找超链接,则其类型为:Windows.UI.Xaml.Documents.Hyperlink。不是 HyperLinkBut​​ton 的类型。

    您可以将 Click 事件处理程序放在文本中,然后在代码隐藏文件中提供处理程序方法。如果您动态生成如下所示的文本:

    <Paragraph>
        Text with a
        <Hyperlink x:Name="link" Click="link_Click">link.</Hyperlink>
    </Paragraph>
    

    将其提供给 XamlReader,并将以下代码放入您的代码隐藏文件中:

    private void link_Click(Windows.UI.Xaml.Documents.Hyperlink sender, Windows.UI.Xaml.Documents.HyperlinkClickEventArgs args)
    {
        Debug.WriteLine("Handle link click, by: " + sender.Name);
    }
    

    然后它应该在运行时正确连接。你可以在 Click 事件处理程序上做任何你想做的事情。即使有多个链接,您也可以对它们进行不同的命名,只需使用一键式处理程序即可处理。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-14
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 2011-01-08
    • 1970-01-01
    相关资源
    最近更新 更多