如何将一个 FlowDocument 中的内联内容插入到另一个 FlowDocument 中?

发布于 2024-08-23 16:05:25 字数 946 浏览 5 评论 0原文

我正在构建一个应用程序,需要允许用户将一个 RichTextBox 中的文本插入到另一个 RichTextBox 的当前插入符号位置。在使用这项技术之前,我花了很多时间研究FlowDocument的对象模型 - 目标 都是 FlowDocument

using (MemoryStream ms = new MemoryStream())
{
    TextRange tr = new TextRange(source.ContentStart, source.ContentEnd);                    
    tr.Save(ms, DataFormats.Xaml);
    ms.Seek(0, SeekOrigin.Begin);
    tr = new TextRange(target.CaretPosition, target.CaretPosition);
    tr.Load(ms, DataFormats.Xaml);
}

这效果非常好。

我现在遇到的唯一问题是它总是将源代码作为新段落插入。它会在插入符处中断当前运行(或其他内容),插入源代码,并结束段落。如果源实际上是一个段落(或多于一个段落),则这是合适的,但如果它只是(例如)一行文本,则不合适。

我认为这个问题的答案很可能最终是检查目标以查看它是否完全由单个块组成,如果是,则将 TextRange 设置为指向开头并将块内容保存到流之前先将其结束。

对我来说,FlowDocument 的整个世界是一片充满黑暗神秘的翻滚海洋。如果有必要的话,我可以成为这方面的专家(按照陀思妥耶夫斯基的说法:“人是一种可以习惯任何事情的动物。”),但如果有人已经弄清楚了这一点并且可以告诉我如何做到这一点,那么我的生活变得更加轻松。

I'm building an application that needs to allow a user to insert text from one RichTextBox at the current caret position in another one. I spent a lot of time screwing around with the FlowDocument's object model before running across this technique - source and target are both FlowDocuments:

using (MemoryStream ms = new MemoryStream())
{
    TextRange tr = new TextRange(source.ContentStart, source.ContentEnd);                    
    tr.Save(ms, DataFormats.Xaml);
    ms.Seek(0, SeekOrigin.Begin);
    tr = new TextRange(target.CaretPosition, target.CaretPosition);
    tr.Load(ms, DataFormats.Xaml);
}

This works remarkably well.

The only problem I'm having with it now is that it always inserts the source as a new paragraph. It breaks the current run (or whatever) at the caret, inserts the source, and ends the paragraph. That's appropriate if the source actually is a paragraph (or more than one paragraph), but not if it's just (say) a line of text.

I think it's likely that the answer to this is going to end up being checking the target to see if it consists entirely of a single block, and if it does, setting the TextRange to point at the beginning and end of the block's content before saving it to the stream.

The entire world of the FlowDocument is a roiling sea of dark mysteries to me. I can become an expert at it if I have to (per Dostoevsky: "Man is the animal who can get used to anything."), but if someone has already figured this out and can tell me how to do this it would make my life far easier.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

秋千易 2024-08-30 16:05:25

您面临的直接问题是您使用的是 TextFormat.Xaml 而不是 TextFormat.XamlPackage

控制合并文档时是否合并行的属性是 Section.HasTrailingParagraphBreakOnPaste 属性。此属性仅在加载或保存 XamlPackage 文本格式时有效。当使用 Xaml 文本格式时,该属性在 Save() 期间被省略,并在 Load() 期间被忽略。

因此,简单的解决方法就是更改 Load 和 Save 调用:

tr.Save(ms, DataFormats.XamlPackage); 
ms.Seek(0, SeekOrigin.Begin); 
tr = new TextRange(target.CaretPosition, target.CaretPosition); 
tr.Load(ms, DataFormats.XamlPackage); 

请注意,这还解决了您最终会遇到的另一个问题:使用 DataFormats.Xaml 时,嵌入位图将无法正确复制,因为没有地方放置图像位。使用DataFormats.XamlPackage构建了整个包,因此位图和其他包项目将正常显示。

进行此更改后,您可能会发现另一个事实,这对您来说可能是也可能不是问题:您的示例代码使用 document.ContentStartdocument.ContentEnd。如果这是您的实际代码,您会发现从 document.ContentStartdocument.ContentEnd 的任何范围都必然包含完整段落,因此复制它总是会在插入结束。如果这是一个问题,请使用 RichTextBox.Selection (如果这是 UI 驱动的)或使用 TextPointerContentEnd 备份到之前隐式段落标记,例如:

var tr = new TextRange(document.ContentStart,
                       document.ContentEnd.GetInsertionPosition(
                                                  LogicalDirection.Backward));

Your immediate problem is that you are using TextFormat.Xaml instead of TextFormat.XamlPackage.

The property that controls whether or not lines are merged when documents are combined is the Section.HasTrailingParagraphBreakOnPaste property. This property is only effective when loading or saving the XamlPackage text format. When using Xaml text format instead, the property is omitted during Save() and ignored during Load().

So the simple fix is to simply change the Load and Save calls:

tr.Save(ms, DataFormats.XamlPackage); 
ms.Seek(0, SeekOrigin.Begin); 
tr = new TextRange(target.CaretPosition, target.CaretPosition); 
tr.Load(ms, DataFormats.XamlPackage); 

Note that this also fixes another problem you would eventually run into: Embedded bitmaps will not be copied properly when using DataFormats.Xaml because there is nowhere to put the image bits. With DataFormats.XamlPackage an entire package is built so bitmaps and other package items will come across ok.

Once you make this change you may discover another fact that may or may not be an issue for you: Your sample code uses document.ContentStart and document.ContentEnd. If this is your actual code you will discover that any range from document.ContentStart to document.ContentEnd necessarily consists of full paragraphs, so copying it will always insert a paragraph break at the end of the insertion. If this is a problem, use something like RichTextBox.Selection (if this is UI driven) or use TextPointer to back up ContentEnd to before the implicit paragraph mark, for example:

var tr = new TextRange(document.ContentStart,
                       document.ContentEnd.GetInsertionPosition(
                                                  LogicalDirection.Backward));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文