Как вставить встроенный контент из одного FlowDocument в другой? - PullRequest
10 голосов
/ 04 марта 2010

Я создаю приложение, которое должно позволить пользователю вставлять текст из одного RichTextBox в текущей позиции каретки в другой. Я потратил много времени на изучение объектной модели FlowDocument перед тем, как перейти к этой технике - source и target оба FlowDocument s:

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 для меня - это волнующее море темных тайн. Я могу стать экспертом в этом, если мне придется (по Достоевскому: «Человек - это животное, которое может привыкнуть ко всему»), но если кто-то уже понял это и может сказать мне, как это сделать, это сделало бы меня жизнь намного проще.

1 Ответ

13 голосов
/ 24 марта 2010

Ваша непосредственная проблема в том, что вы используете TextFormat.Xaml вместо TextFormat.XamlPackage.

Свойство, которое управляет объединением строк при объединении документов, является свойством Section.HasTrailingParagraphBreakOnPaste. Это свойство действует только при загрузке или сохранении текстового формата XamlPackage. При использовании текстового формата Xaml свойство пропускается при Save() и игнорируется при Load().

Итак, самое простое решение - просто изменить вызовы «Загрузить» и «Сохранить»:

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.ContentStart и document.ContentEnd. Если это ваш настоящий код, вы обнаружите, что любой диапазон от document.ContentStart до document.ContentEnd обязательно состоит из полных абзацев, поэтому при его копировании всегда вставляется разрыв абзаца в конце вставки. Если это проблема, используйте что-то вроде RichTextBox.Selection (если это управляется пользовательским интерфейсом) или TextPointer для резервного копирования ContentEnd до неявной метки абзаца, например:

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