Last Updated 2011/09/21
このページでは、XPS ドキュメントを表示する手順について説明します。
テスト用の XPS ドキュメントは WPF SDK の中にもありますが、Microsoft はサンプルドキュメントを公開しています。以下のサイトからダウンロードできますので、紹介しておきます。名前は、SampleXpsDocuments_1_0 です。
http://www.microsoft.com/whdc/xps/xpssampdoc.mspx
Windows Vista には標準で XPS ドキュメントビューワーが組み込まれています。試しに、XPS ファイルをダブルクリックすると、インターネットエクスプローラが起動するはずです。
ところで、Microsoft は Microsoft XPS Essentials Pack なるものを公開しています。これは Windows XP ユーザーのためのものですが、Windows Vista でも使えます。以下のサイトからダウンロードできます。
http://www.microsoft.com/japan/whdc/xps/viewxps.mspx
Windows XP にこれをインストールすると、Microsoft XPS Document Writer をインストールするとともに、単独で動作する XPS Viewer が XPS ビューワーとして使えるようになります。拡張子の .xps にこのビューワーを関連付けておくと、インターネットエクスプローラをいちいち起動する必要がなくなります。なお、Microsoft XPS Document Writer については「XPS ファイルを作成する」のページで説明します。
下図は、Microsoft XPS Essentials Pack に含まれる単独で動作する XPSViewer を起動したところです。次の項目で説明する DocumentViewer コントロールとほとんど同じであることが分かります。
XPS は WPF では固定ドキュメントと呼んでいますが、固定ドキュメントは FixedDocument オブジェクトです。このオブジェクトを表示するコントロールは、DocumentViewer コントロールだけです。そこで、このコントロールに XPS ファイルを読み込ませてみましょう。
下図は、フォームにメニューバーと DocumentViewer コントロールだけを配置したものです。ツールバーと[検索] のためのコントロールが見えますが、これは DocumentViewer コントロール自身に標準装備されているものです。
DocumentViewer コントロールに標準装備の機能をリストアップしておきます。ツールバーの左から次のとおりです。
以下の XAML コードは、上図のフォームを作ったときのものです。
<Window x:Class="XPSViewer.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="XPS Viewer" Height="400" Width="500"> <DockPanel> <Menu DockPanel.Dock="Top"> <MenuItem Header="ファイル(_F)"> <MenuItem Name="mnuFileOpen" Header="ファイルを開く" Click="mnuFileOpen_Click" /> <Separator /> <MenuItem Name="mnuFileExit" Header="終了" Click="mnuFileExit_Click" /> </MenuItem> </Menu> <DocumentViewer Name="docViewer" /> </DockPanel> </Window>分離コード
以下は、メニュー項目を選択したときのイベントハンドラと XPS ドキュメントを読み込むメソッドを示します。
namespace XPSViewer { public partial class Window1 : Window { public Window1() { InitializeComponent(); } //------------------------------------------------------------------------------------- private void mnuFileOpen_Click(object sender, RoutedEventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "XPS ファイル|*.xps|すべてのファイル|*.*"; if (dlg.ShowDialog() == true) { this.LoadFileToDocumentViewer(dlg.FileName); } } //------------------------------------------------------------------------------------- private void mnuFileExit_Click(object sender, RoutedEventArgs e) { this.Close(); } //------------------------------------------------------------------------------------- // 固定ドキュメントをビューワーに読み込む // fileName : .xps ファイル名 private void LoadFileToDocumentViewer(string filename) { XpsDocument document = new XpsDocument(filename, FileAccess.Read, CompressionOption.NotCompressed); FixedDocumentSequence sequence = document.GetFixedDocumentSequence(); docViewer.Document = sequence as IDocumentPaginatorSource; } } // end of Window1 class } // end of namespace
XPS ドキュメントを表示するためのコントロールは DocumentViewer オブジェクトですが、このオブジェクトに設定できるオブジェクトは FixedDocument オブジェクトだけです。XPS ドキュメントは FixedDocument オブジェクトをパッケージ化したものにすぎません。これについては、「XPS ファイルの秘密」を参照してください。
さて、FixedDocument オブジェクトは XAML コードだけで構築できますし、分離コードだけでも可能です。FixedDocument オブジェクトを作成する手順は別途説明するとして、ここでは FixedDocument オブジェクトを定義する XAML ファイルが存在する場合に、それを DocumentViewer コントロールに読み込む手順を説明します。
フォームに button1 と documentViewer を配置します。button1 をクリックすると、ファイルを開くダイアログボックスが表示されますので、目的の XAML ファイルを選択してください。
private void button1_Click(object sender, ExecutedRoutedEventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "XAML ファイル|*.xaml|すべてのファイル|*.*"; dlg.InitialDirectory = Directory.GetCurrentDirectory(); if (dlg.ShowDialog() == true) { Stream stream = dlg.OpenFile(); try { object obj = XamlReader.Load(stream); FixedDocument fixedDoc = obj as FixedDocument; if (fixedDoc != null) { documentViewer.Document = fixedDoc; } } catch (Exception ex) { MessageBox.Show(ex.Message); } } }
いろいろとテストしていて、奇妙なことに気付きました。私がいつも使っているテキストエディタでは文字コードとして shift-jis を使う設定にしていますが、これで作成した FixedDocument オブジェクトを定義する XAML ファイルを DocumentViewer コントロールに読み込ませようとしたとき、日本語の部分でエラーになりました。
そこで、 XamlReader クラスの Load メソッドに ParserContext オブジェクトを設定する構文がありますので、これを利用しようと考えました。ParserContext クラスには文字コードを指定する機能はありませんが、そのコンストラクタに XmlParserContext オブジェクトを指定する構文があることに気付きました。ここに文字エンコーディングを指定する機能があります。
ということで、次のようなコードを作ってみました。
XmlParserContext xmlParserContext = new XmlParserContext(null, null, "ja-jp", XmlSpace.None, System.Text.Encoding.GetEncoding("shift-jis")); ParserContext parserContext = new ParserContext(xmlParserContext); object obj = XamlReader.Load(stream, parserContext);
これで、shift-jis の文字コードを .Net Framework の内部文字コードである Unicode に変換されるはずです。ところが、やはり日本語のところで「無効な文字がある」と怒られます。
次に、XmpParserContext オブジェクトのコンストラクタの 2 番目の引数に null を指定するのがよくないのだろうと考え、ここに XmlNamespaceManager オブジェクトを設定すると、エラーは発生しないのですが、何も表示されません。
私のとった手順がおかしいのか、WPF のほうに問題があるのかは分かりませんが、XAML ファイルの文字コードを UTF-8 または UTF-16 に変更すると正常に動作します。
ちなみに、shift-jis のファイルを読み込むコードを使って UTF-8 のファイルを読み込んでも正常に動作しますので、文字のエンコーディングの部分は無視されているのかもしれません。いずれにしろ、UTF-8 または UTF-16 であれば問題ありませんので、覚えておいてください。
−以上−