0
votes

I need to print a List through my UWP app. Since List can have N number of items so I need to show the pages in my print preview according to that and then print them all. I have tried few scenarios and looked at the sample of UWP Print app provided by Microsoft but in that they are using RichTextBlock for showing all the pages when the content is overflow. But I have a list so I would not know when my content is getting overflow. It just shows only first page in the print preview UI.

I have calculated the total pages also according to the size of A4 paper. Below is my C# code:

 if (PrintManager.IsSupported())
                            {
                                printDoc = new PrintDocument();
                                printDocSource = printDoc.DocumentSource;
                                _totalPages = (int)Math.Ceiling(wholeItemsListForPDF.Count / (double)15);
                                tempList = new ManifestPDFDataModel();
                                tempList = _manifestPDFDataModel;
                                printDoc.Paginate += PaginateManifestLabel;
                                for (int i = 1; i <= _totalPages; i++)
                                {
                                    printDoc.GetPreviewPage += GetPreviewPageManifestLabel;
                                    printDoc.AddPages += AddPagesManifestLabel;
                                    if (i != _totalPages)
                                    {
                                        _manifestPDFDataModel.ItemsPDFList.RemoveRange(0, 15);
                                        tempList.ItemsPDFList = _manifestPDFDataModel.ItemsPDFList;
                                    }
                                }
                                printMan = PrintManager.GetForCurrentView();
                                printMan.PrintTaskRequested += PrintTaskRequestedManifestLabel;

                                //printHelper = new PrintHelper(this);
                                //printHelper.RegisterForPrinting();

                                //// Initialize print content for this scenario
                                //printHelper.PreparePrintContent(new GenericManifestPDF(_manifestPDFDataModel));

                                try
                                {
                                    // Show print UI
                                    await PrintManager.ShowPrintUIAsync();
                                }
                                catch (Exception ex)
                                {
                                    // Printing cannot proceed at this time
                                    ContentDialog noPrintingDialog = new ContentDialog()
                                    {
                                        Title = "Printing error",
                                        Content = "\nSorry, printing can' t proceed at this time.",
                                        PrimaryButtonText = "OK"
                                    };
                                    printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
                                    printDoc.Paginate -= PaginateManifestLabel;
                                    printDoc.GetPreviewPage -= GetPreviewPageManifestLabel;
                                    printDoc.AddPages -= AddPagesManifestLabel;
                                    await noPrintingDialog.ShowAsync();
                                }
                            }
                            else
                            {
                                // Printing is not supported on this device
                                ContentDialog noPrintingDialog = new ContentDialog()
                                {
                                    Title = "Printing not supported",
                                    Content = "\nSorry, printing is not supported on this device.",
                                    PrimaryButtonText = "OK"
                                };
                                printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
                                printDoc.Paginate -= PaginateManifestLabel;
                                printDoc.GetPreviewPage -= GetPreviewPageManifestLabel;
                                printDoc.AddPages -= AddPagesManifestLabel;
                                await noPrintingDialog.ShowAsync();
                            }

All the Print related events:

 public void PrintTaskRequestedManifestLabel(PrintManager sender, PrintTaskRequestedEventArgs args)
    {
        // Create the PrintTask.
        // Defines the title and delegate for PrintTaskSourceRequested
        var printTask = args.Request.CreatePrintTask("Print", PrintTaskSourceRequestedManifestLabel);

        // Handle PrintTask.Completed to catch failed print jobs
        printTask.Completed += PrintTaskCompletedManifestLabel;

    }
    /// <summary>
    /// PrintTaskSourceRequestedManifestLabel
    /// </summary>
    /// <param name="args">PrintTaskSourceRequestedArgs</param>
    public void PrintTaskSourceRequestedManifestLabel(PrintTaskSourceRequestedArgs args)
    {
        // Set the document source.
        args.SetSource(printDocSource);
    }


    #region Print preview
    /// <summary>
    /// Pagination Manifest Label
    /// </summary>
    /// <param name="sender">pass sender object</param>
    /// <param name="e">PaginateEventArgs</param>
    public void PaginateManifestLabel(object sender, PaginateEventArgs e)
    {
        // As I only want to print one Rectangle, so I set the count to 1
        printDoc.SetPreviewPageCount(_totalPages, PreviewPageCountType.Intermediate);
    }
    /// <summary>
    /// Print Preview Page ManifestLabel SetPreviewPage
    /// </summary>
    /// <param name="sender">pass sender object</param>
    /// <param name="e">GetPreviewPageEventArgs</param>
    public void GetPreviewPageManifestLabel(object sender, GetPreviewPageEventArgs e)
    {
        // Provide a UIElement as the print preview.
        printDoc.SetPreviewPage(e.PageNumber, new GenericManifestPDF(tempList));
    }

    #endregion

    #region Add pages to send to the printer
    /// <summary>
    /// Add Pages ManifestLabel
    /// </summary>
    /// <param name="sender">pass sender object</param>
    /// <param name="e">AddPagesEventArgs</param>
    public void AddPagesManifestLabel(object sender, AddPagesEventArgs e)
    {
        printDoc.AddPage(new GenericManifestPDF(tempList));

        // Indicate that all of the print pages have been provided
        printDoc.AddPagesComplete();
    }

    #endregion

    #region Print task completed
    /// <summary>
    /// Print Task Completed ManifestLabel 
    /// </summary>
    /// <param name="sender">PrintTask</param>
    /// <param name="args">PrintTaskCompletedEventArgs</param>
    public async void PrintTaskCompletedManifestLabel(PrintTask sender, PrintTaskCompletedEventArgs args)
    {
        // Notify the user when the print operation fails.
        if (args.Completion == PrintTaskCompletion.Failed)
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
            {
                ContentDialog noPrintingDialog = new ContentDialog()
                {
                    Title = "Printing error",
                    Content = "\nSorry, failed to print.",
                    PrimaryButtonText = "OK"
                };
                printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
                printDoc.Paginate -= PaginateManifestLabel;
                printDoc.GetPreviewPage -= GetPreviewPageManifestLabel;
                printDoc.AddPages -= AddPagesManifestLabel;
                await noPrintingDialog.ShowAsync();
            });
        }
        else
        {
            printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
            //printDoc.Paginate -= Paginate;
            //printDoc.GetPreviewPage -= GetPreviewPage;
            //printDoc.AddPages -= AddPages;
        }
    }

    #endregion

