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>

関連記事

IntelliTestはどこまでカバーしてくれるのか

私はレガシーな開発環境・案件が多かったのですが、 この頃、ユニットテストを利用する機会が増えてきま

記事を読む

【iPhoneアプリ】リリース手順〜審査完了後〜

前回からの続き。 中身が無いアプリだったのでリジェクトされると思いきや 審査に通ってしま

記事を読む

Package ‘Win10SDK_10.0.14393.33,version=10.0.14393.3300’ failed to install.

Visual Studio 2017 RC1 でUWPアプリケーションのコンポーネントインストールす

記事を読む

no image

Xamarin.UITest, Xamarin Test Cloud にて iPhone 6 Plus, 6S Plus, 7 Plus などで app.Tap が効かない

動作しないというか、app.Tapがどうしても反応しない。 app.ScreenShotなどは動作す

記事を読む

no image

【.NET】正規表現の復習

正規表現エンジン System.Text.RegularExpressions.Regexオブジェ

記事を読む

no image

UWPとAzure Web AppsでOData

超メモ。走り書き。 Azure上にSQLデータベースコードファーストなAPIをODataで作成する。

記事を読む

no image

Visual Studio 2017 Version15.2 にアップデート後、Xamarin.iOS でビルドエラーが発生時の回避メモ

環境 Visual Studio Enterprise 2017 Version 15.2

記事を読む

no image

Windows 10 IoT Core の 製品化メモ

概念実証(Proof of concept)を終了し、製品化を行いたい場合のステップ サインア

記事を読む

ストアアプリ、UWPアプリをデスクトップアプリケーションから起動する

SendKeyなどを使って無理やり検索ウインドウへ指定した、起動方法しか知らなかったのでメモ(とんで

記事を読む

no image

【.NET】イベントのサブスクライブとサブスクライブ解除

.NETでイベントをハンドルする方法 サブスクライブ void CustomEven

記事を読む

Comment

  1. ぬかさ より:

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

Message

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

PAGE TOP ↑