How to print a user control in PDF instead of xps?

ComptonAlvaro 166 Reputation points
2022-04-24T17:12:47.393+00:00

When I want to print a user control, if I wanted to print to PDF, I have to covert the user control to a bitmap, if not, I get a blank page.

However, if I print to XPS, I get the pages.

Also I have realized this advantages of the XPS format:

It is saved like vectorial objects, so I can zoom all I want I always get the better quality.  
If it is text, I can select the text.  
The size of the document is lower.  

If I use a bitmap, the quality of text is worse, and I can't select it.

This is the code when I print it to PDF:

public static void ImprimirWpfToPdf(IEnumerable<dynamic> paramIeViewsParaImprimir, int paramFactorCalidad)  
{  
    FixedDocument miDocumento = new FixedDocument();  
  
    DpiScale miDpiScaleDelSistema = System.Windows.Media.VisualTreeHelper.GetDpi(paramIeViewsParaImprimir.ElementAt(0));  
  
  
  
    for (int i = 0; i < paramIeViewsParaImprimir.Count(); i++)  
    {  
        paramIeViewsParaImprimir.ElementAt(i).Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));  
        paramIeViewsParaImprimir.ElementAt(i).Arrange(new Rect(paramIeViewsParaImprimir.ElementAt(i).DesiredSize));  
        paramIeViewsParaImprimir.ElementAt(i).UpdateLayout();  
  
        Size miTamañoPagina = new Size(paramIeViewsParaImprimir.ElementAt(i).ActualWidth, paramIeViewsParaImprimir.ElementAt(i).ActualHeight);  
  
        int miAncho = (int)Math.Round(miTamañoPagina.Width / 2, MidpointRounding.AwayFromZero) * 2;  
        int miAlto = (int)Math.Round(miTamañoPagina.Height / 2, MidpointRounding.AwayFromZero) * 2;  
  
  
        System.Windows.Media.Imaging.RenderTargetBitmap bitmap = new System.Windows.Media.Imaging  
        .RenderTargetBitmap(miAncho * paramFactorCalidad, miAlto * paramFactorCalidad, (miDpiScaleDelSistema.PixelsPerInchX / miDpiScaleDelSistema.DpiScaleX) * paramFactorCalidad, (miDpiScaleDelSistema.PixelsPerInchY / miDpiScaleDelSistema.DpiScaleY) * paramFactorCalidad, System.Windows.Media.PixelFormats.Pbgra32);  
        bitmap.Render(paramIeViewsParaImprimir.ElementAt(i));  
  
  
        System.Windows.Controls.Image myImage = new System.Windows.Controls.Image();  
        myImage.Source = bitmap;  
  
  
        //Se crea una página del documento. La primera, que tendrá los calendarios.  
        FixedPage miPagina1 = new FixedPage();  
        miPagina1.Width = miTamañoPagina.Width;  
        miPagina1.Height = miTamañoPagina.Height;  
        miPagina1.Children.Add(bitmap);  
  
  
        PageContent miContenido1 = new PageContent();  
        ((IAddChild)miContenido1).AddChild(miPagina1);  
  
        miDocumento.Pages.Add(miContenido1);  
    }  
  
  
  
  
    System.Windows.Controls.PrintDialog myDialog = new System.Windows.Controls.PrintDialog();  
  
    if (myDialog.ShowDialog() == true)  
    {  
        try  
        {  
            //Print the image.  
            myDialog.PrintDocument(miDocumento.DocumentPaginator, string.Empty);  
        }  
        catch  
        {  
            //@#MEJORAR: realmente una librería nunca debería tener un messagebox. Se tiene que lanzar una excepción.  
            MessageBox.Show("El documento no se ha podido crear.\r\n\r\n"  
                + "Si está abierto y se está intentando sobreescribir, se recomienda cerrar el documento antes"  
                + " de imprimirlo.");  
        }  
    }  
}  

This is the code to print in XPS:

public static void ImprimirWpfToXps(IEnumerable<dynamic> paramIeViewsParaImprimir, int paramFactorCalidad)  
{  
    FixedDocument miDocumento = new FixedDocument();  
  
    DpiScale miDpiScaleDelSistema = System.Windows.Media.VisualTreeHelper.GetDpi(paramIeViewsParaImprimir.ElementAt(0));  
  
  
  
    for (int i = 0; i < paramIeViewsParaImprimir.Count(); i++)  
    {  
        paramIeViewsParaImprimir.ElementAt(i).Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));  
        paramIeViewsParaImprimir.ElementAt(i).Arrange(new Rect(paramIeViewsParaImprimir.ElementAt(i).DesiredSize));  
        paramIeViewsParaImprimir.ElementAt(i).UpdateLayout();  
  
        Size miTamañoPagina = new Size(paramIeViewsParaImprimir.ElementAt(i).ActualWidth, paramIeViewsParaImprimir.ElementAt(i).ActualHeight);  
  
        int miAncho = (int)Math.Round(miTamañoPagina.Width / 2, MidpointRounding.AwayFromZero) * 2;  
        int miAlto = (int)Math.Round(miTamañoPagina.Height / 2, MidpointRounding.AwayFromZero) * 2;  
  
    
        FixedPage miPagina1 = new FixedPage();  
        miPagina1.Width = miTamañoPagina.Width;  
        miPagina1.Height = miTamañoPagina.Height;  
        miPagina1.Children.Add(paramIeViewsParaImprimir.ElementAt(i));  
  
  
        PageContent miContenido1 = new PageContent();  
        ((IAddChild)miContenido1).AddChild(miPagina1);  
  
        miDocumento.Pages.Add(miContenido1);  
    }  
  
  
  
  
    System.Windows.Controls.PrintDialog myDialog = new System.Windows.Controls.PrintDialog();  
  
    if (myDialog.ShowDialog() == true)  
    {  
        try  
        {  
            //Print the image.  
            myDialog.PrintDocument(miDocumento.DocumentPaginator, string.Empty);  
        }  
        catch  
        {  
            //@#MEJORAR: realmente una librería nunca debería tener un messagebox. Se tiene que lanzar una excepción.  
            MessageBox.Show("El documento no se ha podido crear.\r\n\r\n"  
                + "Si está abierto y se está intentando sobreescribir, se recomienda cerrar el documento antes"  
                + " de imprimirlo.");  
        }  
    }  
}  

