Share via


앱에서 인쇄하기

이 항목은 Universal Windows 앱에서 인쇄하는 방법을 설명합니다.

고급 기능은 인쇄 미리 보기 UI를 사용자 지정하기를 참조하세요.

중요 API

 이 항목에 있는 대부분의 예는 GitHub의 UWP(Universal Windows Platform) 앱 샘플 리포지토리의 일부인 UWP(Universal Windows Platform) 인쇄 샘플을 기반으로 합니다.

인쇄 등록하기

앱에 인쇄를 추가하는 첫 번째 단계는 인쇄 계약을 등록하는 것입니다. 사용자가 인쇄할 수 있도록 모든 화면에 대해 앱이 이 작업을 수행해야 합니다. 사용자에게 표시되는 화면만 인쇄용으로 등록할 수 있습니다. 앱의 한 화면이 인쇄에 등록되어 있는 경우, 종료 시 인쇄 등록을 취소해야 합니다. 다른 화면으로 바뀐 경우, 다음 화면이 열리면 새로운 인쇄 계약을 등록해야 합니다.

 앱에서 하나 이상의 페이지 인쇄를 지원해야 하는 경우, 이 인쇄 코드를 공통 도우미 클래스에 넣고 앱 페이지에서 이를 재사용할 수 있습니다. 이 작업을 수행하는 방법에 대한 예시는 UWP 인쇄 샘플PrintHelper 클래스를 참조하세요.

먼저 PrintManagerPrintDocument를 선언합니다. PrintManager 형식은 다른 Windows 인쇄 기능을 지원하는 형식과 함께 Windows.Graphics.Printing 네임스페이스에 있습니다. PrintDocument 형식은 인쇄하려는 XAML 콘텐츠 준비를 지원하는 다른 형식과 함께 Windows.UI.Xaml.Printing 네임스페이스에 있습니다. 인쇄 코드를 더 쉽게 작성하기 위해 페이지에 다음의 using 또는 Imports 문을 추가할 수 있습니다.

using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

PrintDocument 클래스는 앱과 PrintManager 간의 상호 작용의 대부분을 처리하는 데 사용되지만 자체적으로 여러 콜백을 노출합니다. 등록하는 동안 PrintManagerPrintDocument 인스턴스를 만들고 인쇄 이벤트에 대한 처리기를 등록합니다.

UWP 인쇄 샘플에서, 등록은 RegisterForPrinting 메서드에 의해 수행됩니다.

public virtual void RegisterForPrinting()
{
   printDocument = new PrintDocument();
   printDocumentSource = printDocument.DocumentSource;
   printDocument.Paginate += CreatePrintPreviewPages;
   printDocument.GetPreviewPage += GetPrintPreviewPage;
   printDocument.AddPages += AddPrintPages;

   PrintManager printMan = PrintManager.GetForCurrentView();
   printMan.PrintTaskRequested += PrintTaskRequested;
}

사용자가 인쇄를 지원하는 페이지로 이동하면 OnNavigatedTo 메서드 내에서 등록이 시작됩니다.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
   // Initialize common helper class and register for printing
   printHelper = new PrintHelper(this);
   printHelper.RegisterForPrinting();

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

   // Tell the user how to print
   MainPage.Current.NotifyUser("Print contract registered with customization, use the Print button to print.", NotifyType.StatusMessage);
}

샘플에서 이벤트 처리기는 UnregisterForPrinting 메서드에서 등록 취소됩니다.

public virtual void UnregisterForPrinting()
{
    if (printDocument == null)
    {
        return;
    }

    printDocument.Paginate -= CreatePrintPreviewPages;
    printDocument.GetPreviewPage -= GetPrintPreviewPage;
    printDocument.AddPages -= AddPrintPages;

    PrintManager printMan = PrintManager.GetForCurrentView();
    printMan.PrintTaskRequested -= PrintTaskRequested;
}

사용자가 인쇄를 지원하는 페이지를 떠나면 이벤트 처리기가 OnNavigatedFrom 메서드 내에서 등록 취소됩니다.

참고

다중 페이지 앱이 있고 인쇄 연결을 끊지 않은 경우 사용자가 페이지를 떠났다가 다시 돌아올 때 예외가 발생합니다.

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
   if (printHelper != null)
   {
         printHelper.UnregisterForPrinting();
   }
}

인쇄 버튼 만들기

인쇄 버튼을 표시할 앱의 화면에 추가합니다. 추가한 인쇄 버튼이 인쇄하려는 콘텐츠에 방해가 되지 않는지 확인합니다.

<Button x:Name="InvokePrintingButton" Content="Print" Click="OnPrintButtonClick"/>

