0

我一直在使用我在这里找到的一些代码来尝试更改流文档中文本的大小写。它正确更改了文本,但是所有格式都丢失了(粗体、斜体等),当我将文档保存到 XML 文件时,所有文本都在文档的第一次运行中结束,而所有其他运行都是空的。

    private void ChangeCase()
    {
        TextPointer start = mergedDocument.ContentStart;
        TextPointer end = mergedDocument.ContentEnd;
        List<TextRange> textToChange = SplitToTextRanges(start, end);
        ChangeCaseToAllRanges(textToChange);
    }

    private List<TextRange> SplitToTextRanges(TextPointer start, TextPointer end)
    {
        List<TextRange> textToChange = new List<TextRange>();
        var previousPointer = start;
        for (var pointer = start; (pointer != null && pointer.CompareTo(end) <= 0); pointer = pointer.GetPositionAtOffset(1, LogicalDirection.Forward))
        {
            var contextAfter = pointer.GetPointerContext(LogicalDirection.Forward);
            var contextBefore = pointer.GetPointerContext(LogicalDirection.Backward);
            if (contextBefore != TextPointerContext.Text && contextAfter == TextPointerContext.Text)
            {
                previousPointer = pointer;
            }
            if (contextBefore == TextPointerContext.Text && contextAfter != TextPointerContext.Text && previousPointer != pointer)
            {
                textToChange.Add(new TextRange(previousPointer, pointer));
                previousPointer = null;
            }
        }
        textToChange.Add(new TextRange(previousPointer ?? end, end));
        return textToChange;
    }

    private void ChangeCaseToAllRanges(List<TextRange> textToChange)
    {
        Func<string, string> caseChanger;
        ComboBoxItem cbi = cb_Case.SelectedItem as ComboBoxItem;
        var textInfo = CultureInfo.CurrentUICulture.TextInfo;

        if (cbi == null || (string)cbi.Tag == "none")
        {
            return;
        }
        else if((string)cbi.Tag == "title")
        {
            caseChanger = (text) => textInfo.ToTitleCase(text);
        }
        else if ((string)cbi.Tag == "upper")
        {
            caseChanger = (text) => textInfo.ToUpper(text);
        }
        else if ((string)cbi.Tag == "lower")
        {
            caseChanger = (text) => textInfo.ToLower(text);
        }
        else
            return;

        foreach (var range in textToChange)
        {
            if (!range.IsEmpty && !string.IsNullOrWhiteSpace(range.Text))
            {
                System.Diagnostics.Debug.WriteLine("Casing: " + range.Text);
                System.Diagnostics.Debug.WriteLine("\tat: " + 
                    range.Start.GetOffsetToPosition(mergedDocument.ContentStart) +
                    " ," +
                    range.End.GetOffsetToPosition(mergedDocument.ContentStart));
                range.Text = caseChanger(range.Text);
            }
        }
    }

我看不出这段代码不能正常工作的任何原因。看起来 textrange 对象中的文本指针被重定向到文档的开头。

4

1 回答 1

1

设置 TextRange.Text 时,它首先通过告诉 TextContainer(FlowDocument)删除该内容来删除选择。如果该内容恰好是您的样式依赖属性的整个内联,那么再见!所以,它不仅会得到无样式的文本,还会设置它

由于您想保留现有的内联对象,您可以遍历整个 FlowDocument 以找到它们并设置它们的文本属性。

这里有一个辅助方法,它只支持 Paragraphs 并在整个选择中查找所有内联(如果你总是在做 Document.ContentStart 和 Document.ContentEnd,这个逻辑要简单得多)。如果需要,您可以扩展它以包括列表、列表项和超链接中的内联(通过遵循类似的模式)。

然后,您应该能够在这些内联中的每一个上设置 Text 属性。

    List<Inline> GetInlines(TextRange selection)
    {
        var inlines = new List<Inline>();

        foreach (var block in Document.Blocks.Where(x => selection.Start.CompareTo(x.ContentEnd) < 0 && selection.End.CompareTo(x.ContentStart) > 0))
        {
            var paragraph = block as Paragraph;
            if (paragraph != null)
            {
                inlines.AddRange(paragraph.Inlines.Where(x => selection.Start.CompareTo(x.ContentEnd) < 0 && selection.End.CompareTo(x.ContentStart) > 0));
            }
        }

return inlines;

编辑:您需要将这些转换为 Run 或 Span 以访问 text 属性。您甚至可以删除 Inline 并获取这些类型(可能只是运行)。

于 2016-04-26T17:44:07.700 回答