XPS ドキュメントビューワー

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 ファイルを作成する」のページで説明します。


XPSViewer

下図は、Microsoft XPS Essentials Pack に含まれる単独で動作する XPSViewer を起動したところです。次の項目で説明する DocumentViewer コントロールとほとんど同じであることが分かります。

XPSViewer2


DocumentViewer コントロール

XPS は WPF では固定ドキュメントと呼んでいますが、固定ドキュメントは FixedDocument オブジェクトです。このオブジェクトを表示するコントロールは、DocumentViewer コントロールだけです。そこで、このコントロールに XPS ファイルを読み込ませてみましょう。

下図は、フォームにメニューバーと DocumentViewer コントロールだけを配置したものです。ツールバーと[検索] のためのコントロールが見えますが、これは DocumentViewer コントロール自身に標準装備されているものです。

XPSViewer

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

FixedDocument オブジェクトをビューワーに表示する

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);
    }
  }
}

XAML ファイルの文字コード

いろいろとテストしていて、奇妙なことに気付きました。私がいつも使っているテキストエディタでは文字コードとして 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 であれば問題ありませんので、覚えておいてください。

−以上−