다음으로, 앱의 코드에 클릭 이벤트를 처리하는 이벤트 처리기를 추가합니다. ShowPrintUIAsync 메서드를 사용하여 앱에서 인쇄를 시작합니다. ShowPrintUIAsync는 적절한 인쇄 창을 표시하는 비동기 메서드입니다. 인쇄를 지원하는 디바이스에서 앱이 실행되고 있음을 확인하기 위해 먼저 IsSupported 메서드를 호출하는 것이 좋습니다(그렇지 않은 경우 처리함). 다른 이유로 인해 해당 시간에 인쇄를 수행할 수 없는 경우 ShowPrintUIAsync에서 예외가 throw됩니다. 이러한 예외를 catch하고 인쇄를 계속할 수 없는 경우 사용자에게 알리는 것이 좋습니다.

이 예시에서는 버튼 클릭에 대한 이벤트 처리기에 인쇄 창이 표시됩니다. 메서드가 예외(해당 시간에 인쇄를 수행할 수 없음)를 throw하는 경우, ContentDialog 컨트롤이 사용자에게 상황을 알릴 수 있습니다.

async private void OnPrintButtonClick(object sender, RoutedEventArgs e)
{
    if (Windows.Graphics.Printing.PrintManager.IsSupported())
    {
        try
        {
            // Show print UI
            await Windows.Graphics.Printing.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();
    }
}

앱 콘텐츠 서식 지정하기

ShowPrintUIAsync가 호출되면 PrintTaskRequested 이벤트가 발생합니다. 이 단계에 표시된 PrintTaskRequested 이벤트 처리기는 PrintTaskRequest.CreatePrintTask 메서드를 호출하여 PrintTask를 만들고 인쇄 페이지의 제목과 PrintTaskSourceRequestedHandler 대리자의 이름을 전달합니다. 이 예시에서 PrintTaskSourceRequestedHandler가 인라인으로 정의된다는 점에 유의하세요. PrintTaskSourceRequestedHandler는 인쇄를 위해 서식이 지정된 콘텐츠를 제공하는데 이는 이후에 설명됩니다.

이 예시에서는 완료 처리기도 오류를 catch하도록 정의됩니다. 완료 이벤트를 처리하는 것이 좋습니다. 그러면 앱이 사용자에게 오류가 발생했는지 알리고 가능한 솔루션을 제공할 수 있기 때문입니다. 마찬가지로 앱은 완료 이벤트를 사용하여 인쇄 작업이 성공한 뒤 사용자가 수행할 후속 단계를 나타낼 수 있습니다.

protected virtual void PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e)
{
   PrintTask printTask = null;
   printTask = e.Request.CreatePrintTask("C# Printing SDK Sample", sourceRequested =>
   {
         // Print Task event handler is invoked when the print job is completed.
         printTask.Completed += async (s, args) =>
         {
            // Notify the user when the print operation fails.
            if (args.Completion == PrintTaskCompletion.Failed)
            {
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     MainPage.Current.NotifyUser("Failed to print.", NotifyType.ErrorMessage);
               });
            }
         };

         sourceRequested.SetSource(printDocumentSource);
   });
}

인쇄 작업을 만든 뒤, 인쇄 미리 보기 UI에 표시할 인쇄 페이지 컬렉션을 요청하기 위해 PrintManager페이지 매김 이벤트를 발생시킵니다. 이는 IPrintPreviewPageCollection 인터페이스의 Paginate 메서드에 해당됩니다. 등록 중에 만든 이벤트 처리기가 현재 호출됩니다.

중요

 사용자가 인쇄 설정을 변경한 경우에는 콘텐츠를 재배치할 수 있도록 페이지 매김 이벤트 처리기가 다시 호출됩니다. 최상의 사용자 환경을 위해 콘텐츠를 재배치하기 전에 설정을 체크하여 필요하지 않은 경우 페이지를 매긴 콘텐츠를 다시 초기화하지 않는 것이 좋습니다.

페이지 매김 이벤트 처리기(UWP 인쇄 샘플CreatePrintPreviewPages 메서드)에서 인쇄 미리 보기 UI에 표시하고 프린터로 보낼 페이지를 만듭니다. 인쇄하기 위해 앱의 콘텐츠를 준비하는 데 사용하는 코드는 앱 및 인쇄 콘텐츠와 관련이 있습니다. UWP 인쇄 샘플 소스 코드를 참조하여 인쇄할 콘텐츠의 서식을 지정하는 방법을 확인합니다.

