FixedDocumentの印刷およびXPS形式での保存

公開日: : 最終更新日:2015/10/20 Blog, Microsoft , , ,

こんにちは。
以前、XAMLファイルを帳票テンプレートとして動的ロードする記事を掲載しました。

今回はそれに印刷機能とXPS保存機能を追加しました。

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="800" Width="525">
    <Grid>
        <Grid.RowDefinitions> 
            <RowDefinition Height="50" /> 
            <RowDefinition /> 
        </Grid.RowDefinitions> 
        <StackPanel Orientation="Horizontal"> 
            <Button Margin="5" Width="100" Content="Xaml Load" Click="Load_Click" /> 
            <Button Margin="5" Width="100" Content="ViewModel Bind" Click="Bind_Click" /> 
            <Button Margin="5" Width="100" Content="Send to Printer" Click="Print_Click" /> 
            <Button Margin="5" Width="100" Content="Save to XPS" Click="Save_Click" /> 
        </StackPanel> 
        <DocumentViewer Grid.Row="1"> 
            <FixedDocument x:Name="fixedDoc" /> 
        </DocumentViewer> 
    </Grid> 
</Window>
'for Load_Click 
Imports Microsoft.Win32 
Imports System.Xaml 
Imports MarkUp = System.Windows.Markup 
'for Save_Click 
Imports System.IO.Packaging 
Imports System.Windows.Xps.Packaging 
Imports System.Windows.Xps 
Imports System.Printing 

