2012-03-10 53 views
2

我有一個RichTextBox和DocumentViewer(放置在TabControl中)的應用程序,我想做一些類似「熱預覽」的東西。我已經綁定DocumentViewer.Document屬性RichTextBox.DocumentDocumentViewer到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你不會還沒有遇到過具有相同UriPackageStore多個包的下一個問題。我在下面的實施中關注了這一點。

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關於如何解決這個問題。

+0

按承諾的代碼示例更新。 – Dennis 2012-03-12 09:36:44

+0

如果你正在尋找'ForceRenderFlowDocument'背後的魔法,它可以在這個StackOverflow答案中找到。 http://stackoverflow.com/questions/9447338/printing-blockuicontainer-to-xpsdocument-fixeddocument – Dennis 2012-03-14 13:22:31