protected virtual void CreatePrintPreviewPages(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
   RichTextBlockOverflow lastRTBOOnPage;

   // 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
   while (lastRTBOOnPage.HasOverflowContent && lastRTBOOnPage.Visibility == Windows.UI.Xaml.Visibility.Visible)
   {
         lastRTBOOnPage = AddOnePrintPreviewPage(lastRTBOOnPage, pageDescription);
   }

   if (PreviewPagesCreated != null)
   {
         PreviewPagesCreated.Invoke(printPreviewPages, null);
   }

   PrintDocument printDoc = (PrintDocument)sender;

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

특정 페이지가 인쇄 미리 보기 창에 표시되는 경우, PrintManagerGetPreviewPage 이벤트를 발생시킵니다. 이는 IPrintPreviewPageCollection 인터페이스의 MakePage 메서드에 해당됩니다. 등록 중에 만든 이벤트 처리기가 현재 호출됩니다.

GetPreviewPage 이벤트 처리기(UWP 인쇄 샘플GetPrintPreviewPage 메서드)에서 인쇄 문서에서 적절한 페이지를 설정합니다.

protected virtual void GetPrintPreviewPage(object sender, GetPreviewPageEventArgs e)
{
   PrintDocument printDoc = (PrintDocument)sender;
   printDoc.SetPreviewPage(e.PageNumber, printPreviewPages[e.PageNumber - 1]);
}

마지막으로 사용자가 인쇄 버튼을 클릭하면 PrintManager는 프린터로 보낼 최종 페이지 컬렉션을 요청하기 위해 IDocumentPageSource 인터페이스의 MakeDocument 메서드를 호출합니다. 이는 XAML에서 AddPages 이벤트를 발생시킵니다. 등록 중에 만든 이벤트 처리기가 현재 호출됩니다.

AddPages 이벤트 처리기(UWP 인쇄 샘플AddPrintPages 메서드)에서 페이지 컬렉션의 페이지를 프린터로 보낼 PrintDocument 개체에 추가합니다. 사용자가 인쇄할 특정 페이지 또는 페이지 범위를 지정하는 경우, 실제로 프린터로 전송되는 페이지만 추가하기 위해 여기에서 해당 정보를 사용합니다.

protected virtual void AddPrintPages(object sender, AddPagesEventArgs e)
{
   // Loop over all of the preview pages and add each one to  add each page to be printied
   for (int i = 0; i < printPreviewPages.Count; i++)
   {
         // We should have all pages ready at this point...
         printDocument.AddPage(printPreviewPages[i]);
   }

   PrintDocument printDoc = (PrintDocument)sender;

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

인쇄 옵션 준비하기

다음으로 인쇄 옵션을 준비합니다. 예를 들어 이 섹션은 특정 페이지 인쇄를 허용하도록 페이지 범위 옵션을 설정하는 방법에 대해 설명합니다. 고급 기능 옵션은 인쇄 미리 보기 UI를 사용자 지정하기를 참조하세요.

이 단계에서는 새로운 인쇄 옵션을 만들고, 옵션이 지원하는 값 목록을 정의한 다음, 인쇄 미리 보기 UI에 옵션을 추가합니다. 페이지 범위 옵션에는 다음과 같은 설정이 있습니다.

옵션 이름 작업
모두 인쇄 문서의 모든 페이지를 인쇄합니다.
인쇄 선택 사용자가 선택한 콘텐츠만 인쇄합니다.
인쇄 범위 인쇄할 페이지를 사용자가 입력할 수 있는 편집 컨트롤을 표시합니다.

먼저 PrintTaskRequested 이벤트 처리기를 수정하여 PrintTaskOptionDetails 개체를 가져오는 코드를 추가합니다.

PrintTaskOptionDetails printDetailedOptions = PrintTaskOptionDetails.GetFromPrintTaskOptions(printTask.Options);

인쇄 미리 보기 UI에 표시되는 옵션 목록을 지우고 사용자가 앱에서 인쇄하려고 하는 경우에 표시할 옵션을 추가합니다.

참고

 옵션은 인쇄 미리 보기 UI에 추가된 순서와 동일한 순서로 표시되며, 첫 번째 옵션이 창 맨 위에 표시됩니다.

IList<string> displayedOptions = printDetailedOptions.DisplayedOptions;

displayedOptions.Clear();
displayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Copies);
displayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Orientation);
displayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.ColorMode);

새로운 인쇄 옵션을 만들고 옵션 값 목록을 초기화합니다.

// Create a new list option
PrintCustomItemListOptionDetails pageFormat = printDetailedOptions.CreateItemListOption("PageRange", "Page Range");
pageFormat.AddItem("PrintAll", "Print all");
pageFormat.AddItem("PrintSelection", "Print Selection");
pageFormat.AddItem("PrintRange", "Print Range");

사용자 지정 인쇄 옵션을 추가하고 이벤트 처리기를 할당합니다. 사용자 지정 옵션은 마지막으로 추가되어 옵션 목록의 맨 아래에 표시되도록 합니다. 그러나 목록의 아무 곳에나 배치할 수 있습니다. 사용자 지정 인쇄 옵션을 마지막으로 추가할 필요는 없습니다.

