Windows ストア アプリでは、アプリケーションからプリンターに対して印刷する機能が提供されています。プリントアウトできるのは画像(Bitmap)ではなく、UIElementになります(プログラム的なお話は後述します)。
ここでは、ブランクなPageの上に、テスト用に3枚のエレメントを用意してみました。背景は単純な赤一色のGrid、ねこの顔と体はImageです。僕の落書きですが下図のようにコントロールを重ねています。
Windows ストア アプリにて印刷をおこなう手順について説明します。印刷をおこなうには、まずチャームからプリンターを選択して、印刷物のプレビューを表示し、そこから実際の印刷開始の要求をおこないます。スクリーンショットを交えながら手順を紹介します。
チャームの[デバイス]を選択します。印刷に対応したアプリケーションの場合、印刷可能なプリンターの一覧が並びます。
印刷物を出したいプリンターを選択します。ここでは、プリンターを接続していなくても出力の確認をしやすい[Microsoft XPS Decument Writer]を選択します。(1)
プレビューの確認ができました。複数ページの印刷の場合は2ページ目3ページ目のプレビューを表示することが可能です。(2)
プレビューに表示される内容で問題なければ、印刷ボタンをクリックします。(3)
問題が発生しなければ、印刷処理は完了です。XPSを選択した場合は、ドキュメントフォルダーに成果物が生成されます。XPS リーダー等を使用して印刷物の確認をしてください。
以上が、Windows ストア アプリにて印刷をおこなう際の手順となります。
手順に(1)から(3)までの数字を入れています。印刷処理はメソッドを1つ実行したらプリンターから紙が出てくるわけではなく、ユーザーの操作に応じてイベントが発生し、それらのイベントにて適切な処理をおこなう必要があります。
後述するプログラム側の説明で、「(1)の動作で○○○イベントが発生します」と説明しますので、どの手順かわからなくなった場合は、前に戻って頂ければと思います。
印刷をおこなうプログラム
印刷される対象はUIElementになります。
画面には表示されていないプログラム的に生成したUIElementを印刷させることも可能ですが、ここではあらかじめ画面上に表示されている「猫の画像」を印刷したいと思います。
さきほど印刷の手順にて、説明に使用した赤背景の上に猫が立っているXMLは、以下の通りです。
<Page x:Class="PrinterSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:PrinterSample" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="280*"/> <RowDefinition Height="50*"/> </Grid.RowDefinitions> <!-- 印刷するボタン --> <Button x:Name="btnPrint" Content="印刷する" Grid.Row="1" Click="btnPrint_Click"/> <!-- 猫がいる背景 --> <Grid x:Name="printGrid" Background="Red"> <!-- 猫の体 --> <Image Source="Assets/neko.png" HorizontalAlignment="Center" VerticalAlignment="Top" Stretch="None" /> <!-- 猫の顔 --> <Image Source="Assets/face.png" HorizontalAlignment="Center" VerticalAlignment="Top" Stretch="None" Margin="0,40,0,0" /> </Grid> </Grid> </Page>
printGridと名前を付けたGridの上に、ネコの体と顔のImageコントロールを配置しています。この猫を表示しているprintGridを印刷してみましょう。
チャームの「デバイス」に印刷先のプリンターの一覧を表示させる
Windows ストア アプリにて印刷をおこなうには、印刷物があることを通知する必要があります。
画面の表示時OnNavigateToメソッドの中で、チャームの[デバイス]を選択し、印刷先を表示させるにはPrintManager.GetForCurrentView()メソッドで取得したPrintManagerオブジェクトのPrintTaskRequestedイベントのハンドラを設定します。
PrintTaskRequestedイベントは、(1)のチャームの[デバイス]を選択した瞬間に発生するイベントです。
protected override void OnNavigatedTo(NavigationEventArgs e) { var manager = PrintManager.GetForCurrentView(); manager.PrintTaskRequested += manager_PrintTaskRequested; } // チャームの「デバイス」を選択した場合、または // PrintManager.ShowPrintUIAsync()メソッドを実行した時に実行される private void manager_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e) { e.Request.CreatePrintTask("印刷物のタイトル", req => { }); }
これで印刷するプリンターを選択できるところまで実装できました。しかし、肝心の「何」を印刷するのかについては未設定です。
システム側では何を印刷して良いのか分からない状態ですので、もしプリンターを選択しても「印刷するコンテンツがアプリにはありませんでした。」と警告が表示されてしまいます。
印刷物のプレビューを表示する
PrintDocumentクラスのオブジェクトを生成して、印刷の開始時、プレビュー表示時、印刷時に発生するイベントのハンドラを設定します。
printDocumentから取り出したドキュメントのソースをインスタンス変数に保存しておき、チャームの「デバイス」を選択した時(もしくは、PrintManager.ShowPrintUIAsync()メソッドを実行した時)に実行されるPrintTaskRequestedイベントハンドラで印刷物のタイトルとドキュメントソースを設定します。
// 印刷ドキュメントオブジェクト PrintDocument printDocument = null; // 印刷するドキュメントのソース IPrintDocumentSource printDocumentSource = null; protected override void OnNavigatedTo(NavigationEventArgs e) { // 印刷ドキュメントオブジェクトを生成する printDocument = new PrintDocument(); // ドキュメントのソースを保存します printDocumentSource = printDocument.DocumentSource; // 印刷が要求させると発生するイベントにハンドラを設定する printDocument.Paginate += printDocument_Paginate; // 印刷プレビューで表示されると表示するイベントにハンドラを設定する printDocument.GetPreviewPage += printDocument_GetPreviewPage; // 印刷を要求するイベントにハンドラを設定する printDocument.AddPages += printDocument_AddPages; var manager = PrintManager.GetForCurrentView(); manager.PrintTaskRequested += manager_PrintTaskRequested; } // チャームの「デバイス」を選択した場合、 // またはPrintManager.ShowPrintUIAsync()メソッドを実行した時に実行される private void manager_PrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs e) { e.Request.CreatePrintTask("印刷物のタイトル", req => { req.SetSource(printDocumentSource); }); }
手順の(2)にてプリンターを選択すると、PaginateイベントのハンドラprintDocument_Paginateメソッドが実行されます。このイベントハンドラでは、印刷物の内容を作るいわば印刷の準備をおこないます。
どんな実装方法でも構いませんが、ここではページ別に印刷するUIElementのリストを作り、そのリストにprintGridを追加しました。
// 印刷したいUIElementをページ別にリスト List<UIElement> printPages = new List<UIElement>(); private void printDocument_Paginate(object sender, PaginateEventArgs e) { // UIElement(猫が表示されているGrid)を追加します printPages.Clear(); printPages.Add(printGrid); }
さて、印刷物の準備が完了したので、印刷物のプレビューがおこなわれます。
プレビューを表示する直前にGetPreviewPageイベントのハンドラprintDocument_GetPreviewPageメソッドが実行されます。PrintDocument型のsenderに対して、プレビューさせるUIElementを渡します。。
private void printDocument_GetPreviewPage(object sender, GetPreviewPageEventArgs e) { var document = (PrintDocument)sender; // 配列からプレビュー表示するUIElementを取り出す var element = printPages[e.PageNumber - 1]; // プレビューページに表示するオブジェクトを設定する document.SetPreviewPage(e.PageNumber, element); }
複数ページ存在している場合は、ページを変更する度にこのイベントハンドラが実行されます。ここまでの処理が実装できていれば、正しくプレビューが表示されることが確認できます。
印刷をおこなう
さて、手順(3)での[印刷]のボタンをクリックするとAddPagesイベントのハンドラprintDocument_AddPagesメソッドが実行されます。AddPageメソッドを使って、プリンターで印刷させるUIElementを追加します。
最後に印刷物の追加が完了したことをAddPagesCompleteメソッドを使って通知します。
private void printDocument_AddPages(object sender, AddPagesEventArgs e) { var document = (PrintDocument)sender; // プリンタに送信する印刷ページを追加する for (int i = 0; i < printPages.Count; i++) { printDocument.AddPage(printPages[i]); } // アプリケーションでの印刷ページの追加が完了したことを通知する document.AddPagesComplete(); }
ここまで問題なく処理が実装できていれば、プリンターから紙が出てくる(XPSの場合はドキュメントフォルダにファイルが生成されている)かと思います。以上で印刷をおこなう方法については終わりです。
印刷機能をチャーム以外から呼びだす
また、印刷機能を呼び出すのにチャームを使う以外にも、プログラム側から表示することも可能です。
private async void btnPrint_Click(object sender, RoutedEventArgs e) { if (Windows.UI.ViewManagement.ApplicationView.Value != Windows.UI.ViewManagement.ApplicationViewState.Snapped) { await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync(); } }