次の方法で共有


アプリからの印刷

このトピックでは、ユニバーサル Windows アプリから印刷する方法について説明します。

より高度な機能については、「 印刷プレビュー UI をカスタマイズするを参照してください。

重要な API

ヒント

 このトピックの例のほとんどは、ユニバーサル Windows プラットフォーム (UWP) 印刷サンプルに基づいています。これは、GitHub のユニバーサル Windows プラットフォーム (UWP) アプリのサンプル リポジトリの一部です。

印刷登録

アプリに印刷を追加する最初の手順は、印刷コントラクトに登録することです。 アプリは、ユーザーが印刷できるようにしたいすべての画面でこれを行う必要があります。 印刷登録できるのは、ユーザーに表示される画面のみです。 アプリの 1 つの画面が印刷用に登録されている場合は、終了時に印刷の登録を解除する必要があります。 別の画面に置き換えられる場合、次の画面は、開いたときに新しい印刷コントラクトに登録する必要があります。

ヒント

 アプリで複数のページからの印刷をサポートする必要がある場合は、この印刷コードを共通のヘルパー クラスに配置し、アプリ ページで再利用することができます。 これを行う方法の例については、UWP 印刷サンプルのPrintHelper クラスを参照してください。

最初に、 PrintManagerPrintDocument を宣言します。 PrintManager 型は、他の Windows 印刷機能をサポートする型と共に、Windows.Graphics.Printing 名前空間にあります。 PrintDocument 型は、Windows.UI.Xaml.Printing 名前空間内にあり、印刷用の XAML コンテンツの準備をサポートする他の型と共に使用されます。 次の using または Imports ステートメントをページに追加することで、印刷コードを簡単に記述できます。

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

PrintDocument クラスは、アプリと PrintManager の間の相互作用の多くを処理するために使用されますが、独自のいくつかのコールバックを公開します。 登録時に、 PrintManager および PrintDocument のインスタンスを作成し 印刷イベントのハンドラーを登録します。

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 メソッド内で、イベント ハンドラーの登録が解除されます。

Note

複数ページ アプリが存在しており、印刷を切断していない場合は、ユーザーがページから離れ、その後戻ってくると、例外がスローされます。

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

印刷ボタンを作成する

表示するアプリの画面に印刷ボタンを追加します。 印刷するコンテンツに干渉しないようにしてください。

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

次に、クリック イベントを処理するイベント ハンドラーをアプリのコードに追加します。 ShowPrintUIAsync メソッドを使用して、アプリからの印刷を開始します。 ShowPrintUIAsync は、適切な印刷ウィンドウを表示する非同期メソッドです。 最初に IsSupported メソッドを呼び出して、印刷をサポートするデバイスでアプリが実行されていることを確認することをお勧めします (そうでない場合を処理します)。 その時点で他の理由で印刷を実行できない場合、 ShowPrintUIAsync は例外をスローします。 これらの例外をキャッチし、印刷を続行できないときにユーザーに知らせることをお勧めします。

この例では、ボタン クリックのイベント ハンドラーに印刷ウィンドウが表示されます。 メソッドが例外をスローした場合 (その時点で印刷を実行できないため)、 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 は印刷用に書式設定されたコンテンツを提供し、後で説明します。

この例では、エラーをキャッチするために完了ハンドラーも定義されています。 完了イベントを処理することをお勧めします。エラーが発生したかどうかをアプリがユーザーに知らせ、考えられる解決策を提供できるためです。 同様に、アプリは完了イベントを使用して、印刷ジョブが成功した後にユーザーが実行する後続の手順を示します。

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);
   });
}

印刷タスクが作成されると、 PrintManager は、 Paginate イベントを発生させることで、印刷プレビュー UI に表示する印刷ページのコレクションを要求します。 これは、IPrintPreviewPageCollection インターフェイスの Paginate メソッドに対応します。 登録中に作成したイベント ハンドラーは、現時点で呼び出されます。

重要

 ユーザーが印刷設定を変更すると、改ページ位置イベント ハンドラーが再度呼び出され、コンテンツのリフローが可能になります。 ユーザー エクスペリエンスを最大限に高めるには、コンテンツをリフローする前に設定を確認し、ページ分割されたコンテンツが不要な場合は再初期化しないようにすることをお勧めします。

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 に表示されているオプションの一覧をクリアし、ユーザーがアプリから印刷するときに表示するオプションを追加します。

Note

 オプションは、追加されるのと同じ順序で印刷プレビュー 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 メソッドは、Range テキスト ボックスを作成します。 [ 印刷範囲 オプションを選択したときに、印刷する特定のページを入力します。

印刷オプションの変更を処理する

OptionChanged イベント ハンドラーは 2 つの処理を行います。 まず、ユーザーが選択したページ範囲オプションに応じて、ページ範囲のテキスト編集フィールドを表示および非表示にします。 次に、ページ範囲テキスト ボックスに入力されたテキストをテストして、ドキュメントの有効なページ範囲を表していることを確認します。

この例は、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 印刷サンプルで使用されます。

ページのサブセットを印刷する際、印刷プレビューでコンテンツを表示する方法はいくつかあります。 印刷プレビューでページ範囲を表示するように選択した方法に関係なく、印刷出力には選択したページのみが含まれている必要があります。

  • ページ範囲が指定されているかどうかに関係なく、印刷プレビューのすべてのページを表示します。ユーザーは、実際に印刷されるページを把握したままにします。
  • 印刷プレビューでユーザーのページ範囲によって選択されたページのみを表示し、ユーザーがページ範囲を変更するたびに表示を更新します。
  • 印刷プレビューのすべてのページを表示しますが、ユーザーが選択したページ範囲にないページは灰色で表示されます。