// Add the custom option to the option list
displayedOptions.Add("PageRange");

// Create new edit option
PrintCustomTextOptionDetails pageRangeEdit = printDetailedOptions.CreateTextOption("PageRangeEdit", "Range");

// Register the handler for the option change event
printDetailedOptions.OptionChanged += printDetailedOptions_OptionChanged;

CreateTextOption 메서드는 범위 텍스트 상자를 만듭니다. 사용자는 인쇄 범위 옵션을 선택할 때 인쇄할 특정 페이지를 여기에 입력합니다.

인쇄 옵션 변경 처리하기

OptionChanged 이벤트 처리기는 두 가지 작업을 수행합니다. 먼저 페이지 범위의 텍스트 편집 필드를 사용자가 선택한 페이지 범위 옵션에 따라 표시하고 숨깁니다. 그다음으로 페이지 범위 텍스트 상자에 입력한 텍스트를 테스트하여 문서에 유효한 페이지 범위를 나타내는지 확인합니다.

이 예는 인쇄 옵션 변경 이벤트가 UWP 인쇄 샘플에서 어떻게 처리되는지 보여 줍니다.

async void printDetailedOptions_OptionChanged(PrintTaskOptionDetails sender, PrintTaskOptionChangedEventArgs args)
{
   if (args.OptionId == null)
   {
         return;
   }

   string optionId = args.OptionId.ToString();

   // Handle change in Page Range Option
   if (optionId == "PageRange")
   {
         IPrintOptionDetails pageRange = sender.Options[optionId];
         string pageRangeValue = pageRange.Value.ToString();

         selectionMode = false;

         switch (pageRangeValue)
         {
            case "PrintRange":
               // Add PageRangeEdit custom option to the option list
               sender.DisplayedOptions.Add("PageRangeEdit");
               pageRangeEditVisible = true;
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     ShowContent(null);
               });
               break;
            case "PrintSelection":
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     Scenario4PageRange page = (Scenario4PageRange)scenarioPage;
                     PageToPrint pageContent = (PageToPrint)page.PrintFrame.Content;
                     ShowContent(pageContent.TextContentBlock.SelectedText);
               });
               RemovePageRangeEdit(sender);
               break;
            default:
               await scenarioPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                     ShowContent(null);
               });
               RemovePageRangeEdit(sender);
               break;
         }

         Refresh();
   }
   else if (optionId == "PageRangeEdit")
   {
         IPrintOptionDetails pageRange = sender.Options[optionId];
         // Expected range format (p1,p2...)*, (p3-p9)* ...
         if (!Regex.IsMatch(pageRange.Value.ToString(), @"^\s*\d+\s*(\-\s*\d+\s*)?(\,\s*\d+\s*(\-\s*\d+\s*)?)*$"))
         {
            pageRange.ErrorText = "Invalid Page Range (eg: 1-3, 5)";
         }
         else
         {
            pageRange.ErrorText = string.Empty;
            try
            {
               GetPagesInRange(pageRange.Value.ToString());
               Refresh();
            }
            catch (InvalidPageException ipex)
            {
               pageRange.ErrorText = ipex.Message;
            }
         }
   }
}

 사용자가 범위 텍스트 상자에 입력하는 페이지 범위를 구문 분석하는 방법은 UWP 인쇄 샘플GetPagesInRange 메서드를 참조하세요.

선택한 페이지 미리 보기

인쇄를 위해 앱 콘텐츠의 형식을 지정하는 방법은 앱의 특성과 콘텐츠에 따라 달라집니다. 인쇄할 콘텐츠 형식을 지정하기 위해 UWP 인쇄 샘플에서 사용되는 인쇄 도우미 클래스입니다.

페이지의 하위 집합을 인쇄할 때 인쇄 미리 보기에 내용을 표시하는 방법에는 여러 가지가 있습니다. 인쇄 미리 보기에서 페이지 범위를 표시하도록 선택한 방법에 관계없이 인쇄된 출력에는 선택한 페이지만 포함되어야 합니다.

  • 페이지 범위가 지정되었는지 여부에 관계없이 인쇄 미리 보기의 모든 페이지를 표시하여 사용자가 실제로 인쇄할 페이지를 알 수 있도록 합니다.
  • 인쇄 미리 보기에서 사용자의 페이지 범위에서 선택한 페이지만 표시하고 사용자가 페이지 범위를 변경할 때마다 디스플레이를 업데이트합니다.
  • 인쇄 미리 보기의 모든 페이지를 표시하지만, 사용자가 선택한 페이지 범위에 없는 페이지는 회색으로 표시합니다.