WPF FlowDocument 确定块所在的页面
WPF FlowDocument determine what page a Block would be on
如果我有一个 var flow = new FlowDocument()
并且我在它的 BlockCollection
中添加了几个块:
if (m_Blocks == null || m_Blocks.Count <= 0)
return flow;
flow.Blocks.AddRange(m_Blocks.ToList());
var paginatorSource = flow as IDocumentPaginatorSource;
paginatorSource.DocumentPaginator.ComputePageCount();
var pageCount = paginatorSource.DocumentPaginator.PageCount;
我可以确定这份文件有多少页。
问题
如果页数大于 1,我该如何找出文档的哪些块无法放在第一页上?我在 Block
class 上找不到任何可以帮助我确定这一点的内容。但是由于分页器可以ComputePageCount()
,我认为这是可能的。
我对我试图完成的事情采取了蛮力的方法。基本上,我需要在每一页的顶部重复一个 Paragraph
。我假设这不是最高效的方式,但它完成了工作:
protected FlowDocument RenderBody()
{
var flow = new FlowDocument
{
PageWidth = PaperSizeDPI.Width,
PageHeight = PaperSizeDPI.Height,
ColumnGap = 0,
ColumnWidth = PaperSizeDPI.Width,
PagePadding = new Thickness(MarginDPI.Left, MarginDPI.Top + HeaderHeightDPI, MarginDPI.Right, MarginDPI.Bottom + FooterHeightDPI)
};
if (m_Blocks == null || m_Blocks.Count <= 0)
return flow;
// Get page count before deciding to deal with repeat blocks.
// Adding blocks to the FlowDocument is required before invoking
// `DocumentPaginator.ComputePageCount()`.
flow.Blocks.AddRange(m_Blocks.ToList());
int GetPageCount()
{
var paginatorSource = (IDocumentPaginatorSource) flow;
paginatorSource.DocumentPaginator.ComputePageCount();
return paginatorSource.DocumentPaginator.PageCount;
}
// If there is only one page, no roll-over of headers necessary
if (GetPageCount() <= 1) return flow;
// If we don't have a header to repeat, we assume the report is correct already
if (PrintTemplateConverter.BuildRepeatableHeader == null) return flow;
// Build the FlowDocument, one block at a time, checking if the page count
// changes so that we can inject a repeatable header
flow.Blocks.Clear();
var pageCount = 1;
var blocks = m_Blocks.ToList();
for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
{
flow.Blocks.Add(blocks[blockIndex]);
if (GetPageCount() <= pageCount) continue;
// If this block moved us to a new page, inject repeatable header in its spot.
// `flow.Blocks.AddRange(...)` ignores duplicate blocks (by reference).
// This is why I go through the "pain" of making a whole new Header block
// instance.
var blocksSoFar = flow.Blocks.ToList();
flow.Blocks.Clear();
blocksSoFar.Insert(blockIndex, PrintTemplateConverter.BuildRepeatableHeader());
flow.Blocks.AddRange(blocksSoFar);
pageCount = GetPageCount();
}
return flow;
}
我希望这对以后的人有所帮助!
如果我有一个 var flow = new FlowDocument()
并且我在它的 BlockCollection
中添加了几个块:
if (m_Blocks == null || m_Blocks.Count <= 0)
return flow;
flow.Blocks.AddRange(m_Blocks.ToList());
var paginatorSource = flow as IDocumentPaginatorSource;
paginatorSource.DocumentPaginator.ComputePageCount();
var pageCount = paginatorSource.DocumentPaginator.PageCount;
我可以确定这份文件有多少页。
问题
如果页数大于 1,我该如何找出文档的哪些块无法放在第一页上?我在 Block
class 上找不到任何可以帮助我确定这一点的内容。但是由于分页器可以ComputePageCount()
,我认为这是可能的。
我对我试图完成的事情采取了蛮力的方法。基本上,我需要在每一页的顶部重复一个 Paragraph
。我假设这不是最高效的方式,但它完成了工作:
protected FlowDocument RenderBody()
{
var flow = new FlowDocument
{
PageWidth = PaperSizeDPI.Width,
PageHeight = PaperSizeDPI.Height,
ColumnGap = 0,
ColumnWidth = PaperSizeDPI.Width,
PagePadding = new Thickness(MarginDPI.Left, MarginDPI.Top + HeaderHeightDPI, MarginDPI.Right, MarginDPI.Bottom + FooterHeightDPI)
};
if (m_Blocks == null || m_Blocks.Count <= 0)
return flow;
// Get page count before deciding to deal with repeat blocks.
// Adding blocks to the FlowDocument is required before invoking
// `DocumentPaginator.ComputePageCount()`.
flow.Blocks.AddRange(m_Blocks.ToList());
int GetPageCount()
{
var paginatorSource = (IDocumentPaginatorSource) flow;
paginatorSource.DocumentPaginator.ComputePageCount();
return paginatorSource.DocumentPaginator.PageCount;
}
// If there is only one page, no roll-over of headers necessary
if (GetPageCount() <= 1) return flow;
// If we don't have a header to repeat, we assume the report is correct already
if (PrintTemplateConverter.BuildRepeatableHeader == null) return flow;
// Build the FlowDocument, one block at a time, checking if the page count
// changes so that we can inject a repeatable header
flow.Blocks.Clear();
var pageCount = 1;
var blocks = m_Blocks.ToList();
for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++)
{
flow.Blocks.Add(blocks[blockIndex]);
if (GetPageCount() <= pageCount) continue;
// If this block moved us to a new page, inject repeatable header in its spot.
// `flow.Blocks.AddRange(...)` ignores duplicate blocks (by reference).
// This is why I go through the "pain" of making a whole new Header block
// instance.
var blocksSoFar = flow.Blocks.ToList();
flow.Blocks.Clear();
blocksSoFar.Insert(blockIndex, PrintTemplateConverter.BuildRepeatableHeader());
flow.Blocks.AddRange(blocksSoFar);
pageCount = GetPageCount();
}
return flow;
}
我希望这对以后的人有所帮助!