2010-02-23 8 views
11

Différentes applications WPF de la mine affichent FlowDocument. Je suis capable de les imprimer en utilisant l'approche décrite dans the answer to Printing a WPF FlowDocument. Maintenant, je voudrais ajouter une fonctionnalité "Aperçu avant impression". Dans le cas normal, j'imprime le FlowDocument qui est affiché dans la fenêtre, et donc je n'aurais pas besoin d'un aperçu avant impression. Mais dans certains cas, le FlowDocument à imprimer est construit à la volée en mémoire. Et dans ces cas je voudrais l'afficher avant d'imprimer.Comment puis-je produire un "aperçu avant impression" d'un FlowDocument dans une application WPF?

Maintenant, je peux certainement pop une nouvelle fenêtre et afficher le FlowDocument, mais

  1. Je veux l'aperçu vraiment sentir comme il fait partie de l'opération d'impression, et non pas seulement une autre fenêtre l'application. Je ne veux pas un FlowDocument normal dans un FlowDocumentScrollViewer. Plutôt que d'être «n'importe quelle taille», elle doit être limitée à la taille du papier, à un ratio HxW spécifique et paginée.

Suggestions?

  • est-ce que je devrais juste employer une fenêtre standard, et dans ce cas, comment je m'assure que le FlowDocument est au bon rapport?

  • Y a-t-il une façon plus "intégrée" de faire l'aperçu dans le cadre de l'interface utilisateur PrintDialog qui fait partie de Windows?

Merci

+1

Salut Cheeso, cette réponse http://stackoverflow.com/questions/584551/how-do-i-do-print-preview-when-using-a -documentpaginator-to-print/587962 # 587962 suggère d'utiliser XpsDocument combiné avec une fenêtre standard ... Je ne veux pas l'écrire comme une réponse, parce que je crains que vous avez déjà vu ce lien. Au cas où. Salutations :) – Anvaka

Répondre

19

Prendre l'indice du commentaire ajouté à ma question, je l'ai fait:

private string _previewWindowXaml = 
    @"<Window 
     xmlns     ='http://schemas.microsoft.com/netfx/2007/xaml/presentation' 
     xmlns:x    ='http://schemas.microsoft.com/winfx/2006/xaml' 
     Title     ='Print Preview - @@TITLE' 
     Height    ='200' 
     Width     ='300' 
     WindowStartupLocation ='CenterOwner'> 
     <DocumentViewer Name='dv1'/> 
    </Window>"; 

internal void DoPreview(string title) 
{ 
    string fileName = System.IO.Path.GetRandomFileName(); 
    FlowDocumentScrollViewer visual = (FlowDocumentScrollViewer)(_parent.FindName("fdsv1")); 
    try 
    { 
     // write the XPS document 
     using (XpsDocument doc = new XpsDocument(fileName, FileAccess.ReadWrite)) 
     { 
      XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc); 
      writer.Write(visual); 
     } 

     // Read the XPS document into a dynamically generated 
     // preview Window 
     using (XpsDocument doc = new XpsDocument(fileName, FileAccess.Read)) 
     { 
      FixedDocumentSequence fds = doc.GetFixedDocumentSequence(); 

      string s = _previewWindowXaml; 
      s = s.Replace("@@TITLE", title.Replace("'", "&apos;")); 

      using (var reader = new System.Xml.XmlTextReader(new StringReader(s))) 
      { 
       Window preview = System.Windows.Markup.XamlReader.Load(reader) as Window; 

       DocumentViewer dv1 = LogicalTreeHelper.FindLogicalNode(preview, "dv1") as DocumentViewer; 
       dv1.Document = fds as IDocumentPaginatorSource; 


       preview.ShowDialog(); 
      } 
     } 
    } 
    finally 
    { 
     if (File.Exists(fileName)) 
     { 
      try 
      { 
       File.Delete(fileName); 
      } 
      catch 
      { 
      } 
     } 
    } 
} 

Ce qu'il fait: il imprime en fait le contenu d'un visuel dans un document XPS. Ensuite, il charge le document XPS «imprimé» et l'affiche dans un fichier XAML très simple qui est stocké sous forme de chaîne, plutôt que comme un module séparé, et chargé dynamiquement à l'exécution. La fenêtre qui en résulte a les boutons DocumentViewer: print, adjust-to-max-page-width, et ainsi de suite.

J'ai également ajouté du code pour cacher la boîte de recherche. Voir this answer to WPF: How can I remove the searchbox in a DocumentViewer? pour comment j'ai fait ça.

L'effet est comme ceci:

alt text http://i48.tinypic.com/2hzkfat.jpg

Le XpsDocument se trouve dans la dll ReachFramework et la XpsDocumentWriter se trouve dans le système.Impression dll les deux qui doivent être ajoutés en tant que références au projet

+2

Je ne peux pas utiliser votre code car mon projet n'a pas pu trouver XpsDocument et ne peut pas le résoudre. Quelle référence dois-je ajouter à mon projet? – icaptan

+1

Ajoutez les références pour ReachFramework et System.Printing comme états Cheeso, puis écrivez 'using System.Windows.Xps; using System.Windows.Xps.Packaging; using System.Printing; 'inclure. Mine compile sans problème. –

+2

Qu'est-ce que _parent? –

2

Le contrôle « FlowDocumentPageViewer » est la base de la commande « preview » utilisé dans l'un de nos projets. Voici le XAML du « DocumentPreviewer » contrôle (excuses pour la longueur - XAML n'est pas succincte):

