11

WPF アプリケーションから大きな XPS ドキュメント (>400 ページ) を生成 (および印刷または保存) したいと考えています。XPS に書き込む必要のある大量のインメモリ データがあります。

取得せずにこれを行うにはどうすればよいOutOfMemoryExceptionですか?ドキュメントをチャンクで書き込む方法はありますか? これは通常どのように行われますか?そもそも、大きなファイルに XPS を使用するべきではありませんか?

の根本的な原因はOutOfMemoryException、巨大なFlowDocument. 完全なファイルを作成し、FlowDocumentそれを XPS ドキュメント ライタに送信しています。これは間違ったアプローチですか?

4

6 に答える 6

5

どのようにしますか?コードは表示されませんでした。

次のように、XpsDocumentWriter を使用してチャンクで書き込みます。

FlowDocument flowDocument =  . .. ..;

// write the XPS document
using (XpsDocument doc = new XpsDocument(fileName, FileAccess.ReadWrite))
{
    XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(doc);
    DocumentPaginator paginator = ((IDocumentPaginatorSource)flowDocument).DocumentPaginator;

    // Change the PageSize and PagePadding for the document
    // to match the CanvasSize for the printer device.
    paginator.PageSize = new Size(816, 1056);
    copy.PagePadding = new Thickness(72);  
    copy.ColumnWidth = double.PositiveInfinity;
    writer.Write(paginator);
}

これはうまくいきませんか?

于 2010-02-26T15:28:41.287 に答える
4

関係する特定のシステムを完全に知らないということから言えば、アラスカのWolf Fenceデバッグ手法を使用して、問題の原因を特定することをお勧めしますか?他のレスポンダーがあなたが経験しているのと同じ問題を報告していないので、私はこれを提案しています。再現しやすいバグを処理する場合、Wolf Fenceは非常に簡単に実行できます(競合状態などではうまく機能しません)。

  1. 入力データの中点を選択し、そのデータのみから出力ドキュメントを生成してみてください。
  2. 成功した場合は、入力の約75%のポイントを選択して再試行します。それ以外の場合は、入力の約25%のポイントを選択して再試行します。
  3. 泡立てて、すすぎ、繰り返し、毎回、作業/失敗の線がある場所にウィンドウを狭めます。
  4. 「おもしろい」という特定のページ(またはそのページ上の特定のオブジェクト)をかなりすばやく特定できる場合があります。注:このlog2(N)回だけ実行する必要があります。この場合、言及した400ページの場合は9回実行する必要があります。

これで、おそらく直接攻撃できるものができました。幸運を。

于 2010-03-08T19:06:34.517 に答える
4

FlowDocumentメモリが不足するため、大きなドキュメントを生成するためにシングルを使用することはできません。ただし、出力をシーケンスFlowDocumentまたは非常に高いものとして生成できる場合ItemsControlは、可能です。

これを行う最も簡単な方法はDocumentPaginator、サブクラスを作成して、サブクラスのインスタンスを に渡すことXpsDocumentWriter.Writeです。

var document = new XpsDocument(...);
var writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(new WidgetPaginator { Widget = widgetBeingPrinted, PageSize = ... });

WidgetPaginatorクラス自体は非常に単純です。

class WidgetPaginator : DocumentPaginator, IDocumentPaginatorSource
{
  Size _pageSize;

  public Widget Widget { get; set; }

  public override Size PageSize { get { return _pageSize; } set { _pageSize = value; } }
  public override bool IsPageCountValid { return true; }
  public override IDocumentPaginatorSource Source { return this; }
  public override DocumentPaginator DocumentPaginator { return this; }
  public override int PageCount
  {
   get
    {
      return ...; // Compute page count
    }
  }
  public override DocumentPage GetPaget(int pageNumber)
  {
    var visual = ...; // Compute page visual

    Rect box = new Rect(0,0,_pageSize.With, _pageSize.Height);
    return new DocumentPage(visual, _pageSize, box, box);
  }

もちろん、実際にページを作成するコードを作成する必要があります。

一連の FlowDocuments を使用してドキュメントを作成する場合

一連のFlowDocumentsドキュメントを一度にではなく 1 セクションずつレイアウトするために使用している場合、カスタム ページネーターは 2 つのパスで機​​能します。

  • 最初のパスは、ページネーターが構築されるときに発生します。FlowDocumentセクションごとに を作成し、DocumentPaginatorを取得してページ数を取得します。FlowDocumentページがカウントされた後、各セクションは破棄されます。
  • 2 番目のパスは、実際のドキュメント出力中に発生します。渡された番号がGetPage()最近FlowDocument作成されたものである場合、GetPage()そのドキュメントの paginator を呼び出して適切なページを取得します。それ以外の場合は、その FlowDocument を破棄しFlowDocument、新しいセクションのを作成し、そのページネーターを取得してから、ページネーターを呼び出しGetPage()ます。

FlowDocumentsこの戦略では、データをそれぞれ独自のドキュメントを持つ「セクション」に分割できる限り、これまでと同じように使用し続けることができます。カスタム ページネーターは、個々のすべての FlowDocuments を 1 つの大きなドキュメントとして効果的に扱います。これは、Word の「マスター ドキュメント」機能に似ています。

垂直に積み重ねられたビジュアルのシーケンスとしてデータをレンダリングできる場合

この場合、同じ手法を使用できます。最初のパスでは、すべてのビジュアルが順番に生成され、ページに収まる数が測定されます。データ構造は、特定のページで見つかったビジュアルの範囲を (インデックスなどによって) 示すために構築されます。このプロセスの間、ページがいっぱいになるたびに、次のビジュアルが新しいページに配置されます。ヘッダーとフッターは当然の方法で処理されます。

実際のドキュメント生成中GetPage()に、特定のページにあると以前に決定されたビジュアルを再生成し、垂直 DockPanel または選択した他のパネルを使用してそれらを結合するメソッドが実装されます。

の制限に対処する必要がないため、この手法は長期的にはより柔軟であることがわかりましたFlowDocument

于 2010-03-09T11:11:57.493 に答える
3

XPS が長いドキュメントでメモリ不足をスローしないことを確認できます。理論上 (XPS での操作はページベースであるため、ドキュメント全体をメモリにロードしようとはしません) と実際 (私は XPS ベースのレポートを使用しており、表示されるランナウェイ エラー メッセージは合計で数千に上ります)ページ)。

問題が 1 つの特に大きなページにある可能性はありますか? たとえば、巨大な画像?高 DPI 解像度の大きなページ? ドキュメント内の単一のオブジェクトが大きすぎて一度に割り当てることができない場合、メモリ不足の例外が発生します。

于 2010-03-03T10:21:27.577 に答える
0

あなたが言うように:おそらく、メモリ内の FixedDocument がメモリを消費しすぎています。

おそらく、XPS ページを個別に書き出し (そして、FixedDocument が毎回リリースされるようにする)、その後でマージを使用するというアプローチは、実り多いものになる可能性があります。

各ページを別々に書くことはできますか?

ニック。

ps。お気軽に私に直接連絡してください (info@nixps.com)。私たちは NiXPS で多くの XPS 関連の作業を行っており、この問題を解決する手助けをしたいと思っています。

于 2010-03-07T09:50:21.873 に答える
0

sos を使用して、すべてのメモリを使用しているものを見つけましたか?

ドキュメントの作成中に管理対象または管理対象外のオブジェクトが作成され、ドキュメントが完成するまでリリースされない (またはまったくリリースされない) 可能性があります。

Rico Mariani によるマネージ メモリ リークの追跡が役立つ可能性があります。

于 2010-03-03T16:17:55.093 に答える