Vertical Text in a Migradoc table cell using PdfSharp

Creating the table
Creating a table in Migradoc is straightforward and simple to understand and implement. I am very impressed at how easy it is to use the Migradoc code.

I needed to go beyond the usual requirements with a recent project and have vertical text in certain cells in the pdf table which I was creating. I quickly realised that this was not possible with the Migradoc functionality. The way to achieve this is to use PdfSharp. This works at a lower level and allows much more granular control.

To start with I created the table using Migradoc as usual. Then I had a problem: the rotated text had to be added using PdfSharp, but the problem was how to tell PdfSharp the location of the cell where the particular text should be placed? This was solved by using the Tag property of the Cell object. It is possible to assign any object to the Tag, so I created the following object, named CellLocation:

private class CellLocation
     public Unit X;
     public Unit Y;
     public Unit Width;
     public string Text;

For each Cell I created an instance of the CellLocation object, populated the properties with the location of the particular cell and the text which should go in that cell and then attached this object as the Tag property of the Cell.

Retrieving the tagged cells
Once the MigraDoc document was finished I needed to find all the cells with a Tag. These were the cells which needed vertical text adding. First I had to render the MigraDoc as shown below:

DocumentRenderer docRenderer = new DocumentRenderer(migraDoc);

Then using the DocumentRenderer object I could inspect the document objects and retrieve all Cells with a Tag property which was not null. To do this I wrote the following simple method named GetTaggedCells:

private List<Cell> GetTaggedCells(DocumentRenderer docRenderer)
     List<Cell> taggedCells = new List<Cell>();
     DocumentObject[] docObjects = docRenderer.GetDocumentObjectsFromPage(1);
     if (docObjects != null && docObjects.Length > 0)
          for (int i = 0; i < docObjects.Length; i++)
                if (docObjects[i].GetType() == typeof(MigraDoc.DocumentObjectModel.Tables.Table))
                    MigraDoc.DocumentObjectModel.Tables.Table tbl = (MigraDoc.DocumentObjectModel.Tables.Table)docObjects[i];
                    for (int j = 0; j < tbl.Rows.Count; j++)
                         for (int k = 0; k < tbl.Columns.Count; k++)
                              Cell c = tbl[j, k];
                              if (c.Tag != null)
     return taggedCells;

In the table which I was creating I knew that the tagged cells were only on the first page of the pdf, which is why I simply pass a 1 into the GetDocumentObjectsFromPage method. But if this was not the case I could iterate over each page to get all tagged cells from all pages.

Adding the vertical text
The next task was to add the vertical text to each tagged cell. The MigraDoc must be rendered first before PdfSharp objects can be added to it. First I created a PdfDocumentRenderer:

PdfDocumentRenderer renderer = new PdfDocumentRenderer();

Then rendered the document:


renderer.Document = migraDoc;

Once the document is rendered then it is possible to add pdfSharp text to the document. The method which adds the vertical text is shown below:

private void AddVerticalText(PdfDocumentRenderer renderer, List<Cell> taggedCells)
     using (XGraphics gfx = XGraphics.FromPdfPage(renderer.PdfDocument.Pages[0]))
          XFont font = new XFont(PdfFont.Verdana, FontSizes.smallerFontSize, XFontStyle.Italic);
          CellLocation cellLocation;
          XGraphicsState state;
          foreach (var cell in taggedCells)
               cellLocation = (CellLocation)cell.Tag;
           XRect position = new XRect(cellLocation.X, cellLocation.Y, 1, cellLocation.Width);
               state = gfx.Save();
               gfx.RotateAtTransform(-90, new XPoint(cellLocation.X, cellLocation.Y));
               gfx.DrawString(cellLocation.Text, font, XBrushes.Black, position, CustomFormat.centreLeft);

The first job for the AddVerticalText method is to create an XGraphics object from the PdfDocument. Then the font for adding the text to the table is created, the PdfFont and FontSizes classes are simply static classes which I created as wrappers so that I did not have to use magic strings when setting the font properties. Then for each tagged cell the CellLocation object can be retrieved and inspected. This then makes adding the text easy because contained in this CellLocation object are all properties which are needed for adding the text. These properties are used to create an XRect which determines where the text will be placed on the document.

The next line saves the current state of the XGraphics object, which is then restored at the end of the method. This is important otherwise everytime in the loop that the gfx.RotateAtTransform method was called the text would be rotated another -90°, so in the second loop the text would be rotated -90° + -90° = -180° which is not what is wanted. By resetting the state at the end of each loop iteration it means we always call the gfx.RotateAtTransform method from a consistent starting state.

There are two methods which allow the rotation of a PdfSharp object, these are gfx.RotateTransform and gfx.RotateAtTransform. Rotate transform is simpler, it takes as an argument the required angle of rotation and always rotates around the central point of the pdfDocument. In this case I used RotateAtTransform because it gives more control, it allowed me to specify the point around which I wanted to rotate the transformed object. In the AddVerticalText method I used the coordinates from the CellLocation object as the point around which to rotate.

The final step is to add the string using the simple gfx.DrawString method. The string will now be added in the correct position and rotated by -90°.


In conclusion I would say that Migradoc is very simple to use and understand, but has limited functionality. The good thing is that PdfSharp can be combined with migradoc allowing much greater possibilities, but a solution combining the two is more complicated.

Wir verwenden Cookies zur Bereitstellung von Website-Funktionen und zu Analysezwecken. Mehr zum Datenschutz