2010-03-11 9 views
5

Sto riscontrando alcune difficoltà nel visualizzare le immagini contenute in un documento FlowDocument per mostrare quando il documento FlowDocument viene salvato come documento XPS.Immagini mancanti in FlowDocument salvato come documento XPS

Ecco quello che faccio:

  1. creare un'immagine utilizzando il controllo Image di WPF. Ho impostato la sorgente dell'immagine tra parentesi per le chiamate a BeginInit/EndInit.
  2. Aggiungere l'immagine a FlowDocument inserendola in un BlockUIContainer.
  3. Salvare l'oggetto FlowDocument in un file XPS utilizzando una versione modificata di this code.

Se poi visualizzo il file salvato nel visualizzatore XPS, l'immagine non viene mostrata. Il problema è che le immagini non vengono caricate fino a quando non vengono effettivamente visualizzate sullo schermo da WPF, in modo che non vengano salvate nel file XPS. Quindi, c'è una soluzione: se prima mostro il documento sullo schermo usando lo FlowDocumentPageViewer e poi salvi il file XPS, l'immagine viene caricata e appare nel file XPS. Funziona anche se FlowDocumentPageViewer è nascosto. Ma questo mi dà un'altra sfida. Ecco quello che desidero fare (in pseudocodice):

void SaveDocument() 
{ 
    AddFlowDocumentToFlowDocumentPageViewer(); 
    SaveFlowDocumentToXpsFile(); 
} 

Questo ovviamente non funziona in quanto la FlowDocumentPageViewer non ha la possibilità di mostrare il suo contenuto prima che il documento viene salvato nel file XPS. Ho provato a racchiudere SaveFlowDocumentToXpsFile in una chiamata a Dispatcher.BeginInvoke ma non è stato di aiuto.

Le mie domande sono:

  1. Posso in qualche modo costringere le immagini da caricare prima di salvare il file XPS senza in realtà mostra il documento sullo schermo? (Ho provato a giocherellare con BitmapImage.CreateOptions senza fortuna).
  2. Se non c'è soluzione alla domanda n. 1, c'è un modo per dire quando FlowDocumentPageViewer ha finito di caricare il suo contenuto in modo che io sappia quando è salvato per creare il file XPS?
+0

Hai trovato un modo per mostrare il FlowDocument in un visualizzatore prima della stampa? Sto considerando un simile "trucco" per ottenere il corretto rendering del mio documento. – Dennis

+0

@DennisRoche: No, sfortunatamente non ho mai trovato una soluzione migliore di mostrare brevemente il documento sullo schermo prima di salvarlo in un file. Per favore fatemi sapere se trovate una soluzione migliore. –

+0

Potrei avere una possibile soluzione che utilizza 'ContextualLayoutManager' per accedere alla struttura ad albero logico. Ti farò sapere se funziona ti farò sapere. Altrimenti ricorro a caricare il documento in un visualizzatore come hai fatto, tuttavia imposteremo la posizione della finestra su X: 10.000 Y: 10.000 in modo che l'utente non la veda. – Dennis

risposta

0

la soluzione finale era lo stesso che si è venuto a, che è quello di mettere il documento in un visualizzatore e brevemente mostrare sullo schermo. Di seguito è il metodo di supporto che ho scritto per fare questo per me.

private static string ForceRenderFlowDocumentXaml = 
@"<Window xmlns=""http://schemas.microsoft.com/netfx/2007/xaml/presentation"" 
      xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""> 
     <FlowDocumentScrollViewer Name=""viewer""/> 
    </Window>"; 

public static void ForceRenderFlowDocument(FlowDocument document) 
{ 
    using (var reader = new XmlTextReader(new StringReader(ForceRenderFlowDocumentXaml))) 
    { 
     Window window = XamlReader.Load(reader) as Window; 
     FlowDocumentScrollViewer viewer = LogicalTreeHelper.FindLogicalNode(window, "viewer") as FlowDocumentScrollViewer; 
     viewer.Document = document; 
     // Show the window way off-screen 
     window.WindowStartupLocation = WindowStartupLocation.Manual; 
     window.Top = Int32.MaxValue; 
     window.Left = Int32.MaxValue; 
     window.ShowInTaskbar = false; 
     window.Show(); 
     // Ensure that dispatcher has done the layout and render passes 
     Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Loaded, new Action(() => {})); 
     viewer.Document = null; 
     window.Close(); 
    } 
} 

