2010-03-11 72 views
5

我在FlowDocument中包含的圖像顯示何時將FlowDocument保存爲XPS文檔時遇到了一些困難。FlowDocument中的圖像保存爲XPS文檔

這裏是我做的:

  1. 使用Image控制WPF的創建圖像。我通過調用BeginInit/EndInit將圖像源設置爲方括號。
  2. 將圖像添加到FlowDocument中,並將其包裝在BlockUIContainer中。
  3. 使用修改後的this code版本將FlowDocument對象保存到XPS文件。

如果我然後在XPS查看器中查看保存的文件,則圖像不會顯示。問題是,圖像不會加載,直到WPF實際顯示在屏幕上,因此它們不會保存到XPS文件中。因此,有一種解決方法:如果我首先使用FlowDocumentPageViewer在屏幕上顯示文檔,然後保存XPS文件,則圖像將加載並顯示在XPS文件中。即使FlowDocumentPageViewer處於隱藏狀態,這也可以工作。但那給了我另一個挑戰。這是我希望做的(僞代碼):

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

當然,這並不工作,因爲FlowDocumentPageViewer從來沒有得到一個機會,以顯示其內容之前,文件被保存到XPS文件。我嘗試在調用Dispatcher.BeginInvoke時包裝SaveFlowDocumentToXpsFile,但它沒有幫助。

我的問題是:

  1. 我可以以某種方式保存XPS文件,而無需實際顯示在屏幕上的文件之前強制圖像加載? (我試着用沒有運氣的BitmapImage.CreateOptions擺弄)。
  2. 如果問題#1沒有解決方案,有沒有辦法告訴FlowDocumentPageViewer何時完成加載其內容,以便知道何時保存以創建XPS文件?
+0

您是否在打印機之前找到了在查看器中顯示FlowDocument的方法?我正在考慮類似的「黑客」來讓我的文檔正確呈現。 – Dennis 2012-02-25 20:31:24

+0

@ DennisRoche:不,不幸的是,我從來沒有找到比在屏幕上簡單顯示文檔之前將其保存到文件中的更好的解決方案。如果您找到更好的解決方案,請讓我知道。 – 2012-02-26 17:30:02

+0

我可能有一個可能的解決方案,它使用'ContextualLayoutManager'來走向邏輯樹。我會讓你知道它是否有效,我會讓你知道。否則,我將盡可能地在查看器中加載文檔,但會將窗口位置設置爲X:10,000 Y:10,000,以便用戶不會看到它。 – Dennis 2012-02-26 22:55:09

回答

0

最終的解決方案與您所說的相同,即將文檔放入查看器並在屏幕上簡單顯示。下面是我寫給我的幫手方法。

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(); 
    } 
} 

編輯:我只是說window.ShowInTaskbar = false的方法,如果你是快,你可以看到窗口出現在任務欄中。

用戶永遠不會「看見」窗口,因爲它位於屏幕外的Int32.MaxValue--一種早期多媒體創作(例如Macromedia/Adob​​e Director)當時常見的技巧。

對於搜索和查找此問題的人,我可以告訴你,沒有其他方法強制文檔進行渲染。

HTH,

+0

謝謝你的回答。儘管我希望看到不同的解決方案,但我已將答案標記爲已接受的答案;-)。 – 2012-02-27 14:05:38

+0

我會喜歡更好的解決方案,但我相信已經耗盡了所有其他的可能性。這是一個相當乾淨的解決方法,因爲用戶不會**看到窗口在屏幕外顯示。 – Dennis 2012-02-27 16:47:00

+0

這也是迄今爲止,我所做的最糟糕的黑客攻擊。 – Dennis 2012-02-27 16:48:44

1

夫婦的東西... 你確定圖像的大小之前,它的書面?通常你要調用的控制措施,使得它可以本身的大小相應(無窮讓控制擴大到其寬度和高度)

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

此外,有時你必須碰UI線程使一切都得到更新在控制中

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

使用該分派器技巧確實可用於小圖像或已緩存的圖像,但不適用於從後臺從互聯網下載的大圖像。任何想法如何延遲嘗試保存到XPS,直到1-2秒下載完成?或者更好,等到FlowDocument可能包含的所有圖像都完全下載並呈現? – BCA 2017-02-07 16:35:42

+0

@BCA你可以試試DispatcherPriority.Idle? – Will 2017-02-07 17:15:51

+0

是的,我使用了'DispatcherPriority.SystemIdle'。我想如果圖像在後臺下載,調度器技巧不起作用? – BCA 2017-02-07 17:28:47

0

你不必爲了有保存到XPS圖像顯示文檔。你是否在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

我試着調用XpsSerializationManager.Commit,但沒有達到預期的效果。 – 2012-03-12 22:30:20

+0

很抱歉,沒有及時回覆。這是一個真正的骯髒的版本,應該工作。讓我知道它怎麼變成了 – jfin3204 2012-03-17 15:21:02

+0

這個解決方案是否適合你? – jfin3204 2012-03-30 15:54:38