如何解决如何在不丢失格式的情况下以编程方式替换 WFP RichTextBox 的某些内容?
问题:我们如何以编程方式替换 WPF RichTextBox
中的某些文本而不丢失其格式?在下面的代码中,我显然没有做正确的事情。我的在线搜索提供了一些相关建议,但他们似乎正在使用 Winform,其中 RichTextBox 具有 rtf 属性 - 例如 this 一个。
以下代码正确地将 WPF RichTexBox 中的文本 abcd
替换为 rstu
,但它丢失了 RichTextBox 的格式,如下两幅图所示:
//rtbTest is the name of the RichTextBox
TextRange textRange = new TextRange(rtbTest.Document.ContentStart,rtbTest.Document.ContentEnd);
string oldText = textRange.Text;
string newText = oldText.Replace("abcd","rstu");
textRange.Text = newText;
在用 rstu 替换 abcd 之前 RichTextBox 的屏幕截图:
用 rstu 替换 abcd 后 RichTextBox 的屏幕截图:
我们可以看到格式丢失了。下面显示的列表并不是真正的格式化编号列表,它可能只是未格式化的文本(如 1. Item 1
等)
解决方法
它正在丢失格式,因为您将 RTF 存储到字符串中,而该字符串不保留 RTF 格式。
您可以将其保存如下,
TextRange textRange = new TextRange(rtbTest.Document.ContentStart,rtbTest.Document.ContentEnd);
string rtf;
using (var memoryStream = new MemoryStream())
{
textRange.Save(memoryStream,DataFormats.Rtf);
rtf = ASCIIEncoding.Default.GetString(memoryStream.ToArray());
}
rtf = rtf.Replace("abcd","rstu");
MemoryStream stream = new MemoryStream(ASCIIEncoding.Default.GetBytes(rtf));
rtbTest.SelectAll();
rtbTest.Selection.Load(stream,DataFormats.Rtf);
,
修改 RichTextBox
内容时,分析 TextPointer
上下文非常重要。如何实现,请参见下面的示例:
MainWindow.xaml
<Window ...
Title="MainWindow" Height="350" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<RichTextBox x:Name="rtb" AllowDrop="True" VerticalScrollBarVisibility="Auto" Padding="2">
<FlowDocument>
<Paragraph>
<Run Text="Paste a content to the document..."/>
</Paragraph>
</FlowDocument>
</RichTextBox>
<Button Grid.Row="1" Click="FindAndReplace">Find & Replace </Button>
</Grid>
</Window>
MainWindow.xaml.cs
的一部分using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
private void FindAndReplace(object sender,RoutedEventArgs e)
{
var textToFind = "ABC";
var textReplaceBy = "<A-B-C>";
TextPointer start = rtb.Document.ContentStart;
while (true)
{
var searchRange = new TextRange(start,rtb.Document.ContentEnd);
TextRange foundRange = searchRange.FindText(textToFind);
if (foundRange == null)
break;
foundRange.Text = textReplaceBy;
start = foundRange.End; // Continue the searching
}
rtb.Focus();
}
TextRangeExt.cs
using System;
using System.Windows.Documents;
namespace WpfApp7
{
public static class TextRangeExt
{
public static TextRange FindText(this TextRange searchRange,string searchText)
{
TextRange result = null;
int offset = searchRange.Text.IndexOf(searchText,StringComparison.OrdinalIgnoreCase);
if (offset >= 0)
{
var start = searchRange.Start.GetTextPositionAtOffset(offset);
result = new TextRange(start,start.GetTextPositionAtOffset(searchText.Length));
}
return result;
}
private static TextPointer GetTextPositionAtOffset(this TextPointer position,int offset)
{
for (TextPointer current = position; current != null; current = position.GetNextContextPosition(LogicalDirection.Forward))
{
position = current;
var adjacent = position.GetAdjacentElement(LogicalDirection.Forward);
var context = position.GetPointerContext(LogicalDirection.Forward);
switch (context)
{
case TextPointerContext.Text:
int count = position.GetTextRunLength(LogicalDirection.Forward);
if (offset <= count)
{
return position.GetPositionAtOffset(offset);
}
offset -= count;
break;
case TextPointerContext.ElementStart:
if (adjacent is InlineUIContainer)
{
offset--;
}
else if (adjacent is ListItem lsItem)
{
var trange = new TextRange(lsItem.ElementStart,lsItem.ElementEnd);
var index = trange.Text.IndexOf('\t');
if (index >= 0)
{
offset -= index + 1;
}
}
break;
case TextPointerContext.ElementEnd:
if (adjacent is Paragraph)
offset -= 2;
break;
}
}
return position;
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。