No se puede usar un solo FlowDocument
para generar documentos grandes porque se quedará sin memoria. Sin embargo, si es posible generar su salida como una secuencia de FlowDocument
o como una extremadamente alta ItemsControl
, es posible.
He encontrado la manera más fácil de hacer esto es a subclase DocumentPaginator
y pasar una instancia de mi subclase de XpsDocumentWriter.Write
:
var document = new XpsDocument(...);
var writer = XpsDocument.CreateXpsDocumentWriter(xpsDocument);
writer.Write(new WidgetPaginator { Widget = widgetBeingPrinted, PageSize = ... });
La clase WidgetPaginator
sí es bastante simple:
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);
}
Por supuesto, todavía tiene que escribir el código que realmente crea las páginas.
Si desea utilizar una serie de FlowDocuments para crear el documento
Si estás usando una secuencia de FlowDocuments
para diseñar una sección de su documento a la vez en lugar de todos a la vez, su encargo paginator puede funcionar en dos pasos:
- El primer paso ocurre cuando se construye el paginador. Crea un
FlowDocument
para cada sección, luego obtiene un DocumentPaginator
para recuperar el número de páginas. Cada sección FlowDocument
se descarta una vez que se cuentan las páginas.
- El segundo pase ocurre durante la salida del documento real: si el número pasó a
GetPage()
está en el más reciente FlowDocument
creado, GetPage()
simplemente llama al paginador de ese documento para obtener la página adecuada. De lo contrario, descarta ese FlowDocument y crea un FlowDocument
para la nueva sección, obtiene su paginador, luego llama al GetPage()
en el paginador.
Esta estrategia le permite continuar a utilizar FlowDocuments
como lo has sido, siempre y cuando se puede separar los datos en "secciones" cada uno con su propio documento. Su paginador personalizado trata de manera efectiva todos los FlowDocuments individuales como un documento grande. Esto es similar a la función "Documento maestro" de Word.
Si usted puede hacer que sus datos como una secuencia de imágenes apiladas verticalmente
En este caso, la misma técnica se puede utilizar.Durante el primer pase, todos los efectos visuales se generan en orden y se miden para ver cuántos encajarán en una página. Se construye una estructura de datos para indicar qué rango de imágenes (por índice o lo que sea) se encuentran en una página determinada. Durante este proceso, cada vez que una página se llena, la siguiente vista se coloca en una página nueva. Los encabezados y pies de página serían manejados de la manera obvia.
Durante la generación real de documentos, se implementa el método GetPage()
para regenerar los elementos visuales previamente decididos para estar en una página dada y combinarlos utilizando un DockPanel vertical u otro panel de su elección.
He encontrado esta técnica más flexible a largo plazo porque no tiene que lidiar con las limitaciones de FlowDocument
.
> OutOfMemeoryExcpetion es probablemente causado por ... En otras palabras, no ha verificado realmente. Necesitamos más información para decirle cuál es el problema. –
@ bitbonk Me encuentro con el mismo problema ahora. ¿Encontraste alguna solución? –