Class MainWindow 
     ''' <summary>
     ''' Xamlをロードする
     ''' </summary>
     ''' <remarks>※エラーチェックなどは特に行ってないので注意</remarks>
     Private Sub Load_Click(sender As Object, e As RoutedEventArgs)
         'Xamlファイルを選択
         Dim selectDialog = New OpenFileDialog()
         If selectDialog.ShowDialog() = False Then
             Return
         End If
         'ロード処理。XamlReaderでロードする
         Dim selectPath = selectDialog.FileName
         Dim pageContent = DirectCast(MarkUp.XamlReader.Load(Xml.XmlReader.Create(selectPath)), PageContent)
         fixedDoc.Pages.Add(pageContent)
     End Sub

     ''' <summary>
     ''' ViewModelをセットする
     ''' </summary>
     Private Sub Bind_Click(sender As Object, e As RoutedEventArgs)
         Me.DataContext = New HogeViewModel()
     End Sub

     ''' <summary>
     ''' ロードしたXamlを印刷する
     ''' </summary>
     Private Sub Print_Click(sender As Object, e As RoutedEventArgs)
         'PrintTicherの設定
         Dim localPrtServer = New LocalPrintServer()
         Dim localPrtQueue = localPrtServer.DefaultPrintQueue
         Dim writer = PrintQueue.CreateXpsDocumentWriter(localPrtQueue)
         Dim ticket = localPrtQueue.DefaultPrintTicket
         '用紙サイズの設定(A4、縦)
         ticket.PageMediaSize = New PageMediaSize(PageMediaSizeName.ISOA4)
         ticket.PageOrientation = PageOrientation.Portrait
         'FixedDocumentの内容をPrintWriterに送る
         writer.WriteAsync(fixedDoc, ticket)
         MessageBox.Show("印刷完了")
     End Sub

     ''' <summary>
     ''' ロードしたXamlを保存する
     ''' </summary>
     Private Sub Save_Click(sender As Object, e As RoutedEventArgs)
         '保存先を選択
         Dim saveDialog = New SaveFileDialog()
         If saveDialog.ShowDialog() = False Then
             Return
         End If
         'XpsDocumentWriterを使ってFixedDocumentの内容をXPSに出力
         Using pac = Package.Open(saveDialog.FileName, IO.FileMode.Create)
             Using xps = New XpsDocument(pac)
                 'System.Printing.dllの参照が必要
                 Dim writer = XpsDocument.CreateXpsDocumentWriter(xps)
                 writer.Write(fixedDoc.DocumentPaginator)
             End Using
         End Using
         MessageBox.Show("保存完了")
     End Sub
End Class 

XamlReaderで動的にXamlファイルをロードしています。(ファイルではなく文字列からXamlロードも可能)
保存時もWriteAsyncで非同期に出来ますが、StreamのDisposeのタイミングが面倒だったため
同期実行しています。

Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Public Class HogeViewModel
    Implements INotifyPropertyChanged

    Public Sub New()
        Hoge = "HogeHoge!!"
        Piyo = "PiyoPiyo!!"
        Foo = "FooFoo!!"
    End Sub

    Private _Hoge As String
    Public Property Hoge() As String
        Get
            Return _Hoge
        End Get
        Set(ByVal value As String)
            _Hoge = value
            RaisePropertyChanged()
        End Set
    End Property

    Private _Piyo As String
    Public Property Piyo() As String
        Get
            Return _Piyo
        End Get
        Set(ByVal value As String)
            _Piyo = value
            RaisePropertyChanged()
        End Set
    End Property

    Private _Foo As String
    Public Property Foo() As String
        Get
            Return _Foo
        End Get
        Set(ByVal value As String)
            _Foo = value
            RaisePropertyChanged()
        End Set
    End Property

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    Private Sub RaisePropertyChanged(<CallerMemberName> Optional propName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propName))
    End Sub
End Class

CallerMemberを使ってみました。(.NET4.5から使用可能)
毎度RaisePropertyChangedにハードコードでプロパティ名を渡していたので
これは楽かもしれないです。

<PageContent xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              mc:Ignorable="d" 
              d:DesignHeight="300" d:DesignWidth="300">
    <FixedPage DataContext="{Binding}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBlock Margin="5" Grid.Row="0" Text="Hoge" />
            <TextBlock Margin="5" Grid.Row="1" Text="Piyo" />
            <TextBlock Margin="5" Grid.Row="2" Text="Foo" />
            <TextBox Margin="5" Grid.Column="1" Grid.Row="0" Text="{Binding Hoge}" />
            <TextBox Margin="5" Grid.Column="1" Grid.Row="1" Text="{Binding Piyo}" />
            <TextBox Margin="5" Grid.Column="1" Grid.Row="2" Text="{Binding Foo}" />
        </Grid>
    </FixedPage>
</PageContent>

関連記事

【.NET】16進数文字列から色を設定する

文字列→Colorクラスへの変換メモ プログラム上でFromArgbメソッドに16

記事を読む

no image

Windows 10 IoT 系の概要、エディション、入手方法などを一度整理

Windows 10 IoT にここ最近振り回されているので、ここまで解釈した内容にて、まとメモ 正

記事を読む

no image

【UWP】CS1061 : ‘XXX’に’InitializeComponent’の定義が含まれておらず

いろいろなことに起因しており、引き起こされた問題であって、 根本的な原因ではない可能性はあるが、凡ミ

記事を読む

no image

Developers Festa Sapporo 2016 メモ

ブログ書くまでが、Developers Festa Sapporo 2016 社内とかに展開するよ

記事を読む

VisualStudio2015でiOSアプリケーション開発

こんにちは。 Windows10にアップグレードしました。 VisualStudioも201

記事を読む

【iPhoneアプリ】開発者登録手順(iOS Developer Program) その1

iPhoneアプリの作成からリリースまでの一通りの流れを体験したかったため、 簡単なiPhon

記事を読む

no image

【iPhoneアプリ】背景画像を設定する

ImageResourceにBg.pngという背景画像を登録しておく 背景を設定するタイミング

記事を読む

画面設計デザイン時の無料画面イメージ作成ツール

画面デザイン全般に使っているツールを紹介。 Webアプリ作成時のワイヤーフレームや、 ス

記事を読む

no image

UWPのScrollViewerでスクロール位置の同期を行うメモ

複数のScrollViewerのスクロール位置を同期したい場合、WPFではScrollChanged

記事を読む

no image

シングルボードコンピュータの動作温度について

Raspberry Pi 3 で屋外用のIoT機器を作成できないかと調べていたが、どうやらRaspb

記事を読む

Comment

  1. ぬかさ より:

    XAMLテンプレートからXPSを生成するというのをWindows ストアアプリでやりたいのですが、いい方法をご存じないでしょうか。

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

PAGE TOP ↑