检索在超链接中运行

时间:2014-09-15 09:27:19

标签: c# wpf hyperlink richtextbox

enter image description here

我想删除位于RichTextBox中的所有超链接,但不删除超链接内的运行。

我的计划是针对每个超链接:

  • 收集其中的所有内容
  • 删除超链接
  • 重新插入游戏

在提取运行时,我遇到了这个问题: 如果超链接包含一个未格式化的运行, 我没有得到跑步,但也没有得到周围的超链接。

请尝试以下代码:

的Xaml:

<RichTextBox Name="rtb" Grid.Column="0" Grid.Row="0" IsDocumentEnabled="True">
    <FlowDocument>
        <Paragraph>
            <Hyperlink>
                <Run>HyperlinkUnformatted</Run>
            </Hyperlink>
        </Paragraph>
        <Paragraph>
            <Hyperlink>
                <Run>Hyper</Run><Run Background="Yellow">link</Run><Run>Formatted</Run>
            </Hyperlink>
        </Paragraph>
    </FlowDocument>
</RichTextBox> 

C#:

// All runs inside the RichTextBox
List<Run> runs = runsGet(rtb.Document.ContentStart, rtb.Document.ContentEnd);

foreach (Run run in runs)
{
    TextRange rangeOfRun = new TextRange(run.ContentStart, run.ContentEnd);
    string runAsString = rangeToString(rangeOfRun, DataFormats.Xaml);
    MessageBox.Show(runAsString);
}

/// <summary>
/// Returns all runs between startPos and endPos.
/// </summary>
private List<Run> runsGet(TextPointer startPos, TextPointer endPos)
{
    List<Run> foundRuns = null;
    TextPointer currentPos = startPos;

    while (currentPos != null && currentPos.CompareTo(endPos) <= 0)
    {
        Run nextRun = runNextGet(currentPos);
        if (nextRun == null) break;

        if (nextRun.ContentStart.CompareTo(endPos) <= 0)
        {
            if (foundRuns == null) foundRuns = new List<Run>();

            foundRuns.Add(nextRun);

            currentPos = nextRun.ContentEnd.GetNextInsertionPosition(LogicalDirection.Forward);
        }
        else
        {
            break;
        }
    }

    return foundRuns;
}

/// <summary>
/// Returns first run located at startPos or behind.
/// </summary>
private Run runNextGet(TextPointer startPos)
{
    TextPointer currentPos = startPos;

    while (currentPos != null)
    {
        if (currentPos.Parent is Run)
        {
            return currentPos.Parent as Run;
        }
        else
        {
            currentPos = currentPos.GetNextInsertionPosition(LogicalDirection.Forward);
        }
    }

    return null;
}

/// <summary>
/// Returns a text area as Xaml string (if dataFormat is DataFormats.Xaml).
/// </summary>
private string rangeToString(TextRange range, string dataFormat)
{
    using (MemoryStream memStream = new MemoryStream())
    {
        using (StreamWriter streamWriter = new StreamWriter(memStream))
        {
            range.Save(memStream, dataFormat);

            memStream.Flush();
            memStream.Position = 0;

            StreamReader streamReader = new StreamReader(memStream);

            return streamReader.ReadToEnd();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您要做的是,对于每个超链接,将超链接的Inlines复制到单独的XamlPackage,然后将它们粘贴回FlowDocument,覆盖Hyperlink本身。不幸的是,由于TextRange.Save()“有用”expands the selected rangenearest text insertion boundaries,因此天真的实施方式会失败。由于超链接与其第一个内联的开头(大小为零)之间的空间不是有效的插入符号位置,因此不是有效的插入位置,因此文本范围将扩展为包括超链接。它由此包含在包中,并在粘贴时重新创建。

要解决此问题,您可以在现有内联之前和之后插入一些其他虚拟文本:

public static class FlowDocumentHelper
{
    public static IEnumerable<DependencyObject> WalkTreeDown(this DependencyObject root)
    {
        if (root == null)
            throw new ArgumentNullException();
        yield return root;
        foreach (var child in LogicalTreeHelper.GetChildren(root).OfType<DependencyObject>())
            foreach (var descendent in child.WalkTreeDown())
                yield return descendent;
    }

    public static IEnumerable<DependencyObject> WalkTreeUp(this DependencyObject child)
    {
        for (; child != null; child = LogicalTreeHelper.GetParent(child))
            yield return child;
    }

    public static void RemoveHyperlinks(this FlowDocument doc)
    {
        var allLinks = doc.WalkTreeDown().OfType<Hyperlink>().ToArray();
        for (int iLink = allLinks.Length - 1; iLink >= 0; iLink--)
        {
            var link = allLinks[iLink];
            var range = new TextRange(link.ContentStart.GetInsertionPosition(LogicalDirection.Backward), link.ContentEnd.GetInsertionPosition(LogicalDirection.Forward));

            var first = link.Inlines.FirstInline;
            var last = link.Inlines.LastInline;

            link.Inlines.Add(new Run(" "));
            link.Inlines.InsertBefore(first, new Run(" "));

            var childRange = new TextRange(first.ContentStart, last.ContentEnd);

            using (MemoryStream ms = new MemoryStream())
            {
                string format = DataFormats.XamlPackage;

                childRange.Save(ms, format, true);
                ms.Seek(0, SeekOrigin.Begin);
                range.Load(ms, format);
            }
        }
    }
}

我已经使用您的案例以及包含嵌入图像的超链接进行了测试。

当然,删除了超链接本身的下划线和格式。如果你愿意,你可以在之后添加它们。