2010-02-23 25 views
11

Varias aplicaciones de WPF mías muestran FlowDocument. Puedo imprimirlos, utilizando el enfoque descrito en the answer to Printing a WPF FlowDocument.¿Cómo puedo producir una "vista previa de impresión" de un FlowDocument en una aplicación WPF?

Ahora me gustaría agregar una capacidad de "vista previa de impresión". En el caso normal, estoy imprimiendo el FlowDocument que se muestra en la ventana, y entonces no necesitaría una vista previa de impresión. Pero en algunos casos, el FlowDocument para imprimir se construye sobre la marcha en la memoria. Y en estos casos, me gustaría mostrarlo antes de imprimir.

Ahora, puedo ciertamente hacer estallar una nueva ventana y mostrar el FlowDocument, pero

  1. quiero la vista previa para realmente sentir como que es parte de la operación de impresión, y no sólo otra ventana en la aplicación.

  2. No quiero un FlowDocument normal en un FlowDocumentScrollViewer. En lugar de ser "de cualquier tamaño", debe estar limitado al tamaño del papel, a una relación HxW específica y paginado.

Sugerencias?

  • ¿Debo usar una ventana estándar, y en ese caso, cómo me asegurar la FlowDocument está en la proporción adecuada?

  • ¿hay una forma más "integrada" de hacer la vista previa dentro del alcance de la interfaz de usuario PrintDialog que es parte de Windows?

Gracias

+1

Hola Cheeso, esta respuesta http://stackoverflow.com/questions/584551/how-do-i-do-print-preview-when-using-a -documentpaginator-to-print/587962 # 587962 sugiere usar XpsDocument combinado con una ventana estándar ... No quiero escribirlo como respuesta, porque me temo que ya has visto ese enlace. Por si acaso. Saludos :) – Anvaka

Respuesta

19

la indirecta del comentario añadido a mi pregunta, lo hice:

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 
      { 
      } 
     } 
    } 
} 

Lo que hace: lo que realmente imprime el contenido de una representación visual en un documento XPS. A continuación, carga el documento XPS "impreso" y lo muestra en un archivo XAML muy simple que se almacena como una cadena, en lugar de como un módulo separado, y se carga dinámicamente en el tiempo de ejecución. La ventana resultante tiene los botones de DocumentViewer: imprimir, ajustar al máximo de la página, etc.

También agregué algunos códigos para ocultar el cuadro de búsqueda. Ver this answer to WPF: How can I remove the searchbox in a DocumentViewer? para saber cómo lo hice.

El efecto es como este:

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

El XpsDocument se puede encontrar en la DLL ReachFramework y la XpsDocumentWriter se puede encontrar en el sistema.Imprimiendo dll, los cuales deben agregarse como referencias al proyecto

+2

No puedo usar su código porque mi proyecto no pudo encontrar XpsDocument y no puede resolverlo. ¿Qué referencia debo agregar a mi proyecto? – icaptan

+1

Agregue referencias para ReachFramework y System.Printing como indica Cheeso, luego escriba 'using System.Windows.Xps; utilizando System.Windows.Xps.Packaging; utilizando System.Printing; 'para incluir. La mía compila sin problema. –

+2

¿qué es _parent? –

2

El control "FlowDocumentPageViewer" es la base para el control de "vista previa" que se utiliza en uno de nuestros proyectos. Aquí está el código XAML del control "DocumentPreviewer" (disculpas por la longitud - XAML no es sucinta):

<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> 

que pueden ser causa de un control de este tipo depende de usted (y su aplicación), por supuesto, pero nuestra aplicación tiene un comportamiento similar al de la aplicación típica de Office donde puede imprimir directamente u obtener una vista previa (que muestra la interfaz anterior) e imprimir desde allí.

+0

Definitivamente interesante, pero no quiero tener y administrar todo ese código! Esperaba una forma más simple. He aquí cómo lo hice: http://stackoverflow.com/questions/2322064/how-can-i-produce-a-print-preview-of-a-flowdocument-in-a-wpf-application/2322751#2322751 – Cheeso

Cuestiones relacionadas