XAML Page code:

<Grid>

    <Grid.RowDefinitions>
        <RowDefinition Height="30*"/>
        <RowDefinition Height="70*"/>
    </Grid.RowDefinitions>

    <Grid BorderBrush="Black" BorderThickness="2" Margin="30">
        <Grid.RowDefinitions>
            <RowDefinition Height="80*"/>
            <RowDefinition Height="20*"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <TextBlock Text="Manifest PDF Report" Foreground="Black" FontWeight="Bold" Margin="20,20,0,0"/>
                <TextBlock x:Name="Function" Foreground="Black" Grid.Row="1" FontWeight="Bold" Margin="20,20,0,0"/>
                <TextBlock x:Name="Counts" Grid.Row="2" Foreground="Black" FontWeight="Bold" Margin="20,20,0,0"/>
            </Grid>
            <Grid Grid.Column="1">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <TextBlock x:Name="PrintedValue" Foreground="Black" FontWeight="Bold" Margin="20,20,0,0"/>
                <TextBlock x:Name="RouteValue" Foreground="Black" Grid.Row="1" FontWeight="Bold" Margin="20,20,0,0"/>
                <TextBlock x:Name="BatchIDValue" Grid.Row="2" Foreground="Black" FontWeight="Bold" Margin="20,20,0,0"/>
            </Grid>
            <Grid Grid.Column="2">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Image x:Name="BarcodeImage" Margin="20,0,0,0" HorizontalAlignment="Center"/>
                <TextBlock x:Name="BatchBarcodeText" Grid.Row="1" Foreground="Black" FontWeight="Bold" Margin="20,20,0,0"/>
            </Grid>
        </Grid>
        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="Delivered By :" Foreground="Black" Margin="20,0,0,0" VerticalAlignment="Center"/>
            <TextBlock Text="Batch Delivery Time :" Foreground="Black" Grid.Column="1" Margin="20,0,0,0" VerticalAlignment="Center"/>
        </Grid>
    </Grid>
    <Grid Grid.Row="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="10*"/>
            <RowDefinition Height="90*"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock FontWeight="Bold" Text="BILL#" Foreground="Black" TextDecorations="Underline" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="1" Foreground="Black" TextDecorations="Underline" Text="Carrier" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="2" Foreground="Black" TextDecorations="Underline" Text="Package" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="3" Foreground="Black" TextDecorations="Underline" Text="Location" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="4" Text="ItemType" Foreground="Black" TextDecorations="Underline" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="5" Foreground="Black" TextDecorations="Underline" Text="Deliver To" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="6" Foreground="Black" TextDecorations="Underline" Text="Sender" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="7" Foreground="Black" TextDecorations="Underline" Text="Date" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="8" Foreground="Black" TextDecorations="Underline" Text="PO" Margin="20,20,0,0"/>
            <TextBlock FontWeight="Bold" Grid.Column="9" Foreground="Black" TextDecorations="Underline" Text="Control" Margin="20,20,0,0"/>
        </Grid>
        <ListView Grid.Row="1" x:Name="PDFItemsList" IsItemClickEnabled="False">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="BorderThickness" Value="0,0,0,1" />
                    <Setter Property="BorderBrush" Value="Black"/>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ContentControl Style="{StaticResource EmptyContentControlStyle}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding Bill}" Grid.Column="0" Foreground="Black" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding CarrierName}" HorizontalAlignment="Right" Grid.Column="1" Foreground="Black" Grid.Row="1" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding PackageID}" HorizontalAlignment="Right" Foreground="Black" Grid.Column="2" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding Location}" HorizontalAlignment="Right" Foreground="Black" Grid.Column="3" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding ItemType}" HorizontalAlignment="Right" Foreground="Black" Grid.Column="4" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding DeliverTo}" HorizontalAlignment="Right" Foreground="Black" Grid.Column="5" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding Sender}" HorizontalAlignment="Right" Grid.Column="6" Foreground="Black" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding CreationDate}" HorizontalAlignment="Right" Foreground="Black" Grid.Column="7" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding PONumber}" Foreground="Black" HorizontalAlignment="Right" Grid.Column="8" Margin="20,20,0,0"/>
                            <TextBlock Text="{Binding ControlNumber}" HorizontalAlignment="Right" Foreground="Black" Grid.Column="9" Margin="20,20,0,0"/>
                        </Grid>
                    </ContentControl>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Grid>

