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>

関連記事

no image

Expression Encoder を組み込んだアプリケーションを配布する際のライセンス問題

Windowsアプリケーションにメディア編集機能を実装したい場合に、Expression Encod

記事を読む

【WPF/XAML】チェックボックスのデザイン変更

[xml] <Window x:Class="Sample"

記事を読む

no image

UWP+IoT Coreのシリアル通信メモ

Windows10 IoT + Raspberry Pi を始めようとしているのだが、どうもセンサー

記事を読む

【iPhoneアプリ】リリース手順〜iTunesConnect登録〜

AppStoreに有料アプリ、iAdアプリを公開するためには、 iTunes Connectで

記事を読む

no image

‘System.Windows.Navigation.BaseUriHelper’ のタイプ初期化子が例外をスローしました。

作成した.NETアプリケーション(WPF)が起動しない。 今回は構成ファイル(app.config)

記事を読む

no image

Developers Festa Sapporo 2016 メモ

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

記事を読む

no image

Windows10 IoT CoreでWindowsアップデートの自動実行を停止する

Manage IoT Core device updates このリンクにアップデートコントロール

記事を読む

no image

UWPでMicrosoft.OData.Clientを使用する時、LINQ式でエラー

UWPからは非同期メソッドを実行する必要があるので、通常はExecuteAsyncをコールするが、

記事を読む

no image

UWPとAzure Web AppsでOData

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

記事を読む

no image

KeyboardNavigation以外でFocusVisualStyleを表示させる

WPFです。 結論としてはリフレクションで無理やりやれなくはなさそうという感じ。 元ネタはMSDN

記事を読む

Comment

  1. ぬかさ より:

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

Message

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

PAGE TOP ↑