Edit: Ho appena aggiunto window.ShowInTaskbar = false al metodo come se foste rapido si poteva vedere la finestra viene visualizzata nella barra delle applicazioni.

L'utente non "vedrà" mai la finestra poichè è posizionata fuori dallo schermo a Int32.MaxValue - un trucco che era comune nel corso della giornata con l'authoring multimediale iniziale (ad esempio Macromedia/Adobe Director).

Per le persone alla ricerca e alla ricerca di questa domanda, posso dirvi che non c'è altro modo che forzare il rendering del documento.

HTH,

+0

Grazie per la risposta. Ho contrassegnato la tua risposta come risposta accettata anche se mi sarebbe piaciuto vedere una soluzione diversa ;-). –

+0

Mi sarebbe piaciuta una soluzione migliore, tuttavia credo che abbia esaurito tutte le altre possibilità. È una soluzione abbastanza semplice in quanto l'utente non vedrà mai ** la finestra apparire come fuori campo. – Dennis

+0

È anche, di gran lunga, non il peggiore hack che ho fatto. – Dennis

1

Coppia cose ... Sei sicuro che l'immagine viene ridimensionata prima della sua scrittura? Di solito si deve chiamare Misura sul controllo in modo che esso possa dimensione stessa di conseguenza (infinito consente il controllo espandere la sua larghezza e altezza)

image.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 

Inoltre, a volte si deve urtare il thread dell'interfaccia utente in modo che tutto viene aggiornato nel controllo

Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>{})); 
+0

L'utilizzo di quel trucco Dispatcher funziona davvero per le immagini piccole o quelle già memorizzate nella cache, ma non per le immagini di grandi dimensioni che vengono scaricate da Internet in background. Qualche idea su come ritardare il tentativo di salvare su XPS fino al completamento del download di 1-2 secondi? O meglio, aspetta fino a quando tutte le immagini che il FlowDocument potrebbe contenere sono completamente scaricate e renderizzate? – BCA

+0

@BCA potresti provare DispatcherPriority.Idle? – Will

+0

sì, ho usato 'DispatcherPriority.SystemIdle'. Suppongo che il trucco del dispatcher non funzioni se l'immagine viene scaricata in background? – BCA

0

Come ospite non per visualizzare il documento in modo da avere immagini salvate nelle XPS. Stai chiamando commit su XpsSerializationManager?

FlowDocument fd = new FlowDocument(); 

     fd.Blocks.Add(new Paragraph(new Run("This is a test"))); 

     string image = @"STRING_PATH"; 

     BitmapImage bi = new BitmapImage(); 
     bi.BeginInit(); 
     bi.UriSource = new Uri(image, UriKind.RelativeOrAbsolute); 
     bi.CacheOption = BitmapCacheOption.OnLoad; 
     bi.EndInit(); 
     MemoryStream ms = new MemoryStream(); 
     Package pkg = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite); 
     Uri pkgUri = bi.UriSource; 

     PackageStore.AddPackage(pkgUri, pkg); 


     Image img = new Image(); 
     img.Source = bi; 

     BlockUIContainer blkContainer = new BlockUIContainer(img); 

     fd.Blocks.Add(blkContainer); 


     DocumentPaginator paginator = ((IDocumentPaginatorSource)fd).DocumentPaginator; 

     using (XpsDocument xps = new XpsDocument(@"STRING PATH WHERE TO SAVE FILE", FileAccess.ReadWrite, CompressionOption.Maximum)) 
     { 
      using (XpsSerializationManager serializer = new XpsSerializationManager(new XpsPackagingPolicy(xps), false)) 
      { 
       serializer.SaveAsXaml(paginator); 
       serializer.Commit(); 
      } 
     } 
+0

Ho provato a chiamare XpsSerializationManager.Commit ma non ha avuto l'effetto desiderato. –

+0

Mi dispiace per non aver risposto prima. Ecco una versione veramente sporca che dovrebbe funzionare. Fammi sapere come risulta – jfin3204

+0

Questa soluzione ha funzionato per te? – jfin3204

Problemi correlati