The unique difference between both is that, in the case of XPS, I don't create the bitmap and I add the user control directly to the fixed page.

This example code also it is needed to setup in windows as default printer, XPS printer or PDF printer in each case, but this has an easy solution.

Well, my question is, if in the XPS method version, if I have selected the Microsoft PDF Printer as default printer I get empty pages and if I print to XPS I get the pages that I want?

Thanks.

EDIT: I add a complete example that reproduce the error:

In this case I have realized that if I don't use an image as background of the user control it works, but if I use an image as background, then it doesn't work. So if you want to try this code, you should to use your own image.

The code behind of the main view:

public partial class MainWindow : Window  
    {  
        public MainWindow()  
        {  
            InitializeComponent();  
        }  
  
  
  
  
        private void Imprimir()  
        {  
            ControlUsuarioParaImprimir miControlUsuarioParaImprimir = new ControlUsuarioParaImprimir();  
  
  
            FixedDocument miDocumento = new FixedDocument();  
  
  
            miControlUsuarioParaImprimir.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));  
            miControlUsuarioParaImprimir.Arrange(new Rect(miControlUsuarioParaImprimir.DesiredSize));  
            miControlUsuarioParaImprimir.UpdateLayout();  
  
            Size miTamañoPagina = new Size(miControlUsuarioParaImprimir.ActualWidth, miControlUsuarioParaImprimir.ActualHeight);  
  
  
            FixedPage miPagina1 = new FixedPage();  
            miPagina1.Width = miTamañoPagina.Width;  
            miPagina1.Height = miTamañoPagina.Height;  
            miPagina1.Children.Add(miControlUsuarioParaImprimir);  
  
  
            PageContent miContenido1 = new PageContent();  
            ((IAddChild)miContenido1).AddChild(miPagina1);  
  
            miDocumento.Pages.Add(miContenido1);  
  
  
  
  
            System.Windows.Controls.PrintDialog myDialog = new System.Windows.Controls.PrintDialog();  
  
            if (myDialog.ShowDialog() == true)  
            {  
                try  
                {  
                    //Print the image.  
                    myDialog.PrintDocument(miDocumento.DocumentPaginator, string.Empty);  
                }  
                catch  
                {  
                    //@#MEJORAR: realmente una librería nunca debería tener un messagebox. Se tiene que lanzar una excepción.  
                    MessageBox.Show("El documento no se ha podido crear.\r\n\r\n"  
                        + "Si está abierto y se está intentando sobreescribir, se recomienda cerrar el documento antes"  
                        + " de imprimirlo.");  
                }  
            }  
        }  
  
  
        private void Button_Click(object sender, RoutedEventArgs e)  
        {  
            Imprimir();  
        }  
    }  

The xaml of the user control that I want to print:

<UserControl x:Class="ImprimirControlesUsuario.ControlUsuarioParaImprimir"  
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"   
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
             xmlns:local="clr-namespace:ImprimirControlesUsuario"  
             mc:Ignorable="d"   
             d:DesignHeight="450" d:DesignWidth="800">  
  
    <UserControl.Background>  
        <ImageBrush AlignmentX="Center" AlignmentY="Center" Stretch="Uniform" Opacity="0.20" ImageSource="Sol.jpg">  
            <ImageBrush.RelativeTransform>  
                <ScaleTransform ScaleX="0.65" ScaleY="0.65" CenterX=".5" CenterY="0.5" />  
            </ImageBrush.RelativeTransform>  
        </ImageBrush>  
    </UserControl.Background>  
  
    <Grid>  
        <Label Content="label 01" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="131"/>  
        <Label Content="label 02" HorizontalAlignment="Left" Margin="10,41,0,0" VerticalAlignment="Top" Width="131"/>  
    </Grid>  
</UserControl>  

This is the expected result, that I take when I print in XPS. If i print in PDF using the Microsoft To PDF printer the result is an empty page and the file size is 0kB.

196036-control-usuario.png

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,761 questions
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.