Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print in UWP app?

I am trying to print out something from my UWP app. Basically I've used a WebViewBrush to draw some data on to some FrameworkElement's (Windows.UI.Xaml.Shapes.Rectangle) - and I want to print one of these Rectangles on each page (one rectangle per page)

I was really hoping someone could provide a very simple example of how printing in UWP works. I have tried it myself and I am happy to provide my code, but there are honestly thousands of lines - all of which I've taken from the Microsoft GitHub examples and tried tweaking:

  • https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/Printing

Honestly, those examples are too complicated I think. What I want is just a really simple way to print. I can't find any tutorials on this topic either, but I figure if someone has a small code snippet that I could get working maybe I could build on it so it will work with Rectangles (rather than what I'm doing now - taking a huge example from Microsoft and trying to figure out which parts I don't need).

Thank you. I think anyone that can answer this question in a simple way will find this will become a definitive reference point in the future - because information online about this topic is so scarce.

like image 715
b85411 Avatar asked Aug 22 '16 08:08

b85411


People also ask

What are print workflow applications?

A workflow app is able to alter both the print ticket (the XML document that configures the printer device settings for the current print task) and the actual XPS content to be printed. It can optionally expose this functionality to the user by launching a UI midway through the process.

What is UWP used for?

UWP is one choice for creating apps that run on Windows 10 and Windows 11 devices, and can be combined with other platforms. UWP apps can make use of Win32 APIs and . NET classes (see API Sets for UWP apps, Dlls for UWP apps, and . NET for UWP apps).

How is UWP different from WPF?

WPF is another UI framework, and UWP uses many concepts that you find in WPF, like XAML, data binding, styles etc. That means that a WPF developer gets up to speed with UWP quite fast, and vice versa. But WPF is not a UI framework that C++ developers can use, for WPF you have to develop with .

What is UWP in Visual Studio?

Develop apps that target a wide range of devices including PC, mobile, Xbox, HoloLens, IoT, and Surface Hub. Community 2022.


2 Answers

For how to print in UWP apps, you can follow the steps in Print from your app. And also refer to the Printing sample on GitHub. Following is a simple sample demonstrates how to print a rectangle on the page.

In XAML, add a print button and the rectangle to be printed.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Button HorizontalAlignment="Center" Click="PrintButtonClick">Print</Button>
    <Rectangle x:Name="RectangleToPrint"
               Grid.Row="1"
               Width="500"
               Height="500">
        <Rectangle.Fill>
            <ImageBrush ImageSource="Assets/img.jpg" />
        </Rectangle.Fill>
    </Rectangle>
</Grid>

And in code-behind, handle the print logic.

public sealed partial class MainPage : Page
{
    private PrintManager printMan;
    private PrintDocument printDoc;
    private IPrintDocumentSource printDocSource;

    public MainPage()
    {
        this.InitializeComponent();
    }

    #region Register for printing

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        // Register for PrintTaskRequested event
        printMan = PrintManager.GetForCurrentView();
        printMan.PrintTaskRequested += PrintTaskRequested;

        // Build a PrintDocument and register for callbacks
        printDoc = new PrintDocument();
        printDocSource = printDoc.DocumentSource;
        printDoc.Paginate += Paginate;
        printDoc.GetPreviewPage += GetPreviewPage;
        printDoc.AddPages += AddPages;
    }

    #endregion

    #region Showing the print dialog

    private async void PrintButtonClick(object sender, RoutedEventArgs e)
    {
        if (PrintManager.IsSupported())
        {
            try
            {
                // Show print UI
                await PrintManager.ShowPrintUIAsync();
            }
            catch
            {
                // Printing cannot proceed at this time
                ContentDialog noPrintingDialog = new ContentDialog()
                {
                    Title = "Printing error",
                    Content = "\nSorry, printing can' t proceed at this time.",
                    PrimaryButtonText = "OK"
                };
                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"
            };
            await noPrintingDialog.ShowAsync();
        }
    }

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

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

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

    #endregion

    #region Print preview

    private void Paginate(object sender, PaginateEventArgs e)
    {
        // As I only want to print one Rectangle, so I set the count to 1
        printDoc.SetPreviewPageCount(1, PreviewPageCountType.Final);
    }

    private void GetPreviewPage(object sender, GetPreviewPageEventArgs e)
    {
        // Provide a UIElement as the print preview.
        printDoc.SetPreviewPage(e.PageNumber, this.RectangleToPrint);
    }

    #endregion

    #region Add pages to send to the printer

    private void AddPages(object sender, AddPagesEventArgs e)
    {
        printDoc.AddPage(this.RectangleToPrint);

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

    #endregion

    #region Print task completed

    private async void PrintTaskCompleted(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"
                };
                await noPrintingDialog.ShowAsync();
            });
        }
    }

    #endregion
}
like image 57
Jay Zuo Avatar answered Sep 22 '22 06:09

