textrange 丢失 textpointer 参考?
textrange losing textpointer reference?
我一直在使用我发现的一些代码 here,尝试更改流文档中文本的大小写。它正确地更改了文本,但是所有格式都丢失了(粗体、斜体等),当我将文档保存到 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 对象中的文本指针似乎被重定向到文档的开头。
设置 TextRange.Text 时,它首先通过通知 TextContainer(FlowDocument)删除该内容来删除所选内容。如果该内容恰好是带有样式依赖属性的整个内联,那么再见!因此,它不仅获得无样式的文本,而且设置它
由于您想保留现有的内联对象,您可以遍历整个 FlowDocument 以找到它们并设置它们的文本 属性。
这里有一个辅助方法,它只支持段落并在整个选择中查找所有内联(如果你总是做 Document.ContentStart 和 Document.ContentEnd,这个逻辑就简单多了)。如果需要,您可以扩展它以包括列表、列表项和超链接内的内联(通过遵循类似的模式)。
然后您应该能够在每个内联中设置文本 属性。
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;
编辑:您需要将它们转换为 运行 或 Span 以访问文本 属性。您甚至可以只删除 Inline 并获得这些类型(可能只是 运行)。
我一直在使用我发现的一些代码 here,尝试更改流文档中文本的大小写。它正确地更改了文本,但是所有格式都丢失了(粗体、斜体等),当我将文档保存到 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 对象中的文本指针似乎被重定向到文档的开头。
设置 TextRange.Text 时,它首先通过通知 TextContainer(FlowDocument)删除该内容来删除所选内容。如果该内容恰好是带有样式依赖属性的整个内联,那么再见!因此,它不仅获得无样式的文本,而且设置它
由于您想保留现有的内联对象,您可以遍历整个 FlowDocument 以找到它们并设置它们的文本 属性。
这里有一个辅助方法,它只支持段落并在整个选择中查找所有内联(如果你总是做 Document.ContentStart 和 Document.ContentEnd,这个逻辑就简单多了)。如果需要,您可以扩展它以包括列表、列表项和超链接内的内联(通过遵循类似的模式)。
然后您应该能够在每个内联中设置文本 属性。
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;
编辑:您需要将它们转换为 运行 或 Span 以访问文本 属性。您甚至可以只删除 Inline 并获得这些类型(可能只是 运行)。