Imports Windows.Graphics.Printing.OptionDetails
Imports Windows.UI.Xaml.Printing
Imports Windows.UI.Xaml.Navigation
Imports Windows.UI.Xaml.Data
Imports Windows.UI.Xaml.Controls
Imports Windows.UI.Xaml
Imports Windows.UI.ViewManagement
Imports Windows.UI.Popups
Imports Windows.UI.Core
Imports Windows.Graphics.Printing
Imports Windows.Foundation
Imports System.Collections.Generic
Imports System.Linq
Imports System
Imports C1.Xaml.FlexGrid

''' <summary>
''' An empty page that can be used on its own or navigated to within a Frame.
''' </summary>
Partial Public NotInheritable Class Printing
    Inherits Page
    Private _data As ICollectionView = Product.GetProducts(100)
    Private _pages As List(Of FrameworkElement)
    Private _margin As Double
    Private _scaleMode As ScaleMode

    ''' <summary>
    ''' PrintDocument is used to prepare the pages for printing. 
    ''' Prepare the pages to print in the handlers for the Paginate, GetPreviewPage, and AddPages events.
    ''' </summary>
    Private printDocument As PrintDocument = Nothing

    ''' <summary>
    ''' Marker interface for document source
    ''' </summary>
    Private printDocumentSource As IPrintDocumentSource = Nothing

    Public Sub New()
        Me.InitializeComponent()

        ' populate grid
        _flex.ItemsSource = _data
        _flex.Columns("Line").AllowMerging = True
        _flex.Columns("Color").AllowMerging = True

        ' for testing
        _flex.AllowResizing = AllowResizing.Both

        AddHandler Loaded, AddressOf RegisterForPrinting
        AddHandler Unloaded, AddressOf UnregisterForPrinting
    End Sub

    ''' <summary>
    ''' Invoked when this page is about to be displayed in a Frame.
    ''' </summary>
    ''' <param name="e">Event data that describes how this page was reached.  The Parameter
    ''' property is typically used to configure the page.</param>
    Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
    End Sub

#Region "** printing"

    ''' <summary>
    ''' This method registers the app for printing with Windows and sets up the necessary event handlers for the print process.
    ''' </summary>
    Private Sub RegisterForPrinting(sender As Object, e As RoutedEventArgs)
        ' Create the PrintDocument.
        printDocument = New PrintDocument()

        ' Save the DocumentSource.
        printDocumentSource = printDocument.DocumentSource

        ' Add an event handler which sets up print preview.
        AddHandler printDocument.Paginate, AddressOf Paginate

        ' Add an event handler which provides a specified preview page.
        AddHandler printDocument.GetPreviewPage, AddressOf GetPrintPreviewPage

        ' Add an event handler which provides all final print pages.
        AddHandler printDocument.AddPages, AddressOf AddPrintPages

        ' Create a PrintManager and add a handler for printing initialization.
        Dim printMan As PrintManager = PrintManager.GetForCurrentView()
        AddHandler printMan.PrintTaskRequested, AddressOf PrintTaskRequested
    End Sub

    ''' <summary>
    ''' This method unregisters the app for printing with Windows.
    ''' </summary>
    Private Sub UnregisterForPrinting(sender As Object, e As RoutedEventArgs)
        If printDocument Is Nothing Then
            Return
        End If

        RemoveHandler printDocument.Paginate, AddressOf Paginate
        RemoveHandler printDocument.GetPreviewPage, AddressOf GetPrintPreviewPage
        RemoveHandler printDocument.AddPages, AddressOf AddPrintPages

        ' Remove the handler for printing initialization.
        Dim printMan As PrintManager = PrintManager.GetForCurrentView()
        RemoveHandler printMan.PrintTaskRequested, AddressOf PrintTaskRequested

    End Sub

    ''' <summary>
    ''' This is the event handler for PrintManager.PrintTaskRequested.
    ''' </summary>
    ''' <param name="sender">PrintManager</param>
    ''' <param name="e">PrintTaskRequestedEventArgs </param>
    Private Sub PrintTaskRequested(sender As PrintManager, e As PrintTaskRequestedEventArgs)
        Dim printTask As PrintTask = Nothing
        printTask = e.Request.CreatePrintTask(Strings.SamplePDF, Function(sourceRequested As PrintTaskSourceRequestedArgs)
                                                                     Dim printDetailedOptions As PrintTaskOptionDetails = PrintTaskOptionDetails.GetFromPrintTaskOptions(printTask.Options)

                                                                     Dim displayedOptions As IList(Of String) = printTask.Options.DisplayedOptions

                                                                     Dim zoomItem As PrintCustomItemListOptionDetails = printDetailedOptions.CreateItemListOption("Zoom", Strings.Zoom)
                                                                     zoomItem.AddItem("ActualSize", Strings.ActualSize)
                                                                     zoomItem.AddItem("PageWidth", Strings.PageWidth)
                                                                     zoomItem.AddItem("SinglePage", Strings.SinglePage)
                                                                     zoomItem.TrySetValue("PageWidth")

                                                                     Dim marginItem As PrintCustomItemListOptionDetails = printDetailedOptions.CreateItemListOption("Margin", Strings.Margin)
                                                                     marginItem.AddItem("None", Strings.None)
                                                                     marginItem.AddItem("HalfInch", Strings.HalfInch)
                                                                     marginItem.AddItem("OneInch", Strings.OneInch)
                                                                     marginItem.TrySetValue("OneInch")

                                                                     AddHandler printDetailedOptions.OptionChanged, AddressOf OnPrintOptionsChanged

                                                                     ' 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
                                                                     displayedOptions.Clear()
                                                                     displayedOptions.Add(StandardPrintTaskOptions.Copies)
                                                                     displayedOptions.Add(StandardPrintTaskOptions.Orientation)
                                                                     displayedOptions.Add(StandardPrintTaskOptions.MediaSize)
                                                                     displayedOptions.Add(StandardPrintTaskOptions.Collation)
                                                                     displayedOptions.Add(StandardPrintTaskOptions.Duplex)
                                                                     ' Add the custom option to the option list
                                                                     displayedOptions.Add("Zoom")
                                                                     displayedOptions.Add("Margin")

                                                                     ' Preset the default value of the printer option
                                                                     printTask.Options.MediaSize = PrintMediaSize.IsoA4

                                                                     ' Print Task event handler is invoked when the print job is completed.
                                                                     AddHandler printTask.Completed, AddressOf OnCompleted
                                                                     sourceRequested.SetSource(printDocumentSource)

                                                                 End Function)

    End Sub

    Private Async Sub OnCompleted(sender As Object, args As PrintTaskCompletedEventArgs)
        If args.Completion = PrintTaskCompletion.Failed Then
            Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, Sub()
                                                                                         Dim dialog As New MessageDialog(Strings.PrintException)
                                                                                         dialog.ShowAsync()

                                                                                     End Sub)
        End If
    End Sub

    Async Sub OnPrintOptionsChanged(sender As PrintTaskOptionDetails, args As PrintTaskOptionChangedEventArgs)
        ' Listen for PageContent changes
        Dim optionId As String = TryCast(args.OptionId, String)
        If String.IsNullOrEmpty(optionId) Then
            Return
        End If

        If optionId = "Zoom" OrElse optionId = "Margin" Then
            Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, Function()
                                                                                         printDocument.InvalidatePreview()
                                                                                     End Function)
        End If
    End Sub

    ''' <summary>
    ''' This is the event handler for PrintDocument.Paginate. 
    ''' It fires when the PrintManager requests print preview
    ''' </summary>
    ''' <param name="sender">PrintDocument</param>
    ''' <param name="e">Paginate Event Arguments</param>
    Private Sub Paginate(sender As Object, e As PaginateEventArgs)
        Dim printDoc As PrintDocument = CType(sender, PrintDocument)

        ' Get PageContent property
        Dim printDetailedOptions As Object = PrintTaskOptionDetails.GetFromPrintTaskOptions(e.PrintTaskOptions)
        Dim zoom As String = TryCast(printDetailedOptions.Options("Zoom").Value, String)
        Dim margin As String = TryCast(printDetailedOptions.Options("Margin").Value, String)
        ' get scale mode and margin
        _scaleMode = If(zoom = "ActualSize", ScaleMode.ActualSize, If(zoom = "PageWidth", ScaleMode.PageWidth, ScaleMode.SinglePage))
        _margin = If(margin = "None", 0, If(margin = "HalfInch", 96.0 / 2, 96.0))

        ' calculate page size, discounting margins
        Dim pageDescription As PrintPageDescription = e.PrintTaskOptions.GetPageDescription(0)
        Dim pagesize As Size = pageDescription.PageSize
        pagesize.Width -= 2 * _margin
        pagesize.Height -= 2 * _margin
        _pages = _flex.GetPageImages(_scaleMode, pagesize, 100).[Select](Function(page) CType(New ContentControl() With {
            .Content = page,
            .Padding = New Thickness(_margin)
        }, FrameworkElement)).ToList()

        ' Report the number of preview pages
        printDoc.SetPreviewPageCount(_pages.Count, PreviewPageCountType.Final)
    End Sub

    ''' <summary>
    ''' This is the event handler for PrintDocument.GetPrintPreviewPage. It provides a specific print preview page,
    ''' in the form of an UIElement, to an instance of PrintDocument. PrintDocument subsequently converts the UIElement
    ''' into a page that the Windows print system can deal with.
    ''' </summary>
    ''' <param name="sender">PrintDocument</param>
    ''' <param name="e">Arguments containing the preview requested page</param>
    Private Sub GetPrintPreviewPage(sender As Object, e As GetPreviewPageEventArgs)
        Dim printDoc As PrintDocument = CType(sender, PrintDocument)

        If _pages IsNot Nothing AndAlso e.PageNumber > 0 AndAlso e.PageNumber - 1 < _pages.Count Then
            printDoc.SetPreviewPage(e.PageNumber, _pages(e.PageNumber - 1))
        End If
    End Sub

    ''' <summary>
    ''' This is the event handler for PrintDocument.AddPages. It provides all pages to be printed, in the form of
    ''' UIElements, to an instance of PrintDocument. PrintDocument subsequently converts the UIElements
    ''' into a pages that the Windows print system can deal with.
    ''' </summary>
    ''' <param name="sender">PrintDocument</param>
    ''' <param name="e">Add page event arguments containing a print task options reference</param>
    Private Sub AddPrintPages(sender As Object, e As AddPagesEventArgs)
        ' Loop over all of the pages and add each one to be printed
        For Each page As FrameworkElement In _pages
            printDocument.AddPage(page)
        Next

        Dim printDoc As PrintDocument = CType(sender, PrintDocument)

        ' Indicate that all of the print pages have been provided
        printDoc.AddPagesComplete()
    End Sub

    Sub _btnPrint_Click(sender As Object, e As RoutedEventArgs)
        PrintManager.ShowPrintUIAsync()
    End Sub

#End Region
End Class