Silverlight印刷による使用詳細は、マイクロソフトのBugですか?

8253 ワード

1:Silverlight 4アプリケーションを新規作成します。名前はSLStudyです。完成後は以下の通りです
image
2:SLStudyでSilverlightユーザコントロールを新規作成し、印刷するコントロールとしてPrint 1.xamlを作成します。
Print 1.xamlにコードを追加しました。

<Grid x:Name="LayoutRoot" Background="White">
      <Button> , </Button>
</Grid>
:印刷する内容が確立されました。ここで印刷するのはボタンです。
4:MainPage.xamlコードを修正すると以下の通りです。

<Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <Button x:Name="btnPrint1" Click="btnPrint1_Click">Print1</Button>
        </StackPanel>
</Grid>
:バックグラウンドコードは:

private void btnPrint1_Click(object sender, RoutedEventArgs e)
        {
            PrintDocument printDocument = new PrintDocument();
            printDocument.PrintPage += new EventHandler<PrintPageEventArgs>(printDocument_PrintPage);
            PrintDocument.Print(" , ");
        }

        void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            e.PageVisual = new Print1();
        }

です。
SL 4で印刷機能を提供するのは、PrintDcumentクラスなので、まずこのクラスのオブジェクトを実装します。
次にPrintPageイベントを登録します。PrintPageイベントは印刷時にトリガされます。
print DcumentのPrintメソッドを呼び出して印刷します。
PrintDcumentのPrintPageイベントでは、PrintPageeventArgsは、印刷のパラメータです。
中では現在のプリンタの情報を取得できます。
image
ここにPageVisual、つまり印刷する対象を設定すればいいです。

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
  e.PageVisual = new Print1();
}
を全部書いたら、アプリケーションを実行し、Print 1をクリックして、印刷ウィンドウをイジェクトすることができます。印刷効果は下図のようになります。
image
もちろん、私達のプリント需要はこんなに簡単ではありません。Print 1の内容を設定する必要があるかもしれません。ボタン表示の文字を変更すると、私たちはこのようにすることができます。

void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    Print1 printVisual = new Print1();
    printVisual.btnSample.Content = " , ";
    e.PageVisual = printVisual;
}
は、PrintPageeventArgsパラメータのPageVisualオブジェクトを設定することによって、そのページを印刷する機能を実現します。
ここでまとめます。
1:印刷する内容を確定し、新しいUserControlを作成して印刷の内容を表示します。
2:PrintDcumentオブジェクトを新規作成し、PrintPageイベントを登録し、Printメソッドを呼び出します。
3:PrintPageイベントでは、印刷するオブジェクトを作成し、データベースからデータを取得し、コントロールにデータを結合し、次いで、データを結合したコントロールの値をPrintPageeventArgsのPageVisualオブジェクトに割り当てる。 
複数ページの印刷問題:
印刷するのが一枚だけなら、この方法で十分ですが、一つの文書を複数印刷する必要があります。
上のボタンを5枚印刷すると、どうやって実現されますか?
上記のPrintPageeventArgsのHas MorePagesパラメータを覚えていますか?
PrintPageイベントのトリガ後、デフォルトのHasMorePagesはfalseです。Has MorePagesをtrueに設定し、PrintPageイベントを継続的にトリガすることができます。Has MorePages属性がtrueである場合、PrintPageイベントはHas MorePagesがfalseであるまで何度も発生します。
上のボタンを5枚印刷すると、Has MorePagesをtrueとして4回設定できます。最後にHas MorePagesをfalseとして設定すればいいです。
修正後のprint Dcument_PrintPage方法は以下の通りである。

int count = 5;
int printCount = 0;
void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
    Print1 printVisual = new Print1();
    printVisual.btnSample.Content = " , ";
    e.PageVisual = printVisual;
    printCount++;

    if (printCount < count) // , 。
    {
         e.HasMorePages = true;
    }
    else
    {
        e.HasMorePages = false;
    }
}

は、現在印刷されているのが何ページ目かを知る必要があり、これはprint Dcument.PrintedPageCount属性を調べることによって得られる。
PrintDcument_PrintPageメソッドでは、senderオブジェクトはPrintDcumentオブジェクトですので、タイプを強制的に変換することができます。
上の5つのButtonの内容を全部1,2,3,4,5に修正したいと思います。コードを修正してもいいです。

       int count = 5;
        int printCount = 0;

        void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            PrintDocument printDocument = sender as PrintDocument;
            Print1 printVisual = new Print1();
            printVisual.btnSample.Content = string.Format(" {0}", printDocument.PrintedPageCount);
            e.PageVisual = printVisual;
            printCount++;

            if (printCount < count)
            {
                e.HasMorePages = true;
            }
            else
            {
                e.HasMorePages = false;
            }
        }

は実際に私達のprintCount変数は必要なくなります。直接print Docment.PrintedPageCountを使えばいいです。具体的なコードの実現は読者自身で実現します。
マイクロソフトのBug?
もしあなたのプリンタが
image
印刷の結果は*.xpsのファイルですが、印刷中にヒントボックスをポップアップして保存先を尋ねます。
PrintPageイベントでブレークポイントを打つと、保存先を尋ねる際に、PrintPage方法が既に実行されています。つまり、PringPage方法は2回実行されます。一回目は本物のプリントがありません。
たとえば:
image
image 
上の図の画面でキャンセルをクリックすると、システムが応答を失ってカードが死ぬ恐れがあります。
ユーザがクリックして保存すると、PrintPageイベントは再びトリガされます。
しかし、一回印刷しましたので、複数ページの印刷時に問題が発生する可能性があります。
二つのマーク変数を使ってこの問題を解決できます。
たとえば、変更コードは以下の通りです。

int count = 5;
        int printCount = 0;

        /// <summary>
        /// , 。
        /// </summary>
        private bool isInitialized = false;
        private bool realPrint = false;

        void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            PrintDocument printDocument = sender as PrintDocument;
            int currentPage = printDocument.PrintedPageCount;

            #region , , , PrintedPageCount 0
            if (currentPage == 0)
            {
                if (isInitialized) // , realPrint true
                {
                    realPrint = true;
                }

                isInitialized = true; // , 。
            }
            #endregion

            if (realPrint)
            {
                //PrintDocument printDocument = sender as PrintDocument;

                Print1 printVisual = new Print1();
                printVisual.btnSample.Content = string.Format(" {0}", printDocument.PrintedPageCount);

                e.PageVisual = printVisual;

                printCount++;
                if (printCount < count)
                {
                    e.HasMorePages = true;
                }
                else
                {
                    e.HasMorePages = false;
                }
            }
        }

2回印刷するので、1回目は初期化と考えられ、2回目はプリンタが本格的に印刷を開始すると考えられます。
したがって、2つの変数isInitializedおよびrealPrintは、それぞれ初期化かそれともリアル印刷かを表すために使用されてもよい。
一回目を実行する時print Dcument.PrintedPageCount==0はこの時isInitializedをtrueに設定します。
2回目を実行するときは、isInitialized==trueのため、realPrintをtrueに設定することができます。
後のコードの中でrealPrintがtrueであると判断するだけでいいです。