MedicalBill project is an example of creating a “Medical Bill” document. The example shows how to create a complex document that includes tables, nested tables, and lists. Also it shows one of the ways to display forms for manual filling of a printed document.
The example source is available in repo.
Table of Content
- Prerequisites
- Purpose
- Description
- Output file
- Open the project in Visual Studio
- Run the sample application
- Source code structure
- The Program class
- The MedicalBillRunner class
- The MedicalBillBuilder class
- The MedicalBillFrontBuilder class
- The MedicalBillBackBuilder class
- The MedicalBillHeadBuilder class
- The MedicalBillBodyBuilder class
- The MedicalBillBottomBuilder class
- The MedicalBillBackTextBuilder class
- The MedicalBillBackClientInfoBuilder class
- Summary
-
Visual Studio 2017 or later is installed. To install a community version of Visual Studio, use the following link: https://visualstudio.microsoft.com/vs/community/. Please make sure that the way you are going to use Visual Studio is allowed by the community license. You may need to buy Standard or Professional Edition.
-
.NET Core Framework SDK 2.1 or later is installed. To install the framework, use the following link: https://dotnet.microsoft.com/download.
The example shows how to create a “Medical Bill” that is a complex two-page document. See Fig. 1.
The images below show the main blocks of the document in blue rectangles.
The first, or the front, page is the bill itself that consists of:
- A header
- A body (bill data table)
- A bottom part
The second, or the back, page is a form for the clients to fill in the information about themselves and their insurance agent. The page consists of:
- A text
- A form
Fig. 1
The example creates the Medical.pdf file in the output bin/(debug|release)/netcoreapp2.1 folder, unless specified otherwise in the command line.
There are two ways to open the project:
-
After installing Visual Studio, double-click the project file MedicalBill.csproj.
-
In Visual Studio, select File > Open > Project/Solution > MedicalBill.csproj.
There are two ways to run the sample application:
-
From Visual Studio by clicking F5.
-
From a command line: in the directory with MedicalBill.csproj, run the command:
dotnet run
You can get optional parameters of the command line using the command:
dotnet run -help
that shows the specification of the command line options:
Usage: dotnet run [fullPathToOutFile] [appToView]
Where: fullPathToOutFile - a path to the result file, 'MedicalBill.pdf' by default
appToView - the name of an application to view the file immediately after preparing, by default none app starts
The source code consists of several files (classes).
The reasons to write several classes are the following (in descending order of priority):
- Separation of responsibility. The class
Program
processes the command line options, any possible errors during the document creation, and displays the error report. The other classes do not process the command line options and errors. They are used to build the document itself. - Reduction of responsibility of each class. This helps to limit the size of code for each class, which improves understanding of the code example.
- Independent blocks of content. The document consists of several content blocks which are independent, so for each class you can select its own block.
Responsibility:
- Parse command line options.
You can process the command line options using the
PrepareParameters
that prepares theParameters
structure. - Display prompts to the user when one of the following options is present in the command line:
“?”
,“-h”
,“-help”
,“--h”
,“--help”
. It is processed byUsage
. - Build the document. It delegates the document building to the
MedicalBillRunner
class with the name of the resulting document file. - Run the application to demonstrate the resulting document if specified in the command line options.
Responsibility:
- Create an object of the
MedicalBillBuilder
class. - Initialize its properties with data of Medical Bill. The properties of the
MedicalBillBuilder
class have the default values, which are as specified in the following lines:
GuarantorNumber = "2nnnnn",
StatementDate = "07/10/2020",
CenterName = "Sample Medical Center",
CenterAddress = "123 Main Street\nAnywhere, NY 12345 - 6789",
CenterPhone = "123 - 456 - 7890",
CenterPatent = "Sample Patent",
FinServAddress = "Main Street 123",
FinServUrl = "http://www.ourwebsite.com/PatientFinancialServices.aspx"
These lines are not required to run the sample application. But these lines and subsequent lines must contain real information about the medical entity and data of account calculations in a real application.
- Build the document. It delegates the document building to the
MedicalBillBuilder
class using theCreateDocumentBuilder
method.
Responsibility:
- Save the properties with data of the medical entity in the
Params
structure. The classes for creating the document blocks will use this structure. - Save the calculation data in the
RowData
structure. The class for creating the calculation block will use this structure.
The method CreateDocumentBuilder
has the following responsibilities:
- Create an object of the
Gehtsoft.PDFFlow.Builder.DocumentBuilder
class. - Create an object of the
MedicalBillFrontBuilder
class and build the front page using theBuild
method of the created object. - Create an object of the
MedicalBillBackBuilder
class and build the back page using theBuild
method of the created object - Return the created object of the
Gehtsoft.PDFFlow.Builder.DocumentBuilder
class.
Responsibility:
- Create a page and set its parameters:
var sectionBuilder = documentBuilder.AddSection();
sectionBuilder
.SetOrientation(Orientation)
.SetMargins(Margins)
- Create the footer:
.AddFooterToOddPage(12, BuildFooter);
-
Create the first (front) page of the document. This is done by the
Build
method. It creates objects one by one and runs theBuild
methods for the following classes: -
MedicalBillHeadBuilder
-
MedicalBillBodyBuilder
-
MedicalBillBottomBuilder
The footer is created by the BuildFooter
method. The link to the method is passed to the Gehtsoft.PDFFlow.Builder.SectionBuilder.AddFooterToOddPage
method.
private void BuildFooter(RepeatingAreaBuilder footerBuilder)
{
var paragraphBuilder = footerBuilder.AddParagraph();
paragraphBuilder
.SetAlignment(HorizontalAlignment.Right)
.SetFont(FNT7)
.AddTextToParagraph("1nnnnn-XX-XXX-00");
}
Responsibility:
- Create the page and set its parameters:
var sectionBuilder = documentBuilder.AddSection();
sectionBuilder.SetOrientation(Orientation).SetMargins(Margins);
-
Create the second (back) page of the document. This is done by the
Build
method. It creates objects one by one and runs theBuild
methods for the following classes: -
MedicalBillBackTextBuilder
-
MedicalBillBackClientInfoBuilder
Responsibility:
- Create the header of the page. See Fig. 2.
Fig. 2
This is done by the BuildHead
method.
The header consists of three logos of the medical center in the top row and four blocks of text information in the bottom row. In this case, two right blocks of text information are located under one picture of the top row. So, this part of the document is implemented as a table consisting of two rows and four columns, where the last cell of the first row spans two columns.
Though the PDFFlow library supports adding headers using the methods Gehtsoft.PDFFlow.Builder.Gehtsoft.PDFFlow.SectionBuilder.AddHeader ...
, it does not give any advantage in this particular case. So, here we add the table directly to the section:
var tableBuilder = sectionBuilder.AddTable();
tableBuilder
.SetContentRowStyleFont(FNT9)
.SetBorder(Stroke.None)
.SetWidth(XUnit.FromPercent(100))
.AddColumnPercentToTable("", 33)
.AddColumnPercentToTable("", 33)
.AddColumnPercentToTable("", 17)
.AddColumnPercent("", 17);
Add cells with images to the first row of the table that is created as follows:
var rowBuilder = tableBuilder.AddRow();
To make the cell span two columns, use the TableCellBuilder.SetColSpan
method:
cellBuilder = rowBuilder.AddCell();
cellBuilder.SetColSpan(2).SetPadding(4, 0, 0, 0);
paragraphBuilder = cellBuilder.AddParagraph();
paragraphBuilder
.SetAlignment(HorizontalAlignment.Right)
.AddInlineImage(Path.Combine(ps.ImageDir, "Healthcare_2x.png"));
Add the cells with texts to the second row of the table:
rowBuilder = tableBuilder.AddRow();
cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetPadding(4)
.AddParagraphToCell(ps.CenterName + "\n" +
ps.CenterAddress);
cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetPadding(4)
.AddParagraphToCell("To Contact Us Call: " +
ps.CenterPhone +
"\n\nPhone representatives are available:\n8am to 8pm Monday - Thursday\nand 8am to 4:30pm Friday");
etc.
Responsibility:
- Create a table of the Medical Bill calculation block. See Fig. 3
Fig. 3
This is done by the BuildBody
method.
We implement this block as a table with five columns:
var tableBuilder = sectionBuilder.AddTable();
tableBuilder
.SetWidth(XUnit.FromPercent(100))
.SetBorder(Stroke.None)
.AddColumnPercentToTable("", 17)
.AddColumnPercentToTable("", 47)
.AddColumnPercentToTable("", 12)
.AddColumnPercentToTable("", 12)
.AddColumnPercent("", 12);
Set a blue background for the first row:
var rowBuilder = tableBuilder.AddRow();
rowBuilder
.SetBackColor(BLUE_COLOR)
This row contains the titles, for example:
var cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetPadding(4)
.AddParagraphToCell("Date of Service");
etc.
We configure the rows with calculation data in the foreach
loop:
foreach (RowData rowData in rowsData)
{
FontBuilder curFont = (--i) == 0 ? FNT10B : FNT10;
rowBuilder = tableBuilder.AddRow();
rowBuilder
.SetFont(curFont)
.SetBorder(BorderBuilder.New()
.SetRightWidth(0)
.SetTopWidth(0)
.SetLeftWidth(0)
.SetBottomWidth(0.5f)
.SetBottomStroke(Stroke.Solid)
);
cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetPadding(4)
.AddParagraphToCell(rowData.Date);
etc.
Responsibility:
- Create the bottom part of Medical Bill. See Fig. 4.
Fig. 4
This is done by the BuildBottom
method.
The bottom part of Medical Bill consists of the following blocks:
- Block before the Cut line
- Cut line
- Block after the Cut
These blocks are created in the following methods respectively:
BuildBeforeCut
BuildCut
BuildAfterCut
There are two columns before the Cut line in the document. So we implement the block before the Cut line as a one-row table with two columns of the same width.
- The left column with the text "MESSAGES: ..."
- The right column with the table "Current Balance ..."
private void BuildBeforeCut(SectionBuilder sectionBuilder)
{
var outerTableBuilder = sectionBuilder.AddTable();
outerTableBuilder
.SetWidth(XUnit.FromPercent(100)).SetBorder(Stroke.None)
.AddColumnPercentToTable("", 50)
.AddColumnPercent("", 50);
var rowBuilder = outerTableBuilder.AddRow();
var cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetFont(FNT9).SetPadding(0, 8, 0, 0)
.AddParagraphToCell("MESSAGES:\nWe have filed the medical claims with your insurance.They have\nindicated the balance is your responsibility. To pay your DIN online,\nplease visit www.ourwebsite.com.\n\nIf you have questions regarding your bill, or for payment arrangements, please call 123 - 456 - 78 or send an email inquiry to aboutmybill@ourwebsite.com");
cellBuilder = rowBuilder.AddCell();
cellBuilder.AddTable(FillBottomBalanceTable);
}
The FillBottomBalanceTable
method fills the "Current Balance ..." table. The link to the method is passed to the Gehtsoft.PDFFlow.Builder.TableCellBuilder.AddTable
method.
The FillBottomBalanceTable
method creates a table with two columns. Only the first row of the table is divided into two cells, the cells of the second and the third rows span two columns. This is done using the Gehtsoft.PDFFlow.Builder.TableCellBuilder.SetColSpan (2)
method.
private void FillBottomBalanceTable(TableBuilder tableBuilder)
{
tableBuilder
.SetWidth(XUnit.FromPercent(100)).SetBorder(Stroke.None)
.SetContentRowBorderWidth(0, 0, 0, 0)
.AddColumnPercentToTable("", 74)
.AddColumnPercent("", 26);
var rowBuilder = tableBuilder.AddRow();
var cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetPadding(4)
.SetBackColor(MedicalBillBuilder.BLUE_COLOR)
.SetFont(FNT9B_W)
.AddParagraphToCell("Current Balance");
cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetPadding(4)
.SetHorizontalAlignment(HorizontalAlignment.Right)
.SetBackColor(MedicalBillBuilder.BLUE_COLOR)
.SetFont(FNT9B_W)
.AddParagraphToCell(ps.Balance);
rowBuilder = tableBuilder.AddRow();
cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetColSpan(2)
.SetFont(FNT9B_B)
.AddParagraphToCell("This is your first notice for the visit above, which includes a list of itemized services rendered.");
rowBuilder = tableBuilder.AddRow();
cellBuilder = rowBuilder.AddCell();
cellBuilder
.SetColSpan(2)
.SetFont(FNT9)
.AddParagraphToCell("We offer a Financial Aid program for qualified applicants. For more information, please call 123-456-7890 or visit our website at www.ourwebsite.com for more information.");
}
}
The Cut line is a horizontal dashed line with the text above it.
private void BuildCut(SectionBuilder sectionBuilder)
{
var paragraphBuilder = sectionBuilder.AddParagraph();
paragraphBuilder
.SetAlignment(HorizontalAlignment.Center)
.SetFont(FNT9B).SetMarginTop(20)
.AddTextToParagraph("Please retain statement for your records");
sectionBuilder.AddLine(PageWidth, 0.5f, Stroke.Dashed);
}
The block after the Cut line is divided into two parts vertically.
- The information about two payment methods for the Medical Bill is located at the top.
- The information on how to send the Medical Bill document by mail is located at the bottom.
Accordingly, these parts are created by the BuildPayment
and BuildPostNet
methods.
The method creates a block with information about two payment methods for the Medical Bill:
- Payment by check. Information about the payment must be located on the left.
- Payment by credit card. Information about the payment is a form for the credit card data located on the right. This form is expected to be filled manually by the patient on the printed document.
For this, we create a table with one row and two columns:
private void BuildPayment(SectionBuilder sectionBuilder)
{
var tableBuilder = sectionBuilder.AddTable();
tableBuilder
.SetWidth(XUnit.FromPercent(100)).SetBorder(Stroke.None)
.AddColumnPercentToTable("", 50)
.AddColumnPercent("", 50);
var rowBuilder = tableBuilder.AddRow();
rowBuilder
.AddCellToRow(BuildCheck)
.AddCellToRow(BuilCard);
}
The BuildCheck
and BuildCard
methods create information about the two payment methods.
The method creates information about payment by check in the document.
To get a line before the phrase "MAKE CHECKS PAYABLE TO", we create the table with a visible bottom border in the first row.
The method creates the table and delegates its filling to the FillCheckTable
method.
The method fills the table with information for payment by check and sets the visible bottom border in the first row:
tableBuilder.SetWidth(PageWidth / 2 - 8).SetBorder(Stroke.None)
.AddColumnPercent("", 100);
var rowBuilder = tableBuilder.AddRow();
rowBuilder.SetBorder(BorderBuilder.New()
.SetRightWidth(0)
.SetTopWidth(0)
.SetLeftWidth(0)
.SetBottomWidth(0.5f)
.SetBottomStroke(Stroke.Solid)
);
The method creates information about payment by credit card. The information consists of:
- A form for choosing card types.
- A form with four rows for filling credit card details.
private void BuilCard(TableCellBuilder cellBuilder)
{
if (ps.CardNames.Count > 0)
{
AddCardHead(cellBuilder);
AddForm(cellBuilder, MedicalBillBuilder.CARD_TEXTS1,
new int[] { 50, 25, 25 });
AddForm(cellBuilder, MedicalBillBuilder.CARD_TEXTS2, new int[] { 50, 50 });
AddForm(cellBuilder, MedicalBillBuilder.CARD_TEXTS3,
new int[] { 33, 34, 33 }, false,
new string[] { ps.StatementDate, ps.GuarantorNumber, ps.Balance });
AddForm(cellBuilder, MedicalBillBuilder.CARD_TEXTS4,
new int[] { 50, 50 }, true);
}
}
The method creates the form for choosing card types.
It creates a paragraph with the phrase "* IF PAYING BY VISA, MASTERCARD, DISCOVER OR AMEX, FILL OUT BELOW *",
creates a table for checkboxes of each card type, and delegates filling of the table to the FillCardNames
method.
The method creates columns for CardNames
in the foreach
loop for each card type and then fills the cells with a checkbox and the name of the card type in another foreach
cycle.
private void FillCardNames(TableBuilder tableBuilder)
{
tableBuilder
.SetWidth(XUnit.FromPercent(100))
.SetBorder(Stroke.None)
.SetContentRowBorderWidth(0, 0, 0, 0);
foreach (string cardName in ps.CardNames)
{
tableBuilder
.AddColumnPercent("", 100 / ps.CardNames.Count);
};
var rowBuilder = tableBuilder.AddRow();
foreach (string cardName in ps.CardNames)
{
var cellBuilder = rowBuilder.AddCell().SetPadding(0, 0, 0, 8);
cellBuilder.AddParagraph("o").SetFont(FNTZ16);
cellBuilder.AddParagraph(cardName).SetFont(FNT10);
}
}
This method is defined in the FormBuilder
class and is used to create forms on both front and back pages.
The method accepts the following parameters:
cellBuilder
— an object of theGehtsoft.PDFFlow.Builder.TableCellBuilder
class of the table cell where you want to create the form.labels
— astring
array that must be printed as label of the field values.widths
— aint
array. Each element of the array determines the width of the column in % of the width of the nested table to display a label and a blank space for the field value.bottomBorder
— an optionalbool
flag value. It determines whether to print the bottom border of the row or not. The default value isfalse
.values
— an optionalstring
array of field values. If it is specified and not null, values are printed instead of the blank space. It is used to display the string "* Statement Date ...*"topBorderDepth
— an optional width,float
, of the top border. The default value is0.5
.bottomBorderDepth
— an optional width,float
, of the bottom border. The default value is0.5
.valueFontSize
— an optional font size,float
, for printing elements of thevalues
array. The default value is12
.
The method creates a nested table with one row of cells. Each cell contains:
- The field label
- A space to be filled by the client
The method creates information about sending Medical Bill by mail.
This information represents two identical blocks at the very bottom of the front page, starting with the strings "* SAMPLE GUARANTOR *" and "SAMPLE MEDICAL CENTER". We create it as a table with one row and two columns:
private void BuildPostNet(SectionBuilder sectionBuilder)
{
var tableBuilder = sectionBuilder.AddTable();
tableBuilder
.SetWidth(XUnit.FromPercent(100)).SetBorder(Stroke.None)
.AddColumnPercentToTable("", 50)
.AddColumnPercent("", 50);
var rowBuilder = tableBuilder.AddRow();
var cellBuilder = rowBuilder.AddCell().SetFont(FNT12);
var paragraphBuilder = cellBuilder.AddParagraph((ps.GuarantorName + "\n" +
ps.CenterAddress).ToUpper());
paragraphBuilder.SetMarginTop(10).SetMarginBottom(10);
cellBuilder.AddImageToCell(Path.Combine(ps.ImageDir,
"postnet1_2x.png"), new XSize(124, 11));
cellBuilder = rowBuilder.AddCell().SetFont(FNT12);
paragraphBuilder = cellBuilder.AddParagraph((ps.CenterName + "\n" +
ps.CenterAddress).ToUpper());
paragraphBuilder.SetMarginTop(10).SetMarginBottom(10);
cellBuilder.AddImageToCell(Path.Combine(ps.ImageDir,
"postnet2_2x.png"), new XSize(124, 11));
}
Responsibility:
- Create a block of text on the second (back) page of the document.
Fig. 5.
This is done by the AddTexts
method.
The method creates text information on the second (back) page of the document.
The information consists of several distinct blocks of text:
- The first block with the title which format differs from that of the other blocks "* The Sample Medical Center financial assistance policy plain language summary *".
- The second and fourth blocks with titles.
- The third block that includes a list and links.
Accordingly, the following methods are called to create these blocks:
AddFirstBlock
AddNextBlock
AddListBlock
AddNextBlock
As the third block includes links, when calling the listed methods, we pass the StringWithUrl
parameter defined in the MedicalBillBackTextBuilder.cs file.
Responsibility:
- Store information about the created text consisting of several elements, regardless of whether the elements are texts or links.
The class implements this responsibility by using one-dimensional array of objects of the Text
type defined in the MedicalBillBackTextBuilder.cs file.
internal class StringWithUrl
{
private Text[] texts;
public StringWithUrl(string v) : this(new Text[] { new Text(v) }) { }
public StringWithUrl(Text[] vs)
{
this.texts = vs;
}
public Text[] Texts
{
get { return texts; }
}
}
Responsibility:
- Store information about a text element with indication that this element is not a link. The feature of the class is a possibility to be extended with overriding the indication that the piece of the text is a link.
Using this indication, the calling code can determine how to work with this element, either as with a plain text or as with a link.
internal class Text
{
private string content;
public String Content
{
get { return content; }
}
public Text(string content)
{
this.content = content;
}
public virtual bool IsUrl()
{
return false;
}
public override string ToString()
{
return content;
}
}
It is an extension of the Text
class.
Responsibility:
- Store information about a text element with indication that this element is a link.
internal class Link : Text
{
private string href;
public String Title
{
get { return Content; }
}
public String Href
{
get { return href; }
}
public Link(string href) : base(href)
{
this.href = href;
}
public Link(string title, string href) : base(title)
{
this.href = href;
}
public override bool IsUrl()
{
return true;
}
}
The code of the AddFirstBlock
method is trivial because the data is already prepared in the AddTexts
method.
What is different in this method:
- A larger title margin than in the other blocks. We set it using the
Gehtsoft.PDFFlow.Builder.ParagraphBuilder.SetMarginBottom
method. - A larger font size for the title than in the other blocks. We set it using the
Gehtsoft.PDFFlow.Builder.ParagraphBuilder.SetFont
method.
private void AddFirstBlock(SectionBuilder sectionBuilder,
string title, StringWithUrl stringWithUrl)
{
var paragraphBuilder = sectionBuilder.AddParagraph();
paragraphBuilder.SetMarginBottom(17).SetFont(FNT20B).AddText(title);
paragraphBuilder = sectionBuilder.AddParagraph();
paragraphBuilder.SetFont(FNT11);
foreach (Text text in stringWithUrl.Texts)
{
paragraphBuilder.AddText(text.Content);
}
}
The method creates the title of the block. After the margin, it creates the text of the block. Creation of the title and of the text paragraphs for this block is the same as creation of the title and of the text paragraphs for the block with a list.
So, the method delegates all work to the following methods:
AddBlockTitle
methodAddBlockText
method
The method creates a paragraph for the title, sets its top and bottom margins, sets its font size, and adds the title text to the paragraph.
private void AddParagraphTitle(SectionBuilder sectionBuilder, string title)
{
var paragraphBuilder = sectionBuilder.AddParagraph();
paragraphBuilder
.SetMarginTop(12).SetMarginBottom(4).SetFont(FNT12B).AddText(title);
}
The code of the AddBlockText
is trivial because the data is already prepared in the AddTexts
method.
The method creates a paragraph, sets the top margin, and adds the text elements to the paragraph in the foreach
loop.
private void AddArticleText(SectionBuilder sectionBuilder,
StringWithUrl stringWithUrl, FontBuilder font, float topMargin = 0f)
{
var paragraphBuilder =
sectionBuilder.AddParagraph().SetFont(font).SetMarginTop(topMargin);
foreach (Text text in stringWithUrl.Texts)
{
paragraphBuilder
.AddText(text.Content);
}
}
This method creates:
- The title of the block.
- The first paragraph of the block after the margin.
- The list.
- The last paragraph of the block.
The method reduces all the work to the sequential calling of of the following methods:
AddBlockTitle
AddBlockText
AddBlockList
AddBlockText
During processing of objects of the StringWithUrl
array in a loop, the method adds the paragraphs to the section. For each paragraph it sets:
- The left margin using the
Gehtsoft.PDFFlow.Builder.ParagraphBuilder.SetMarginLeft
method. - The font using the
Gehtsoft.PDFFlow.Builder.ParagraphBuilder.SetFont
method. - The type of the list using the
Gehtsoft.PDFFlow.Builder.ParagraphBuilder.SetListBulleted
method. - All objects of the
StringWithUrl
type. It delegates determining whether the text is a plain text or a link to theAddTextOrUrl
method.
The method displays either a plain text or link. It delegates the work to:
- The
AddLink
method, if thetext
is a link. - The
AddText
method, if thetext
is not a link.
The method sets the style of the link display for the paragraph and adds the URL and the text of the link to the paragraph.
private void AddLink(ParagraphBuilder paragraphBuilder, Link link)
{
paragraphBuilder
.SetUrlStyle(
StyleBuilder.New()
.SetFontColor(Color.Blue)
.SetFontName("Helvetica")
.SetFontSize(11)
.SetFontUnderline(Stroke.Solid, Color.Blue))
.AddUrlToParagraph(link.Href, link.Title);
}
The method adds a text element to the paragraph.
private void AddText(ParagraphBuilder paragraphBuilder, Text text)
{
paragraphBuilder.AddTextToParagraph(text.Content);
}
Responsibility:
- Build a block of forms on the second (back) page of the document.
Fig. 6.
This is done by the Build
method.
The block of forms consists of the following parts:
- The text "If any of this following has changed since your last statement, please indicate…"
- A table of forms with client's information
To create these parts, the method calls the following methods:
AddInfoTitle
AddClientTable
The method creates a paragraph, sets the top margin, sets the font, and adds the text to the paragraph:
private void AddInfoTitle(SectionBuilder sectionBuilder)
{
var paragraphBuilder = sectionBuilder.AddParagraph();
paragraphBuilder
.SetMarginTop(17)
.SetFont(FNT9)
.AddTextToParagraph("If any of this following has changed since your last statement, please indicate…");
}
The block of forms at the bottom of the Medical Bill back page represents two columns with forms:
- The left one for client's information to be filled by the client.
- The right one for information about client's insurance agent to be filled by the client.
Accordingly, the method creates a table with two columns and one row which contains:
- The left cell with the client's information form in the nested table. The
FillAboutYouTable
method fills the nested table. - The right cell with the client's insurance agent information form in the nested table. The
FillInsuranceTable
method fills the nested table.
private void AddClientTable(SectionBuilder sectionBuilder)
{
var tableBuilder = sectionBuilder.AddTable();
tableBuilder
.SetWidth(XUnit.FromPercent(100)).SetBorder(Stroke.None)
.AddColumnPercentToTable("", 50).AddColumnPercent("", 50);
var rowBuilder = tableBuilder.AddRow();
rowBuilder.AddCell().AddTable(FillAboutYouTable);
rowBuilder.AddCell().AddTable(FillInsuranceTable);
}
The method fills the table with client's information form with the following:
- Seven forms of text data using the
AddForm
method described above. - One form for choosing one of several options delegating its creation to the
AddRadioButtons
method. - One line to display the "* Comments *:" label.
- One blank line for client's comment.
private void FillAboutYouTable(TableBuilder tableBuilder)
{
tableBuilder
.SetWidth(PageWidth / 2 - 8)
.SetBorder(Stroke.None)
.SetContentRowBorderWidth(0f, 0f, 0f, 0f)
.AddColumnPercent("", 100);
var rowBuilder = tableBuilder.AddRow();
AddTitle(rowBuilder, "About you:");
rowBuilder = tableBuilder.AddRow();
var cellBuilder = rowBuilder.AddCell();
AddForm(cellBuilder, MedicalBillBuilder.CLIENT_NAME_TEXT, new int[] { 100 });
AddForm(cellBuilder, MedicalBillBuilder.CLIENT_ADDRESS_TEXT, new int[] { 100 });
AddForm(cellBuilder, MedicalBillBuilder.ADDRESS_FIELDS_TEXT,
new int[] { 50, 25, 25 });
AddForm(cellBuilder, MedicalBillBuilder.CLIENT_PHONE_TEXT, new int[] { 100 });
AddRadioButtons(cellBuilder,
MedicalBillBuilder.MARITAL_STATUS_TEXT,
MedicalBillBuilder.MARITAL_STATUS_VALUES_TEXT,
new int[] { 14, 17, 17, 17, 17, 17 });
AddForm(cellBuilder, MedicalBillBuilder.EMPL_PHONE_TEXT, new int[] { 50, 50 });
AddForm(cellBuilder, MedicalBillBuilder.EMPL_ADDRESS_TEXT, new int[] { 100 });
AddForm(cellBuilder, MedicalBillBuilder.ADDRESS_FIELDS_TEXT,
new int[] { 50, 25, 25 }, true);
rowBuilder = tableBuilder.AddRow();
rowBuilder
.SetBorder(borderBuilder =>
{
borderBuilder
.SetRightWidth(0).SetTopWidth(0).SetLeftWidth(0).SetBottomWidth(2)
.SetBottomStroke(Stroke.Solid);
});
cellBuilder = rowBuilder.AddCell().SetPadding(0, 7, 0, 0);
cellBuilder.AddParagraph().SetFont(FNT11).AddText("Comments:");
AddRowForClient(tableBuilder);
}
The method is defined in the FormBuilder
class.
The method accepts the following parameters:
cellBuilder
– an object ofGehtsoft.PDFFlow.Builder.TableCellBuilder
class of the table cell where you want to create the form.label
– a commonstring
label for all choices.choices
– astring
array of values of each choice.widths
– anint
array. Each element of the array determines the width of the column in % of the width of the nested table to display the common label and a label of each choice. The number of elements in thewidths
array must be one more than the number of elements in thechoices
array.bottomBorder
– an optionalbool
flag value. It determines whether to print the bottom border of the row or not. The default value isfalse
.
The method creates a nested table with one row and several cells. The first cell of the row contains the common explanation of the selection purpose. The other cells contain checkboxes with selection options.
The method fills the table with client's insurance agent information form consisting of ten forms of text data using the AddForm
method described above
private void FillInsuranceTable(TableBuilder tableBuilder)
{
tableBuilder
.SetWidth(XUnit.FromPercent(100))
.SetBorder(Stroke.None)
.SetContentRowBorderWidth(0, 0, 0, 0)
.AddColumnPercent("", 100);
var rowBuilder = tableBuilder.AddRow();
AddTitle(rowBuilder, "About your insurance:");
rowBuilder = tableBuilder.AddRow();
var cellBuilder = rowBuilder.AddCell();
AddForm(cellBuilder, MedicalBillBuilder.ENS_PR_NAME_TEXT, new int[] { 60, 40 });
AddForm(cellBuilder, MedicalBillBuilder.ENS_PR_ADDRESS_TEXT,
new int[] { 60, 40 });
AddForm(cellBuilder, MedicalBillBuilder.ADDRESS_FIELDS_TEXT,
new int[] { 50, 25, 25 });
AddForm(cellBuilder, MedicalBillBuilder.ENS_POLICY_TEXT, new int[] { 50, 50 });
AddForm(cellBuilder, MedicalBillBuilder.ENS_RELATION_TEXT,
new int[] { 100 }, true,
new string[] { " " }, 0.5f, 2.0f, 13f);
AddForm(cellBuilder, MedicalBillBuilder.ENS_SC_NAME_TEXT, new int[] { 60, 40 });
AddForm(cellBuilder, MedicalBillBuilder.ENS_SC_ADDRESS_TEXT,
new int[] { 60, 40 });
AddForm(cellBuilder, MedicalBillBuilder.ADDRESS_FIELDS_TEXT,
new int[] { 50, 25, 25 });
AddForm(cellBuilder, MedicalBillBuilder.ENS_POLICY_TEXT, new int[] { 50, 50 });
AddForm(cellBuilder, MedicalBillBuilder.ENS_RELATION_TEXT,
new int[] { 100 }, true);
}
The above example showed how to create a complex document that includes tables, nested tables, images, and lists.
The resulting MedicalBill.pdf document can be accessed here.
The example source is available in repo.