Сообщение об ошибке действительно сбивает с толку, и причина не сразу очевидна. В основном вы закрываете 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;
}
}
}
XpsReference
реализует IDisposable
, поэтому не забудьте вызвать Dispose()
на нем.
Кроме того, как только вы исправите вышеуказанную ошибку, следующей проблемой, с которой вы, вероятно, столкнетесь, будет контент, который не будет отображаться так, как вы ожидаете. Это связано с тем, что вам нужно клонировать FlowDocument
, и он не прошел полную меру и не организовал проход макета. Читать
Печать BlockUIContainer в XpsDocument / FixedDocument о том, как решить эту проблему.