<Control 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" 
    xmlns:l="clr-namespace:Tyler.ComPort.UI" 
    mc:Ignorable="d" 
    x:Class="Tyler.ComPort.UI.DocumentPreviewer" 
    x:Name="UserControl" 
    Background="Gray" 
    d:DesignWidth="640" d:DesignHeight="480"> 
    <Control.Resources> 
     <ObjectDataProvider x:Key="ViewStyles" MethodName="GetValues" ObjectType="{x:Type sys:Enum}" > 
      <ObjectDataProvider.MethodParameters> 
       <x:Type TypeName="l:ViewType" /> 
      </ObjectDataProvider.MethodParameters> 
     </ObjectDataProvider> 
     <l:EnumMatchVisibilityConverter x:Key="EnumVisibilityConverter" /> 
    </Control.Resources> 
    <Control.Template> 
     <ControlTemplate> 
      <ControlTemplate.Triggers> 
       <Trigger Property="l:DocumentPreviewer.ViewType"> 
        <Trigger.Value> 
         <l:ViewType>Actual</l:ViewType> 
        </Trigger.Value> 
        <Trigger.Setters> 
         <Setter TargetName="ScrollViewer" Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" /> 
         <Setter TargetName="ScrollViewer" Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" /> 
         <Setter TargetName="Viewbox" Property="Viewbox.Stretch" Value="None" /> 
        </Trigger.Setters> 
       </Trigger> 
       <Trigger Property="l:DocumentPreviewer.ViewType"> 
        <Trigger.Value> 
         <l:ViewType>Fit</l:ViewType> 
        </Trigger.Value> 
        <Trigger.Setters> 
         <Setter TargetName="ScrollViewer" Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" /> 
         <Setter TargetName="ScrollViewer" Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled" /> 
         <Setter TargetName="Viewbox" Property="Viewbox.Stretch" Value="Uniform" /> 
        </Trigger.Setters> 
       </Trigger> 
       <Trigger Property="l:DocumentPreviewer.ViewType"> 
        <Trigger.Value> 
         <l:ViewType>Wide</l:ViewType> 
        </Trigger.Value> 
        <Trigger.Setters> 
         <Setter TargetName="ScrollViewer" Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" /> 
         <Setter TargetName="ScrollViewer" Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" /> 
         <Setter TargetName="Viewbox" Property="Viewbox.Stretch" Value="UniformToFill" /> 
        </Trigger.Setters> 
       </Trigger> 
      </ControlTemplate.Triggers> 
      <DockPanel> 
       <ToolBar DockPanel.Dock="Top"> 
        <Button Command="{x:Static ApplicationCommands.Print}" CommandTarget="{Binding ElementName=PageViewer}" Content="Print..." /> 
        <Separator /> 
        <Button Command="{x:Static NavigationCommands.PreviousPage}" CommandTarget="{Binding ElementName=PageViewer}" Content="&lt; Previous" /> 
        <Button Command="{x:Static NavigationCommands.NextPage}" CommandTarget="{Binding ElementName=PageViewer}" Content="Next &gt;" /> 
        <Separator /> 
        <l:ToolBarButtonGroup 
         ItemsSource="{Binding Source={StaticResource ViewStyles}}" 
         SelectedItem="{Binding ViewType, ElementName=UserControl}" 
         IsSynchronizedWithCurrentItem="True" 
         > 
         <l:ToolBarButtonGroup.ItemTemplate> 
          <DataTemplate> 
           <StackPanel Orientation="Horizontal" ToolTip="{Binding}" SnapsToDevicePixels="True"> 
            <Image Source="../Images/actual.png" Visibility="{Binding Converter={StaticResource EnumVisibilityConverter}, ConverterParameter=Actual}" /> 
            <Image Source="../Images/fit.png" Visibility="{Binding Converter={StaticResource EnumVisibilityConverter}, ConverterParameter=Fit}" /> 
            <Image Source="../Images/wide.png" Visibility="{Binding Converter={StaticResource EnumVisibilityConverter}, ConverterParameter=Wide}" /> 
           </StackPanel> 
          </DataTemplate> 
         </l:ToolBarButtonGroup.ItemTemplate> 
        </l:ToolBarButtonGroup> 
       </ToolBar> 
       <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled"> 
        <Border 
          BorderBrush="Black" 
          BorderThickness="1" 
          HorizontalAlignment="Center" 
          VerticalAlignment="Top" 
          Background="White" 
          Margin="10"> 
         <Viewbox x:Name="Viewbox" Stretch="Uniform"> 
          <FlowDocumentPageViewer 
           x:Name="PageViewer" 
           Document="{Binding Document, ElementName=UserControl}" 
           Zoom="100" 
           MinZoom="20" 
           MaxZoom="200"> 
           <FlowDocumentPageViewer.Template> 
            <ControlTemplate TargetType="{x:Type FlowDocumentPageViewer}"> 
             <AdornerDecorator> 
              <DocumentPageView FlowDocumentPageViewer.IsMasterPage="True" /> 
             </AdornerDecorator> 
            </ControlTemplate> 
           </FlowDocumentPageViewer.Template> 
          </FlowDocumentPageViewer> 
         </Viewbox> 
        </Border> 
       </ScrollViewer> 
      </DockPanel> 
     </ControlTemplate> 
    </Control.Template> 
</Control> 

où vous pourriez mettre un tel contrôle est à vous (et votre application) bien sûr, mais notre application a un comportement similaire à l'application Office typique où vous pouvez soit imprimer directement ou afficher un aperçu (qui montre l'interface ci-dessus) et imprimer à partir de là.

+0

Certainement intéressant, mais je ne veux pas posséder et gérer tout ce code! J'espérais un moyen plus simple. Voici comment je l'ai fait: http://stackoverflow.com/questions/2322064/how-can-i-produce-a-print-preview-of-a-flowdocument-in-a-wpf-application/2322751#2322751 – Cheeso

Questions connexes