/// <summary>
        /// This is the event handler for PrintManager.PrintTaskRequested.
        /// In order to ensure a good user experience, the system requires that the app handle the PrintTaskRequested event within the time specified
        /// by PrintTaskRequestedEventArgs->Request->Deadline.
        /// Therefore, we use this handler to only create the print task.
        /// The print settings customization can be done when the print document source is requested.
        /// </summary>
        /// <param name="sender">The print manager for which a print task request was made.</param>
        /// <param name="e">The print taks request associated arguments.</param>
        protected override void PrintTaskRequested(Windows.Graphics.Printing.PrintManager sender, Windows.Graphics.Printing.PrintTaskRequestedEventArgs e)
        {
            PrintTask printTask = null;

            printTask = e.Request.CreatePrintTask("Printing Coloring Page", sourceRequestedArgs =>
            {
                PrintTaskOptionDetails printDetailedOptions = PrintTaskOptionDetails.GetFromPrintTaskOptions(printTask.Options);

                // Choose the printer options to be shown.
                // The order in which the options are appended determines the order in which they appear in the UI
                printDetailedOptions.DisplayedOptions.Clear();
                printDetailedOptions.DisplayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.MediaSize);
                printDetailedOptions.DisplayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Copies);

                // Create a new list option.
                PrintCustomItemListOptionDetails photoSize = printDetailedOptions.CreateItemListOption("photoSize", "Photo Size");
                photoSize.AddItem("SizeFullPage", "Full Page");
                photoSize.AddItem("Size4x6", "4 x 6 in");
                photoSize.AddItem("Size5x7", "5 x 7 in");
                photoSize.AddItem("Size8x10", "8 x 10 in");

                // Add the custom option to the option list.
                printDetailedOptions.DisplayedOptions.Add("photoSize");

                PrintCustomItemListOptionDetails scaling = printDetailedOptions.CreateItemListOption("scaling", "Scaling");
                scaling.AddItem("ShrinkToFit", "Shrink To Fit");
                scaling.AddItem("Crop", "Crop");

                // Add the custom option to the option list.
                printDetailedOptions.DisplayedOptions.Add("scaling");

                // Set default orientation to landscape.
                printTask.Options.Orientation = PrintOrientation.Landscape;

                // Register for print task option changed notifications.
                printDetailedOptions.OptionChanged += PrintDetailedOptionsOptionChanged;

                // Register for print task Completed notification.
                // Print Task event handler is invoked when the print job is completed.
                printTask.Completed += async(s, args) =>
                {
                    await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        ClearPageCollection();

                        // Reset image options to default values.
                        this.photoScale = Scaling.ShrinkToFit;
                        this.photoSize  = PhotoSize.SizeFullPage;

                        // Reset the current page description
                        currentPageDescription = null;
                    });
                };

                // Set the document source.
                sourceRequestedArgs.SetSource(printDocumentSource);
            });
        }
        /// <summary>
        /// Generates a page containing a photo.
        /// The image will be rotated if detected that there is a gain from that regarding size (try to maximize photo size).
        /// </summary>
        /// <param name="photoNumber">The photo number.</param>
        /// <param name="pageDescription">The description of the printer page.</param>
        /// <returns>A task that will return the page.</returns>
        private async Task <UIElement> GeneratePageAsync(int photoNumber, PageDescription pageDescription)
        {
            Canvas page = new Canvas
            {
                Width  = pageDescription.PageSize.Width,
                Height = pageDescription.PageSize.Height
            };

            Canvas viewablePage = new Canvas()
            {
                Width  = pageDescription.ViewablePageSize.Width,
                Height = pageDescription.ViewablePageSize.Height
            };

            viewablePage.SetValue(Canvas.LeftProperty, pageDescription.Margin.Width);
            viewablePage.SetValue(Canvas.TopProperty, pageDescription.Margin.Height);

            // The image "frame" which also acts as a viewport
            Grid photoView = new Grid
            {
                Width  = pageDescription.PictureViewSize.Width,
                Height = pageDescription.PictureViewSize.Height
            };

            // Center the frame.
            photoView.SetValue(Canvas.LeftProperty, (viewablePage.Width - photoView.Width) / 2);
            photoView.SetValue(Canvas.TopProperty, (viewablePage.Height - photoView.Height) / 2);

            // Return an async task that will complete when the image is fully loaded.
            WriteableBitmap bitmap = await LoadBitmapAsync(
                new Uri(string.Format("ms-appx:///Assets/photo{0}.jpg", photoNumber)),
                pageDescription.PageSize.Width > pageDescription.PageSize.Height);

            if (bitmap != null)
            {
                Image image = new Image
                {
                    Source = bitmap,
                    HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
                    VerticalAlignment   = Windows.UI.Xaml.VerticalAlignment.Center
                };

                // Use the real image size when croping or if the image is smaller then the target area (prevent a scale-up).
                if (photoScale == Scaling.Crop ||
                    (bitmap.PixelWidth <= pageDescription.PictureViewSize.Width &&
                     bitmap.PixelHeight <= pageDescription.PictureViewSize.Height))
                {
                    image.Stretch = Stretch.None;
                    image.Width   = bitmap.PixelWidth;
                    image.Height  = bitmap.PixelHeight;
                }

                // Add the newly created image to the visual root.
                photoView.Children.Add(image);
                viewablePage.Children.Add(photoView);
                page.Children.Add(viewablePage);
            }

            // Return the page with the image centered.
            return(page);
        }
        /// <summary>
        /// This is the event handler for Pagination.
        /// </summary>
        /// <param name="sender">The document for which pagination occurs.</param>
        /// <param name="e">The pagination event arguments containing the print options.</param>
        protected override void CreatePrintPreviewPages(object sender, Windows.UI.Xaml.Printing.PaginateEventArgs e)
        {
            PrintDocument printDoc = (PrintDocument)sender;

            // A new "session" starts with each paginate event.
            Interlocked.Increment(ref requestCount);

            PageDescription pageDescription = new PageDescription();

            // Get printer's page description.
            PrintTaskOptionDetails printDetailedOptions = PrintTaskOptionDetails.GetFromPrintTaskOptions(e.PrintTaskOptions);
            PrintPageDescription   printPageDescription = e.PrintTaskOptions.GetPageDescription(0);

            // Reset the error state
            printDetailedOptions.Options["photoSize"].ErrorText = string.Empty;

            // Compute the printing page description (page size & center printable area)
            pageDescription.PageSize = printPageDescription.PageSize;

            pageDescription.Margin.Width = Math.Max(
                printPageDescription.ImageableRect.Left,
                printPageDescription.ImageableRect.Right - printPageDescription.PageSize.Width);

            pageDescription.Margin.Height = Math.Max(
                printPageDescription.ImageableRect.Top,
                printPageDescription.ImageableRect.Bottom - printPageDescription.PageSize.Height);

            pageDescription.ViewablePageSize.Width  = printPageDescription.PageSize.Width - pageDescription.Margin.Width * 2;
            pageDescription.ViewablePageSize.Height = printPageDescription.PageSize.Height - pageDescription.Margin.Height * 2;

            // Compute print photo area.
            switch (photoSize)
            {
            case PhotoSize.Size4x6:
                pageDescription.PictureViewSize.Width  = 4 * DPI96;
                pageDescription.PictureViewSize.Height = 6 * DPI96;
                break;

            case PhotoSize.Size5x7:
                pageDescription.PictureViewSize.Width  = 5 * DPI96;
                pageDescription.PictureViewSize.Height = 7 * DPI96;
                break;

            case PhotoSize.Size8x10:
                pageDescription.PictureViewSize.Width  = 8 * DPI96;
                pageDescription.PictureViewSize.Height = 10 * DPI96;
                break;

            case PhotoSize.SizeFullPage:
                pageDescription.PictureViewSize.Width  = pageDescription.ViewablePageSize.Width;
                pageDescription.PictureViewSize.Height = pageDescription.ViewablePageSize.Height;
                break;
            }

            // Try to maximize photo-size based on it's aspect-ratio
            if ((pageDescription.ViewablePageSize.Width > pageDescription.ViewablePageSize.Height) && (photoSize != PhotoSize.SizeFullPage))
            {
                var swap = pageDescription.PictureViewSize.Width;
                pageDescription.PictureViewSize.Width  = pageDescription.PictureViewSize.Height;
                pageDescription.PictureViewSize.Height = swap;
            }

            pageDescription.IsContentCropped = photoScale == Scaling.Crop;

            // Recreate content only when :
            // - there is no current page description
            // - the current page description doesn't match the new one
            if (currentPageDescription == null || !currentPageDescription.Equals(pageDescription))
            {
                ClearPageCollection();

                if (pageDescription.PictureViewSize.Width > pageDescription.ViewablePageSize.Width ||
                    pageDescription.PictureViewSize.Height > pageDescription.ViewablePageSize.Height)
                {
                    printDetailedOptions.Options["photoSize"].ErrorText = "Photo doesn’t fit on the selected paper";

                    // Inform preview that it has only 1 page to show.
                    printDoc.SetPreviewPageCount(1, PreviewPageCountType.Intermediate);

                    // Add a custom "preview" unavailable page
                    lock (printSync)
                    {
                        pageCollection[0] = new PreviewUnavailable(pageDescription.PageSize, pageDescription.ViewablePageSize);
                    }
                }
                else
                {
                    // Inform preview that is has #NumberOfPhotos pages to show.
                    printDoc.SetPreviewPageCount(NumberOfPhotos, PreviewPageCountType.Intermediate);
                }

                currentPageDescription = pageDescription;
            }
        }