« [P12]WPFアプリケーション:マウスでテキストボックスをクリックした場合のイベントハンドラーは? | トップページ | [P14] WPF: プリンター印刷(XPS) »

WPF:印刷の初めての成功例コード

------------------------------------------------- 

左の欄の、カテゴリー『パソコンの窓』内の [P14] の記事(WPF: プリンター印刷)
の付属資料コードです。そちらの本文とあわせて御覧下さい。
(本文のウィンドウとコードのウィンドウの二つを開いたほうが、見やすいです。)

本文
http://hokkai53.cocolog-nifty.com/blog/2008/01/p14wpf_xps_9e5d.html

なお、さらにこの成功例コードを解体して、実際の複数ページデータ読み出しに適合させた、第二付属コードへのリンク が、このページの最下段にある [後記] の末尾にあります。
-------------------------------------------------
コードの内容

WPFプログラミングの、本格的な複数ページ印刷が可能なコードをめざしますが、
始めて未知の領域に踏み込むのですから、
Canvas 上に Label が1個あって、Content = "Hello World !" と表示されている。
この Hello World ! だけを印刷する1ページだけのコードです。
複数ページの場合、どこがどうなるのかは、該当箇所に記載してあります。

中心部分以外のコードは、できるだけ省いています。

これ以外は、ブログ本文の解説を御覧下さい。以下、コードです。

XAML

<Window x:Class="MyFirstPrinting.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" >
    <Grid>
       
    </Grid>
</Window>

WPF アプリケーション・プロジェクトを新規作成したときのまま、何もしていない状態です。

MyFirstPrinting のところは、各自のもので差し支えありません。
逆にここを無理に変えようとすると、面倒な作業が必要になるので、そのことがわかっている方以外はそのまま。

以下の言語コード中で、XAML で処理して差し支えないものは、たった一行です。
ですから、一切使わないでまいります。

//-----------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;//実際は不要
using System.Windows.Navigation;//実際は不要
using System.Windows.Shapes;//実際は不要
//(以上)WPF アプリケーションとして、プロジェクトを新規作成した状態
//----------------------------------------
//アセンブリ参照設定で以下の二つを追加する
// ReachFramework
// System.Printing
using System.Windows.Xps;
using System.Windows.Xps.Packaging;
using System.IO;
using System.Printing;
using System.Windows.Markup;//IAddChild
//----------------------------------------
namespace MyFirstPrinting  //各自バラバラでよい
{
    public partial class Window1 : Window
    {
        Canvas printCanvas;
        Label lblHello;         
    //-----------------------------------   
        public Window1()
        {
            InitializeComponent();
            //--------------------------------------------
            MakeCanvasForPrint();
                //《コード:1》

            FixedDocument fixedDocument
                                 = CreateFixedDocumentFromFixedPages();
                //《コード:3》
                //《コード:3》は《コード:2》の結果を吸収しているので、
                //《コード:3》の実質は、《コード:2》を含み、
                //CreateFixedDocumentFrom"Canvaces"(); ともいうべき
                //内容になっている。

            SendFixedDocumentToPrinter(fixedDocument); 
                //《コード:4》
        }
 
       //-------------------------------------------------
        //《コード:4》 [第4段階] Printer(Queue)への書き出し
        //-------------------------------------------------   

        void SendFixedDocumentToPrinter(FixedDocument fixedDocument)
        {

            LocalPrintServer ps = new LocalPrintServer();
            PrintQueue pq = ps.DefaultPrintQueue;
            
            PrintDocumentImageableArea imgArea = null;
            XpsDocumentWriter xpsdw
                         = PrintQueue.CreateXpsDocumentWriter(ref imgArea);
       //上記メソッドの引数並びは、いろいろな種類があり、
              //それによって、印刷ダイアログを表示する。
              //PrintDialog クラスがあることとの関係は、まだよくわかりません。
            xpsdw.Write(fixedDocument);

        }
       
        //-------------------------------------------------
        //《コード:3》[第3段階]FixedPage から FixedDocument を作る
        //-------------------------------------------------   

        private FixedDocument CreateFixedDocumentFromFixedPages()
        {
            FixedDocument fixedDocument = new FixedDocument();
            fixedDocument.DocumentPaginator.PageSize
                                                      = new Size(96 * 8.5, 96 * 11);
            //---------------------------------------------
            PageContent pageContent = CreateFixedPageFromCanvas();
       //ここで《コード:2》が使われる
            fixedDocument.Pages.Add(pageContent);
            //複数ページの場合は、ここで複数回 Add()を繰り返す。
            //このプログラムでは、1ページのみを作る。
            return fixedDocument;
        }//CreateFixedDocumentFromFixedPages()
       

