2010-03-11 18 views
5

FlowDocument bir XPS belgesi olarak kaydedildiğinde, bir FlowDocument öğesinde bulunan görüntülerin gösterilmesi konusunda bazı zorluklar yaşıyorum. İşte FlowDocument içinde XPS belgesi olarak kaydedilen eksik resimler

benim yaptığım:

  1. WPF Image kontrolü kullanarak bir görüntü oluşturun. Başlangıç ​​kaynağını BeginInit/EndInit'e yönlendiren görüntü kaynağını ayarlıyorum.
  2. Görüntüyü, BlockUIContainer ürününde bulunan FlowDocument dosyasına ekleyin.
  3. FlowDocument nesnesini, this code'un değiştirilmiş bir sürümünü kullanarak bir XPS dosyasına kaydedin.

Kaydedilen dosyayı XPS görüntüleyicide görüntülediğimde, görüntü gösterilmez. Sorun, görüntülerin WPF tarafından ekranda gösterilene kadar yüklenmemesi ve böylece XPS dosyasına kaydedilmemeleridir. Bu nedenle, bir geçici çözüm var: Belgeyi FlowDocumentPageViewer kullanarak ekranda ilk görüntüledikten sonra XPS dosyasını daha sonra kaydedersem, görüntü yüklenir ve XPS dosyasında görünür. Bu FlowDocumentPageViewer gizli olsa bile çalışır. Ama bu bana başka bir meydan okuma veriyor. Burada (pseudocode) yapmak isteyen budur: FlowDocumentPageViewer asla belge XPS dosyasına kaydedilir önce içeriğini göstermek için bir şans olur çünkü

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

Bu işe yaramaz. Dispatcher.BeginInvoke bir çağrıya SaveFlowDocumentToXpsFile sarma çalıştı ancak yardımcı olmadı.

Sorularım şunlardır:

  1. ben bir şekilde aslında ekranda belge göstermeden XPS dosyayı kaydetmeden önce yüklemeye görüntüleri zorlayabilir miyim? (Hiçbir şansla BitmapImage.CreateOptions ile uğraşmaya çalıştı).
  2. # 1 numaralı soruya çözüm bulunmuyorsa, FlowDocumentPageViewer'ın içeriğini ne zaman yüklemeyi bitirdiğini anlamanın bir yolu var, böylece XPS dosyasını oluşturmak için ne zaman kaydedileceğini biliyorum.
+0

Yazdırma öncesinde FlowDocument'i bir görüntüleyicide göstermenin bir yolunu buldunuz mu? Belgesini doğru şekilde oluşturması için benzer bir "kesmek" düşünürüm. – Dennis

+0

@DennisRoche: Hayır, ne yazık ki bir dosyaya kaydetmeden önce ekranda kısaca belgeyi gösteren daha iyi bir çözüm bulamadılar. Daha iyi bir çözüm bulursanız lütfen bize bildirin. –

+0

Mantıksal bir ağaca yürümek için 'ContextualLayoutManager'ı kullanan olası bir çözümüm olabilir. Çalışırsa, size bildireceğim. Aksi halde, yaptığınız gibi belgeyi bir görüntüleyiciye yüklemeyi tercih ederim, ancak pencere yerini X: 10,000 Y: 10,000 olarak ayarlayacaktır, böylece kullanıcı bunu görmeyecektir. – Dennis

cevap

0

nihai çözüm aynıydı. Aşağıda benim için bunu yapmak için yazdığım yardımcı yöntem.

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

Düzenleme: hızlı olsaydı pencere görev çubuğunda görünen alabildiğine Sadece yöntemine window.ShowInTaskbar = false eklendi. Kullanıcı, ekranın önünden ekrana yerleştirildiği için Int32.MaxValue numaralı pencereyi asla görüntülemez - bu, gün içerisinde çok sayıda multimedya yazımı (ör. Macromedia/Adobe Director) ile ortak olan bir hiledir.

Bu soruyu arayan ve bulabileceğiniz kişiler için, belgeyi oluşturmaya zorlamak için 'un başka bir yolu olmadığını söyleyebilirim.

HTH,

+0

Cevabınız için teşekkür ederiz. Farklı bir çözümü görmeyi çok isterdim bile cevabınızı kabul edilen cevap olarak işaretledim ;-). –

+0

Daha iyi bir çözüm isterdim, ancak diğer tüm olasılıkları tükettiğime inanıyorum. Kullanıcı, ** pencerenin ekran dışı olarak göründüğünü asla görmeyeceği için oldukça temiz bir çözümdür. – Dennis

+0

Ayrıca, bugüne kadar yaptığım en kötü hack değil. – Dennis

1

Çift şeyler ... Görüntünün yazılmadan önce boyutundan emin misiniz? Ayrıca

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

(sonsuz kontrolü onun Genişlik ve Yükseklik genişletmek sağlar) o boyutu buna göre kendisinin may böylece Genellikle her şeyi güncellenir, böylece bazen UI iş parçacığı çarpmak zorunda kumanda üzerindeki ölçün aramak zorunda bir izleyici belgeyi koymak ve kısaca ekranda göstermek için hangi geldi sürede kontrol

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

Dispatcher hüner gerçekten arka planda internetten indirmek büyük görüntüler için önceden önbelleğe küçük resimler veya olanlar için çalışır, ancak etmediğini kullanma. 1-2 saniyelik indirme işlemine kadar XPS'e kaydetme girişiminin nasıl geciktirileceği hakkında bir fikriniz var mı? Ya da daha iyi, FlowDocument'in içerdiği tüm görüntüler tamamen indirilip oluşturulmasını bekleyin. – BCA

+0

@BCA DispatcherPriority.Idle deneyebilirsiniz? – Will

+0

evet, 'DispatcherPriority.SystemIdle' kullanılır. Görüntü arka planda indiriliyorsa dağıtıcı hilesi çalışmıyor mu? – BCA

0

Sen xps içine kaydedilmiş görüntüleri sahip olmak için belgeyi görüntülemek için gerekmez. XpsSerializationManager'da taahhüt mi arıyorsun?

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'i aramayı denedim ancak istenen etkiyi almadı. –

+0

Daha önce yanıtlamadığım için üzgünüz. İşte çalışması gereken gerçek bir kirli sürümüdür. Bana nasıl geldiğini bildirin. – jfin3204

+0

Bu çözüm sizin için işe yarıyor mu? – jfin3204

İlgili konular