Jay Zuo


I've been struggling with this also. I've gone over and over the SDK example. This solution may be helpful to you. If there is some way that you can put what you want to print into a RichTextBox, you can build the paragraphs for it programmatically. And replace the RichTextBox in the SDK example with a blank StackPanel that you have laid out the grid requirements on, and it will solve your issue. Mine wasn't exactly the same issue, because I have done it with Creating an even 2 columned grocery list. The trick was to use a fixed width font, CourierNew, in my example.

In your page that calls the print libraries, you need to have this in the XAML

<Canvas x:Name="PrintCanvas" Opacity="0"/>

In the page that is substituting for PageToPrint, you can build this stuff right in the constructor. I pass a Collection into the instantiation of the page, and then calculate the layout right in the PageToPrint substitute, like this,,,

   private void MakeThePrintOut()
    {


        RichTextBlock gutOne = initBlock();
        PopulateBlock(gutOne);
        ContentStack.Children.Add(gutOne);


    }
    private RichTextBlock initBlock()
    {

        RichTextBlock gutInitBlock = new RichTextBlock();
        gutInitBlock.Foreground = new SolidColorBrush(Windows.UI.Colors.Black);
        gutInitBlock.FontSize = 18;
        gutInitBlock.OverflowContentTarget = FirstLinkedContainer;
        gutInitBlock.FontFamily = new FontFamily("Courier New");
        gutInitBlock.VerticalAlignment = VerticalAlignment.Top;
        gutInitBlock.HorizontalAlignment = HorizontalAlignment.Left;
        return gutInitBlock;

    }
    private void PopulateBlock( RichTextBlock Blocker)
    {


        bool firstItem = true;
        int firstLength = 0;
        Paragraph paraItem = null;
        Run itemRun = null;

        string CurrentIsle = "None";

        foreach( Grocery j in Grocs)
        {
            if (j.Isle != CurrentIsle)
            {
                if ((CurrentIsle != "None") && (!firstItem))
                {
                    paraItem.Inlines.Add(itemRun);
                    Blocker.Blocks.Add(paraItem);

                }
                CurrentIsle = j.Isle;
                firstItem = true;
                Paragraph paraIsle = new Paragraph();
                Run paraRan = new Run();
                paraRan.Text = "     " + j.Isle;
                paraIsle.Inlines.Add(paraRan);
                Blocker.Blocks.Add(paraIsle);


            }
           if (firstItem)
            {
                paraItem = new Paragraph();
                itemRun = new Run();
                itemRun.Text = "        [] " + j.Item;
                firstLength = j.Item.Length;
                firstItem = false;
            } else
            {
                firstItem = true;
                string s = new string(' ', 30 - firstLength);
                itemRun.Text += s + "[] " +  j.Item;
                paraItem.Inlines.Add(itemRun);
                Blocker.Blocks.Add(paraItem);

            }





            }
        if (!firstItem)
        {
            paraItem.Inlines.Add(itemRun);
            Blocker.Blocks.Add(paraItem);
        }
    }

It's not exactly what you are looking for, but I know how hard it is to find something that makes sense to answer the printing question. If you want to see the complete example it's on my GitHub.com/Gibbloggen GutenbergOne project was my prototyping that I developed this stuff. And I also have imported into my main project EssentialGrocer, this too is open source in the same location. That, just tonight, includes printing of the shopping list.

Hope some of this helps, I've really struggled with this one also.

like image 44
John Leone Avatar answered Sep 22 '22 06:09

John Leone