Thanks in advance.

1
Please check official print sample Scenario4PageRange.Nico Zhu - MSFT
They are using RichTextBlock in PageToPrint frame. I don't have that in my app. I have ListView.tushargoyal1309
The better way is that use rendertargetbitmap to make the listview as image then print.Nico Zhu - MSFT
ListView can contain N number of records so it would be quite long process and time taking.tushargoyal1309
you need scroll the listview and make several targetbitmap then stitch the targetbitmap together。Nico Zhu - MSFT

1 Answers

0
votes

After two days I'm finally able to do it now. Here is the solution:

We need to use 'Skip' and 'Take' methods using Linq until we reach the total pages of the list and along with that we need to keep on updating the list. Total pages are determined by how many items are fitting into the A4 size paper. In my case that is 11. So my 'Paginate' event looks like this:

 protected FrameworkElement firstPage;

 public void PaginateManifestLabel(object sender, PaginateEventArgs e)
    {
        // Clear the cache of preview pages
        printPreviewPages.Clear();

        // Clear the print canvas of preview pages
        PrintCanvas.Children.Clear();

        // This variable keeps track of the last RichTextBlockOverflow element that was added to a page which will be printed
        ListView lastRTBOOnPage = null;

        // Get the PrintTaskOptions
        PrintTaskOptions printingOptions = ((PrintTaskOptions)e.PrintTaskOptions);
        // Get the page description to deterimine how big the page is
        PrintPageDescription pageDescription = printingOptions.GetPageDescription(0);

        // We know there is at least one page to be printed. passing null as the first parameter to
        // AddOnePrintPreviewPage tells the function to add the first page.
        //lastRTBOOnPage = AddOnePrintPreviewPage(null, pageDescription);

        // We know there are more pages to be added as long as the last RichTextBoxOverflow added to a print preview
        // page has extra content
        int i = 0;
        while (i < _totalPages)
        {


            _manifestPDFDataModelforPriniPagination.ItemsPDFList = tempList.ItemsPDFList.Skip(i * 11).Take(11).ToList();


            lastRTBOOnPage = AddOnePrintPreviewPage(lastRTBOOnPage, pageDescription);

            i++;
        }



        PrintDocument printDoc = (PrintDocument)sender;

        // Report the number of preview pages created
        printDoc.SetPreviewPageCount(printPreviewPages.Count, PreviewPageCountType.Intermediate);
    }

AddOnePrintPreviewPage:

private ListView AddOnePrintPreviewPage(ListView lastRTBOAdded, PrintPageDescription printPageDescription)
    {
        // XAML element that is used to represent to "printing page"
        FrameworkElement page;

        // The link container for text overflowing in this page
        ListView textLink;

        // Check if this is the first page ( no previous RichTextBlockOverflow)
        if (lastRTBOAdded == null)
        {
            // If this is the first page add the specific scenario content
            page = firstPage;
        }
        else
        {
            // Flow content (text) from previous pages
            page = new GenericManifestPDF(_manifestPDFDataModelforPriniPagination);
        }
        // Set "paper" width
        page.Width = printPageDescription.PageSize.Width;
        page.Height = printPageDescription.PageSize.Height;
        // Find the last text container and see if the content is overflowing
        textLink = (ListView)page.FindName("PDFItemsList");
        // Add the page to the page preview collection
        printPreviewPages.Add(page);

        return textLink;
    }

