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

Developers Festa Sapporo 2016 メモ

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

記事を読む

no image

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

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

記事を読む

no image

【C#, WPF】XMLデータをListViewに表示し、チェック項目のみXML保存させる

前回の続きというか、WPF版。 <Window x:Class="MyWP

記事を読む

no image

Azure へ WordPress 環境を作成

よくあるやつだけど。 社内LT用

記事を読む

no image

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

環境 Visual Studio Enterprise 2017 Version 15.2

記事を読む

no image

Xamarin.Forms で ScrollView の中に Map を配置したとき、Androidで地図のスクロールが出来なくなる

iOSは問題ないけど、AndroidはScrollViewにタッチを持ってかれてる感じ。 カスタ

記事を読む

WordPressでスパムコメント対策

WordPressのスパムコメント対策を行ったのでメモ。 標準でAkismetがインストール済み(

記事を読む

Visual Studio から Android SDK Managerが起動できない

Android SDKやエミュレーターイメージのアップデートを行いたい場合にAndroid SDK

記事を読む

no image

SmallBasicで拡張ライブラリを使用する

こんにちは。 teratailにて以下の質問に遭遇しまして。 small basic の 拡

記事を読む

no image

属性を使って、列挙型の列挙子を並び替え、フィルタリングする

メモだよ

記事を読む

Comment

  1. ぬかさ より:

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

Message

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

PAGE TOP ↑