        //-------------------------------------------------
        //《コード:2》    [第2段階]Canvas の内容を
        //                    FixedPage(=>そして 最後に PageContent) にする
        //-------------------------------------------------   

        PageContent CreateFixedPageFromCanvas()
        {
            //作られた FixedPage は、最後に PageContent の子要素とされて、
            //次の FixedDocument 作成の準備が整う
            PageContent pageContent = new PageContent();
            FixedPage fixedPage = new FixedPage();

            //Canvas がFixedPage(=印刷用紙) 中のどこに位置づけられるか。
            FixedPage.SetLeft(printCanvas, 0);
            FixedPage.SetTop(printCanvas, 0);

      //この近辺に、Canvas サイズを用紙サイズに合わせる
            //調整用のコードが加わってくるものと考えられる。

            double pageWidth = 96 * 8.5;
            double pageHeight = 96 * 11;

            fixedPage.Width = pageWidth;
            fixedPage.Height = pageHeight;

            fixedPage.Children.Add((UIElement)printCanvas);
            //printCanvas=親(例えばWindow)があるとエラーになる
            //これが、Canvas は親要素を持ってはならない、という根拠

            Size sz = new Size(8.5 * 96, 11 * 96);
            fixedPage.Measure(sz);
            fixedPage.Arrange(new Rect(new Point(), sz));
            fixedPage.UpdateLayout();

            ((IAddChild)pageContent).AddChild(fixedPage);
            return pageContent;
        }//CreateFixedPageFromCanvas()
       
        //-------------------------------------------------
        //《コード:1》[第1段階]Canvas とその内容の用意
        //-------------------------------------------------

        void MakeCanvasForPrint()
        {//Canvas 全体が、1ページになる
            this.WindowState = WindowState.Maximized;//Window
            //---------------  Canvas  --------------------
            printCanvas = new Canvas();
                  // ここで this.Content = printCanvas; を
        // 絶対入れてはならない(親要素を持たない)
            printCanvas.Background = Brushes.Transparent;
            printCanvas.Width = 800;//数値はともに適当
            printCanvas.Height = 600;
        //後述の数値(8.5 * 96, 11 * 96)と不整合
                 //とりあえず、御勘弁を!
            //--------------  Label  ------------------------
            lblHello = new Label();
            printCanvas.Children.Add(lblHello);
            lblHello.Background = Brushes.Transparent;
            lblHello.Width = 160;
            lblHello.Height = 30;
            Canvas.SetTop(lblHello, 100);
            Canvas.SetLeft(lblHello, 50);
            lblHello.Content = "Hello World !";//これを印刷するのが最終目標          
        }//MakeCanvasForPrint()

    }//class Window1

}//namespace

[後記]
   このコードを実用に供することができるように組み換えた上で、実際に複数ページ
  印刷をしてみました(ある程度複雑な表の複数ページ印刷)。
   基本的な枠組みができあがって一通りのことが見通せた段階に立ってみると、
  GDI時代より、WPF下の方が印刷のコーディングは、いろいろな意味でわかりやすく
  可読性が高いものになった、という印象です。
      コーディング上では、あたかもラインプリンターからページプリンターになったような
  ものなのですから。


  なお、私はまだ最終的な最適解にまで到達しておりませんが、
実用化のためには上記コードを解体し、実際に複数ページ印刷ができるように
組み換える必要があります。 その際には、GDI当時とは異なる、WPFに対応した感覚が求められるように思われます。
ご参考までに、第二付属コードとして、下記のリンクから見られるようにしておきます。

 
[実際の複数ページ印刷対応の実用コード例(第二付属コード)]

    下記リンクをクリックして下さい。

http://hokkai53.cocolog-nifty.com/blog/2008/07/post_9b2d.html

以上。

|

« [P12]WPFアプリケーション:マウスでテキストボックスをクリックした場合のイベントハンドラーは? | トップページ | [P14] WPF: プリンター印刷(XPS) »

コメント

コメントを書く



(ウェブ上には掲載しません)




« [P12]WPFアプリケーション:マウスでテキストボックスをクリックした場合のイベントハンドラーは? | トップページ | [P14] WPF: プリンター印刷(XPS) »