GetPreviewPageManifestLabel:

 public void GetPreviewPageManifestLabel(object sender, GetPreviewPageEventArgs e)
    {
        // Provide a UIElement as the print preview.
        PrintDocument printDoc = (PrintDocument)sender;
        printDoc.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
    }

AddPagesManifestLabel:

 public void AddPagesManifestLabel(object sender, AddPagesEventArgs e)
    {
        for (int i = 0; i < printPreviewPages.Count; i++)
        {
            // We should have all pages ready at this point...
            printDoc.AddPage(printPreviewPages[i]);
        }
        PrintDocument printDocument = (PrintDocument)sender;

        // Indicate that all of the print pages have been provided
        printDocument.AddPagesComplete();
    }

PrintTaskRequestedManifestLabel:

public void PrintTaskRequestedManifestLabel(PrintManager sender, PrintTaskRequestedEventArgs args)
    {
        // Create the PrintTask.
        // Defines the title and delegate for PrintTaskSourceRequested
        var printTask = args.Request.CreatePrintTask("Print", PrintTaskSourceRequestedManifestLabel);
        printTask.Options.Orientation = PrintOrientation.Landscape;


        // Handle PrintTask.Completed to catch failed print jobs
        printTask.Completed += PrintTaskCompletedManifestLabel;

    }

PrintTaskSourceRequestedManifestLabel:

public void PrintTaskSourceRequestedManifestLabel(PrintTaskSourceRequestedArgs args)
    {
        // Set the document source.
        args.SetSource(printDocSource);
    }

PrintTaskCompletedManifestLabel:

 public async void PrintTaskCompletedManifestLabel(PrintTask sender, PrintTaskCompletedEventArgs args)
    {
        // Notify the user when the print operation fails.
        if (args.Completion == PrintTaskCompletion.Failed)
        {
            await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
            {
                ContentDialog noPrintingDialog = new ContentDialog()
                {
                    Title = "Printing error",
                    Content = "\nSorry, failed to print.",
                    PrimaryButtonText = "OK"
                };
                printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
                printDoc.Paginate -= PaginateManifestLabel;
                printDoc.GetPreviewPage -= GetPreviewPageManifestLabel;
                printDoc.AddPages -= AddPagesManifestLabel;
                await noPrintingDialog.ShowAsync();
            });
        }
        else
        {
            printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
        }
    }

PreparePrintContent:

 public void PreparePrintContent(GenericManifestPDF page)
    {
        firstPage = null;
        if (firstPage == null)
        {
            firstPage = page;
        }
    }

And finally you need to call these events like this:

 if (PrintManager.IsSupported())
                            {
                                printDoc = new PrintDocument();
                                printDocSource = printDoc.DocumentSource;
                                _totalPages = (int)Math.Ceiling(wholeItemsListForPDF.Count / (double)11);
                                tempList = new ManifestPDFDataModel();
                                tempList = _manifestPDFDataModel;
                                printDoc.Paginate += PaginateManifestLabel;
                                printDoc.GetPreviewPage += GetPreviewPageManifestLabel;
                                printDoc.AddPages += AddPagesManifestLabel;
                                printMan = PrintManager.GetForCurrentView();
                                printMan.PrintTaskRequested += PrintTaskRequestedManifestLabel;
                                PreparePrintContent(new GenericManifestPDF(_manifestPDFDataModel));


                                try
                                {
                                    // Show print UI
                                    await PrintManager.ShowPrintUIAsync();
                                }
                                catch (Exception ex)
                                {
                                    // Printing cannot proceed at this time
                                    ContentDialog noPrintingDialog = new ContentDialog()
                                    {
                                        Title = "Printing error",
                                        Content = "\nSorry, printing can' t proceed at this time.",
                                        PrimaryButtonText = "OK"
                                    };
                                    printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
                                    printDoc.Paginate -= PaginateManifestLabel;
                                    printDoc.GetPreviewPage -= GetPreviewPageManifestLabel;
                                    printDoc.AddPages -= AddPagesManifestLabel;

                                    await noPrintingDialog.ShowAsync();
                                }
                            }
                            else
                            {
                                //Printing is not supported on this device
                               ContentDialog noPrintingDialog = new ContentDialog()
                               {
                                   Title = "Printing not supported",
                                   Content = "\nSorry, printing is not supported on this device.",
                                   PrimaryButtonText = "OK"
                               };
                                printMan.PrintTaskRequested -= PrintTaskRequestedManifestLabel;
                                printDoc.Paginate -= PaginateManifestLabel;
                                printDoc.GetPreviewPage -= GetPreviewPageManifestLabel;
                                printDoc.AddPages -= AddPagesManifestLabel;
                                await noPrintingDialog.ShowAsync();

                            }