The reason was the bookmarks are collected in the fieldinfos before the table is really rendered, so the logic doesn't know the exact page if there is an automatic page break. So i have changed the preparation of the fieldinfos and add the bookmarks at rendering. After the content rendering i add links which can't be rendered.
I don't know if my solution is universal insertable, but it works fine:
1st change in MigraDoc.Rendering.ParagraphRenderer.FormatBookmarkField:
Code:
FormatResult FormatBookmarkField(BookmarkField bookmarkField)
{
if (!bookmarkField.Name.Contains("ac_"))
this.fieldInfos.AddBookmark(bookmarkField.Name);
return FormatResult.Ignore;
}
I have all bookmarks in the 2nd table with the prefix 'ac_' so i can do it this way. Better solution would be if parent is table, but didn't find a field how i can validate this. So I did it like this.
Next change is also in the ParagraphRenderer I have change following Method and the call of it:
Code:
void RenderBookmarkField(BookmarkField bookmarkField)
{
this.FieldInfos.AddBookmark(bookmarkField.Name);
RenderUnderline(0, false);
}
Change is the method needs the bookmark field and I have added the bookmark at this position. Also I have added to the property the get part.
If the bookmark is already in the fieldinfos it would get updated.
So now the links from the bottom to the top are working. But the Links from the top to the bottom are not there, because the bookmark couldn't be found.
The solution:
Change the EndHyperlink:
Code:
void EndHyperlink(Hyperlink hyperlink, XUnit right, XUnit bottom)
{
this.hyperlinkRect.Width = right - this.hyperlinkRect.X;
this.hyperlinkRect.Height = bottom - this.hyperlinkRect.Y;
PdfPage page = this.gfx.PdfPage;
if (page != null)
{
XRect rect = this.gfx.Transformer.WorldToDefaultPage(this.hyperlinkRect);
switch (hyperlink.Type)
{
case HyperlinkType.Local:
int pageRef = this.fieldInfos.GetPhysicalPageNumber(hyperlink.Name);
if (pageRef > 0)
page.AddDocumentLink(new PdfRectangle(rect), pageRef);
else
{
fieldInfos.AddBookmarkToRenderLater(hyperlink.Name, new PdfRectangle(rect));
}
break;
case HyperlinkType.Web:
page.AddWebLink(new PdfRectangle(rect), hyperlink.Name);
break;
case HyperlinkType.File:
page.AddFileLink(new PdfRectangle(rect), hyperlink.Name);
break;
}
this.hyperlinkRect = new XRect();
}
}
For this I have added an Dictionary in the fieldinfos:
Code:
Dictionary<string, PdfRectangle> bookmarksToRenderLater
internal void AddBookmarkToRenderLater(string name, PdfRectangle rect)
{
if (this.bookmarksToRenderLater == null)
this.bookmarksToRenderLater = new Dictionary<string, PdfRectangle>();
if (this.bookmarksToRenderLater.ContainsKey(name))
this.bookmarksToRenderLater.Remove(name);
if (rect != null)
this.bookmarksToRenderLater.Add(name, rect);
}
The name bookmark is a bit disappointing, because it is more the links then the bookmarks...
Now I have in the fieldinfos the links incl. bookmarks with the links which couldn't be rendered.
So I have add a few lines to the PdfDocumentRenderer.RenderPages
Code:
public void RenderPages(int startPage, int endPage)
{
if (startPage < 1)
throw new ArgumentOutOfRangeException("startPage");
if (endPage > this.documentRenderer.FormattedDocument.PageCount)
throw new ArgumentOutOfRangeException("endPage");
if (this.documentRenderer == null)
PrepareDocumentRenderer();
if (this.pdfDocument == null)
this.pdfDocument = CreatePdfDocument();
this.documentRenderer.printDate = DateTime.Now;
for (int pageNr = startPage; pageNr <= endPage; ++pageNr)
{
PdfPage pdfPage = this.pdfDocument.AddPage();
PageInfo pageInfo = this.documentRenderer.FormattedDocument.GetPageInfo(pageNr);
pdfPage.Width = pageInfo.Width;
pdfPage.Height = pageInfo.Height;
pdfPage.Orientation = pageInfo.Orientation;
using (XGraphics gfx = XGraphics.FromPdfPage(pdfPage))
{
gfx.MUH = this.unicode ? PdfFontEncoding.Unicode : PdfFontEncoding.WinAnsi;
gfx.MFEH = this.fontEmbedding;
this.documentRenderer.RenderPage(gfx, pageNr);
}
}
//MIH: Add links of the bookmarks after the completion of the document because http://forum.pdfsharp.net/viewtopic.php?f=2&t=1080
FieldInfos fieldInfo = null;
PdfPage page = null;
for (int pageNr = startPage; pageNr <= endPage; ++pageNr)
{
fieldInfo = this.documentRenderer.FormattedDocument.GetFieldInfos(pageNr);
if (fieldInfo.bookmarksToRenderLater != null)
{
using (XGraphics gfx = XGraphics.FromPdfPage(this.pdfDocument.Pages[pageNr - 1]))
{
page = gfx.PdfPage;
foreach (KeyValuePair<string, PdfRectangle> entry in fieldInfo.bookmarksToRenderLater)
if (fieldInfo.GetPhysicalPageNumber(entry.Key) > 0)
page.AddDocumentLink(entry.Value, fieldInfo.GetPhysicalPageNumber(entry.Key));
}
}
}
}
I hope I got all changes, but if I miss anything it won't be a big thing.
Just ask if there are any things which need more infomation....