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

【UWP】矢印キーでのフォーカス移動

FocusManagerで上下左右のフォーカス遷移が出来るので、その仕組みを利用してやるビヘイビアを

記事を読む

no image

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

環境 Visual Studio Enterprise 2017 Version 15.2

記事を読む

【ストアアプリ】トースト通知の基本

Windowsストアアプリ開発での基本。 トースト通知について投稿します。 Pack

記事を読む

no image

【ストアアプリ】バックグラウンドタスクを作成する

こんにちは。 Windows.ApplicationModel.Background名前空間を使用

記事を読む

no image

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

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

記事を読む

no image

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

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

記事を読む

no image

【解決】Visual Studio 2015 Update1 の Xamarin.Forms でインテリセンスを使いたい

前回保留になっていた問題が解決したのでメモっときます。 Visual Studio 2015 Up

記事を読む

no image

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

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

記事を読む

Flowで毎月の定期タスク設定

Flow を使い始めてみた。 Requrrenceで時間をトリガーにすることが出来るがSecond

記事を読む

【.NET Framework 4.6.1】MultiLineなTextBoxでCtrl+Aが使えない問題が解決(今更)

WinForms.NETなアプリケーションの標準TextBoxで、Multiline=Trueに設定

記事を読む

Comment

  1. ぬかさ より:

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

Message

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

PAGE TOP ↑