DocumentViewer到RichTextBox绑定错误
我有一个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。应用程序粉碎,我得到这样的例外:
无法在只写模式下执行读取操作。
我在做什么错了?是否有可能使这种绑定?
错误信息确实令人困惑,原因并不明显。基本上,您关闭的MemoryStream
太早,XpsDocument
太早,当DocumentViewer
尝试读取文档时,它不能作为只写模式(因为流已关闭)。
的解决方案是不立即关闭MemoryStream
直到后查看完文档。为了达到这个目的,我写了一个XpsDocumentConverter
,返回XpsReference
。
而且,因为你从来没有能够转换和显示单个XpsDocument
你不会还没有遇到过具有相同Uri
在PackageStore
多个包的下一个问题。我在下面的实施中关注了这一点。
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
而导致的,它没有经过全面的测量并安排布局通过。阅读 Printing BlockUIContainer to XpsDocument/FixedDocument关于如何解决这个问题。
按承诺的代码示例更新。 – Dennis 2012-03-12 09:36:44
如果你正在寻找'ForceRenderFlowDocument'背后的魔法,它可以在这个*答案中找到。 http://*.com/questions/9447338/printing-blockuicontainer-to-xpsdocument-fixeddocument – Dennis 2012-03-14 13:22:31