我一直在使用我在这里找到的一些代码来尝试更改流文档中文本的大小写。它正确地更改了文本,但是所有格式都丢失了(粗体,斜体等),当我将文档保存到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.Text 时,它首先通过告诉 TextContainer(FlowDocument)删除该内容来删除所选内容。 如果该内容恰好与您的样式依赖项属性完全内联,那么再见! 因此,它不仅会获得无样式的文本,而且还会设置它
由于您希望保留现有的内联对象,因此可以循环访问整个 FlowDocument 以查找它们并设置其文本属性。
这是一个仅支持段落并查找整个选择中的所有内联的帮助程序方法(如果您总是执行 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;
编辑:您需要将它们强制转换为"运行"或"跨度"以访问文本属性。 您甚至可以删除内联并获取这些类型(可能只是运行)。