2012-03-10 3 views
2

У меня есть приложение с RichTextBox и DocumentViewer (размещено в TabControl), и я хочу сделать что-то вроде «горячего предварительного просмотра». Я переплетены DocumentViewer.Document свойство RichTextBox.DocumentОшибка DocumentViewer для RichTextBox

Переплет:

<DocumentViewer Document="{Binding Document, Converter={StaticResource FlowDocumentToPaginatorConverter}, ElementName=mainRTB, Mode=OneWay}" />

И это конвертер код:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      FlowDocument d = value as FlowDocument; 
      DocumentPaginator pagin = ((IDocumentPaginatorSource)d).DocumentPaginator; 
      FixedDocumentSequence result = null; 
      Size s = new Size(793.700787402, 1122.519685039); 
      pagin.PageSize = s; 

      using (MemoryStream ms = new MemoryStream()) 
      { 
       TextRange tr = new TextRange(d.ContentStart, d.ContentEnd); 
       tr.Save(ms, DataFormats.XamlPackage); 
       Package p = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); 
       Uri uri = new Uri(@"memorystream://doc.xps"); 
       PackageStore.AddPackage(uri, p); 
       XpsDocument xpsDoc = new XpsDocument(p); 
       xpsDoc.Uri = uri; 
       XpsDocument.CreateXpsDocumentWriter(xpsDoc).Write(pagin); 
       result = xpsDoc.GetFixedDocumentSequence(); 
      } 
      return result; 
     } 

Когда я начинаю это приложение все в порядке, пока я не переключиться на вкладку с DocumentViewer. Приложение подавляет, и я получаю такой Исключение:

Невозможно выполнить операцию чтения в режиме только для записи.

Что я делаю неправильно? Можно ли сделать это связывание?

ответ

4

Сообщение об ошибке действительно запутывается, и причина не сразу очевидна. В основном вы закрываете MemoryStream, который содержит XpsDocument слишком рано, и когда DocumentViewer пытается прочитать документ, он не может, поскольку это режим только для записи (поскольку поток был закрыт).

Решение не должно немедленно закрывать MemoryStream до после Вы закончили просмотр документа. Для этого я написал XpsDocumentConverter, который возвращает XpsReference.

Кроме того, как вы никогда не были в состоянии преобразовать и отобразить один XpsDocument не будет еще встречается следующий вопрос, имеющий несколько пакетов в PackageStore с тем же Uri. Я позаботился об этом в своей реализации ниже.

public static XpsDocumentReference CreateXpsDocument(FlowDocument document) 
{    
    // Do not close the memory stream as it still being used, it will be closed 
    // later when the XpsDocumentReference is Disposed. 
    MemoryStream ms = new MemoryStream(); 

    // We store the package in the PackageStore 
    Uri uri = new Uri(String.Format("pack://temp_{0}.xps/", Guid.NewGuid().ToString("N"))); 
    Package pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); 
    PackageStore.AddPackage(uri, pkg); 
    XpsDocument xpsDocument = new XpsDocument(pkg, CompressionOption.Normal, uri.AbsoluteUri); 

    // Need to force render the FlowDocument before pagination. 
    // HACK: This is done by *briefly* showing the document. 
    DocumentHelper.ForceRenderFlowDocument(document); 

    XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDocument), false); 
    DocumentPaginator paginator = new FixedDocumentPaginator(document, A4PageDefinition.Default);    
    rsm.SaveAsXaml(paginator); 

    return new XpsDocumentReference(ms, xpsDocument); 
} 

public class XpsDocumentReference : IDisposable 
{ 
    private MemoryStream MemoryStream;    
    public XpsDocument XpsDocument { get; private set; } 
    public FixedDocument FixedDocument { get; private set; } 

    public XpsDocumentReference(MemoryStream ms, XpsDocument xpsDocument) 
    { 
     MemoryStream = ms; 
     XpsDocument = xpsDocument; 

     DocumentReference reference = xpsDocument.GetFixedDocumentSequence().References.FirstOrDefault(); 
     if (reference != null) 
      FixedDocument = reference.GetDocument(false); 
    } 

    public void Dispose() 
    { 
     Package pkg = PackageStore.GetPackage(XpsDocument.Uri); 
     if (pkg != null) 
     { 
      pkg.Close(); 
      PackageStore.RemovePackage(XpsDocument.Uri); 
     } 

     if (MemoryStream != null) 
     { 
      MemoryStream.Dispose(); 
      MemoryStream = null; 
     } 
    } 

} 

XpsReferenceIDisposable реализует так что не забудьте позвонить Dispose() на него.

Кроме того, после устранения вышеуказанной ошибки следующая проблема, с которой вы, скорее всего, столкнетесь, будет не отображаться, как вы ожидали. Это вызвано тем фактом, что вам необходимо клонировать FlowDocument, и он не претерпел полной меры и не уложил макет. Прочтите Printing BlockUIContainer to XpsDocument/FixedDocument о том, как это решить.

+0

Обновлен с образцом кода как и было обещано. – Dennis

+0

Если вы ищете волшебство за «ForceRenderFlowDocument», оно доступно в этом ответе StackOverflow. http://stackoverflow.com/questions/9447338/printing-blockuicontainer-to-xpsdocument-fixeddocument – Dennis

Смежные вопросы