I have a document where the first page has three sections. The top and bottom section are required to be on the first page. The center section has dynamic text. I am trying to find a way to get all the text that will fit in the center section, set it, and then add the remaining to the continuation second page (if required).
I have looked at this S.O. answer, but it seems that it wouldn't allow for the bottom section to be placed where it needs to go.
Here is what I am trying to do.
using (var workStream = new MemoryStream())
{
using (var pdfWriter = new PdfWriter(workStream))
{
using (var pdfDoc = new PdfDocument(pdfWriter))
{
var document = new Document(pdfDoc);
var pageSize = pdfDoc.GetDefaultPageSize();
var width = pageSize.GetWidth() - document.GetLeftMargin() - document.GetRightMargin();
// *** First Top Section ***
// ... variable creations removed for brevity ...
document.Add(paragraph);
document.Add(table);
// *** CENTER SECTION ***
// This section has a required float height of 325f
// *** Third Bottom Section ***
// ... table creation removed for brevity ...
document.Add(table);
// *** Create the second page if needed and add the overflow text ***
}
}
}
I found a solution that works for me. I am sure I could streamline it, but tempest fugit.
So here is how I got the text for section 1:
// Set the height of section 2 paragraph
var section2Height = 325f;
// Create a Text element with the desired text
var tempText = new Text(myDesiredText).SetFont(font);
// Create rectangle for the allowable space for section 2
var rectangle = new Rectangle(width, section2Height);
// Create PDFCanvas for the document
var pdfCanvas = new PdfCanvas(pdfDoc, 1);
// Create canvas space for adding the temp paragraph to for splitting
var canvas = new Canvas(pdfCanvas, rectangle);
// Set the temp text to a paragraph
var synopsis = new Paragraph(tempText).SetFixedLeading(12f);
// Get the paragraph renderer
var renderer = synopsis.CreateRendererSubTree();
// Set the paragraph renderer parent to the canvas renderer
renderer.SetParent(canvas.GetRenderer());
// Process the renderer and get the layout result
var result = renderer.Layout(new LayoutContext(new LayoutArea(1, rectangle)));
// If the renderer is full, get all text, otherwise get the text that fits
var page1 = result.GetStatus() == LayoutResult.FULL ? renderer : result.GetSplitRenderer();
// Create a new paragraph for Section 2 (SYNOPSIS)
var newParagraph = new Paragraph().SetFixedLeading(12f);
// Set the Paragraph height and width
newParagraph.SetWidth(width);
newParagraph.SetHeight(section2Height);
// Get the count of child renderers. Each one is a new line
var page1Count = page1.GetChildRenderers().Count;
// Instantiate a string for the last renderer text
var lastText = string.Empty;
// Iterate through the child renderers
for (var i = 0; i < page1Count; i++)
{
// Get the string value
var text = page1.GetChildRenderers()[i].ToString();
// Create a text element
var t1 = new Text(text + Environment.NewLine).SetFont(font);
// Add the Text element to the new paragraph
newParagraph.Add(t1);
// If this is the last line, store the text for later use
if (i + 1 == page1Count)
lastText = text;
}
// Get the index of the last string of text
index = myDesiredText.IndexOf(lastText);
// Get the remaining text base off the index and the last text string length
var page2 = myDesiredText.Substring(index + lastText.Length);
// If there is a string value...
if (!string.IsNullOrEmpty(page2))
{
// Create a list of line returns
var returnCharList = new List<string> { "\r", "\n" };
// Remove the beginning line returns
while (returnCharList.Contains(page2.Substring(0, 1)))
page2 = page2.Substring(2);
}
// Add the new paragraph to the section
document.Add(newParagraph);
This I how I set the rest of the text to the next page
// If there is a second page, build it out
if (!string.IsNullOrEmpty(page2))
{
// Create the text element
var page2Text = new Text(page2).SetFont(font);
// Get the workable height for the paragraph minus the space for the page footer
var page2Height = height - 30f;
// Create page 2 paragraph
var page2Paragraph = new Paragraph(page2Text).SetHeight(page2Height).SetFixedLeading(12f);
// Add the paragraph to the document
document.Add(page2Paragraph);
// Create new pager
pager = new Paragraph().AddTabStops(tabStops);
// Set the page string for page 2
pageBill = $"EBM - { RemoveBillSpaces(bsd.Bill.BillNumber)} - 2 of { totalPages }";
// Create the text element
pagerText = new Text(pageBill).SetFont(font).SetFontSize(fontSize_Small);
// Add the tabs and text for the pager
pager
.Add(new Tab())
.Add(new Tab())
.Add(pagerText);
// Add the pager to page 2
document.Add(pager);
}
Related
I try to create a PdfFlowDocument with header and footer. The page from 1 to 3 in Portrait mode. Page 4 is in Landscape and the rest again in portrait. Following my code code snippet:
PdfFlowDocument flowDocument = new PdfFlowDocument();
//flowDocument.HeadersFooters.EvenPagesHeader = docHeader;
//flowDocument.HeadersFooters.EvenPagesFooter = docFooter;
Xfinium.Pdf.Core.PdfFile sourceFile = new Core.PdfFile(File.OpenRead(""));
Xfinium.Pdf.Graphics.PdfPageContent[] pageContents = sourceFile.ExtractPageContent(0, sourceFile.PageCount - 1);
foreach (Xfinium.Pdf.Graphics.PdfPageContent content in pageContents)
{
//content can be Portrait or Landscape
//How can I rotate the orientation?
//How can I scale the page?
var flowContent = new Xfinium.Pdf.FlowDocument.PdfFlowFormXObjectContent(content);
flowDocument.AddContent(flowContent);
}
You handle the PageCreated event and set the page rotation to 90 for landscape based on your specific condition.
PdfFlowDocument flowDocument = new PdfFlowDocument();
flowDocument.PageCreated += FlowDocument_PageCreated;
//flowDocument.HeadersFooters.EvenPagesHeader = docHeader;
//flowDocument.HeadersFooters.EvenPagesFooter = docFooter;
Xfinium.Pdf.Core.PdfFile sourceFile = new Core.PdfFile(File.OpenRead(""));
Xfinium.Pdf.Graphics.PdfPageContent[] pageContents = sourceFile.ExtractPageContent(0, sourceFile.PageCount - 1);
foreach (Xfinium.Pdf.Graphics.PdfPageContent content in pageContents)
{
//content can be Portrait or Landscape
//How can I rotate the orientation?
//How can I scale the page?
var flowContent = new Xfinium.Pdf.FlowDocument.PdfFlowFormXObjectContent(content);
flowContent.SizeIsRelativeToAvailableSpace = true;
flowContent.FormXObjectHeight = 100;
flowContent.FormXObjectWidth = 100;
flowDocument.AddContent(flowContent);
}
private void FlowDocument_PageCreated(object sender, PdfFlowPageCreatedEventArgs e)
{
if (yourConditionHere)
{
e.Page.Rotation = 90;
}
}
Update: you can set the flowContent.SizeIsRelativeToAvailableSpace property to true and flowContent.FormXObjectWidth and flowContent.FormXObjectHeight properties to 100. This means the content object will be scaled to take all available space (100%). It will also take care of the white page problem.
Disclaimer: I work for the company that develops the XFINIUM.PDF library.
How do you set certain sections (what type of sections should I be using?) to landscape or portrait?
I am attempting to create sections that have the following section properties (see code below) and then set that section to landscape or portrait respectively. However, when I use this code and create break paragraphs the code generates a blank page in landscape.
public static SectionProperties PageOrientationPortrait()
{
SectionProperties sectionProperties2 = new SectionProperties();
PageSize pageSize = new PageSize()
{
Width = (UInt32Value)12240U,
Height = (UInt32Value)15840U,
Orient = PageOrientationValues.Portrait
};
PageMargin pageMargin = new PageMargin()
{
Top = 1440,
Right = (UInt32Value)1440U,
Bottom = 1440,
Left = (UInt32Value)1440U,
Header = (UInt32Value)720U,
Footer = (UInt32Value)720U,
Gutter = (UInt32Value)0U
};
Columns columns = new Columns() { Space = "720" };
DocGrid docGrid = new DocGrid() { LinePitch = 360 };
sectionProperties2.Append(pageSize, pageMargin, columns, docGrid);
return sectionProperties2;
}
public static SectionProperties PageOrientationLandScape()
{
SectionProperties sectionProperties = new SectionProperties();
PageSize pageSize = new PageSize()
{
Width = (UInt32Value)15840U,
Height = (UInt32Value)12240U,
Orient = PageOrientationValues.Landscape
};
PageMargin pageMargin = new PageMargin()
{
Top = 1440,
Right = (UInt32Value)1440U,
Bottom = 1440,
Left = (UInt32Value)1440U,
Header = (UInt32Value)720U,
Footer = (UInt32Value)720U,
Gutter = (UInt32Value)0U
};
Columns columns = new Columns() { Space = "720" };
DocGrid docGrid = new DocGrid() { LinePitch = 360 };
sectionProperties.Append(pageSize, pageMargin, columns, docGrid);
return sectionProperties;
}
public static Paragraph GenerateSectionBreakParagraph()
{
Paragraph paragraph232 = new Paragraph();
ParagraphProperties paragraphProperties220 = new ParagraphProperties();
SectionProperties sectionProperties1 = new SectionProperties();
SectionType sectionType1 = new SectionType() { Val = SectionMarkValues.NextPage };
sectionProperties1.Append(sectionType1);
paragraphProperties220.Append(sectionProperties1);
paragraph232.Append(paragraphProperties220);
return paragraph232;
}
When you wish to create a standard section in a WordProcessing document you first need to create an empty Paragraph element and an empty ParagraphProperties element. Then you can create a SectionProperties element with the desired properties as shown below:
/// <summary>
/// Will create a section properties
/// </summary>
/// <param name="orientation">The wanted orientation (landscape or portrai)</param>
/// <returns>A section properties element</returns>
public static SectionProperties CreateSectionProperties(PageOrientationValues orientation)
{
// create the section properties
SectionProperties properties = new SectionProperties();
// create the height and width
UInt32Value height = orientation == (PageOrientationValues.Portrait) ? 16839U : 11907U;
UInt32Value width = orientation != (PageOrientationValues.Portrait) ? 16839U : 11907U;
// create the page size and insert the wanted orientation
PageSize pageSize = new PageSize()
{
Width = width,
Height = height,
Code = (UInt16Value)9U,
// insert the orientation
Orient = orientation };
// create the page margin
PageMargin pageMargin = new PageMargin()
{
Top = 1417,
Right = (UInt32Value)1417U,
Bottom = 1417,
Left = (UInt32Value)1417U,
Header = (UInt32Value)708U,
Footer = (UInt32Value)708U,
Gutter = (UInt32Value)0U
};
Columns columns = new Columns() { Space = "720" };
DocGrid docGrid = new DocGrid() { LinePitch = 360 };
// appen the page size and margin
properties.Append(pageSize, pageMargin, columns, docGrid);
return properties;
}
When creating a section properties element with a certain orientation it is important that you adjust the height and the width of the PageSize element accordingly. Otherwise the pages within the section will be rendered incorrectly (if you render a landscape section with portrait height and width the section will appear to be a portrait).
When we are done creating the sectionproperties all we need to do is to append the section properties to the empty paragraphproperties and then append the paragraphproperties to the paragraph.
Using this function we can create a word document having different orientated sections with the console program below:
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
namespace ChangeDocVariable
{
class Program
{
static void Main(string[] args)
{
using(WordprocessingDocument doc = WordprocessingDocument.Create(#"path to document", WordprocessingDocumentType.Document))
{
// Create the maindocument part
MainDocumentPart maindDocomentPart = doc.AddMainDocumentPart();
// add the document
Document document = maindDocomentPart.Document = new Document();
// add the bdoy
Body body = document.Body = new Body();
// insert a set of sections
// To insert a section we need to add a paragraph
// which contains paragaph properties
// which holds the section properties
Paragraph firstSection = new Paragraph();
ParagraphProperties firstSectionProperties = new ParagraphProperties();
firstSectionProperties.Append(CreateSectionProperties(PageOrientationValues.Portrait));
firstSection.Append(firstSectionProperties);
Paragraph secondSection = new Paragraph();
ParagraphProperties secondSectionProperties = new ParagraphProperties();
secondSectionProperties.Append(CreateSectionProperties(PageOrientationValues.Landscape));
secondSection.Append(secondSectionProperties);
Paragraph thirdSection = new Paragraph();
ParagraphProperties thirdSectionProperties = new ParagraphProperties();
thirdSectionProperties.Append(CreateSectionProperties(PageOrientationValues.Portrait));
thirdSection.Append(thirdSectionProperties);
body.Append(firstSection, secondSection, thirdSection);
// for the last section we can directly add a section properties
body.Append(CreateSectionProperties(PageOrientationValues.Landscape));
}
}
/// <summary>
/// Will create a section properties
/// </summary>
/// <param name="orientation">The wanted orientation (landscape or portrai)</param>
/// <returns>A section properties element</returns>
public static SectionProperties CreateSectionProperties(PageOrientationValues orientation)
{
// create the section properties
SectionProperties properties = new SectionProperties();
// create the height and width
UInt32Value height = orientation == (PageOrientationValues.Portrait) ? 16839U : 11907U;
UInt32Value width = orientation != (PageOrientationValues.Portrait) ? 16839U : 11907U;
// create the page size and insert the wanted orientation
PageSize pageSize = new PageSize()
{
Width = width,
Height = height,
Code = (UInt16Value)9U,
// insert the orientation
Orient = orientation };
// create the page margin
PageMargin pageMargin = new PageMargin()
{
Top = 1417,
Right = (UInt32Value)1417U,
Bottom = 1417,
Left = (UInt32Value)1417U,
Header = (UInt32Value)708U,
Footer = (UInt32Value)708U,
Gutter = (UInt32Value)0U
};
Columns columns = new Columns() { Space = "720" };
DocGrid docGrid = new DocGrid() { LinePitch = 360 };
// appen the page size and margin
properties.Append(pageSize, pageMargin, columns, docGrid);
return properties;
}
}
}
This will create a document with four sections. The last SectionProrties can be directly added to the body of the document itself.
Is there a way to add a border around the table and hide the cell borders in MigraDoc?
The default width of the borders is 0 and borders are not visible. To enable borders, set a value greater than 0.
If table is your Table object, you could write table.Borders.Width = 0.5;
You can set borders for the table and for each cell. Cells inherit border properties from the table, the column, the row unless they are overwritten at a lower stage.
Also check the SetEdge method of the Table class.
Sample code discussed here:
http://www.pdfsharp.net/wiki/Invoice-sample.ashx
My test code:
private static void TabelWithBorderTest()
{
var document = new Document();
// Add a section to the document.
var section = document.AddSection();
Table table = section.AddTable();
table.Borders.Width = 0.25;
table.Rows.LeftIndent = 0;
// Before you can add a row, you must define the columns
Column column = table.AddColumn("7cm");
column.Format.Alignment = ParagraphAlignment.Left;
Row row = table.AddRow();
row.Cells[0].AddParagraph("Text in table");
// Create a renderer for the MigraDoc document.
var pdfRenderer = new PdfDocumentRenderer(false) { Document = document };
// Associate the MigraDoc document with a renderer.
// Layout and render document to PDF.
pdfRenderer.RenderDocument();
// Save the document...
const string filename = "TableTest.pdf";
pdfRenderer.PdfDocument.Save(filename);
// ...and start a viewer.
Process.Start(filename);
}
I managed to get this down by setting each row borders visibility as false;
var document = new Document();
var page = document.AddSection();
Table table = page.AddTable();
table.Borders.Visible = true;
Column col = table.AddColumn("3cm");
col = table.AddColumn("10cm");
col = table.AddColumn("3cm");
col.Format.Alignment = ParagraphAlignment.Left;
Row row = table.AddRow();
Paragraph p = row.Cells[0].AddParagraph();
p.AddFormattedText("Top header row");
row.Cells[0].MergeRight = 2;
// then set it in visible as false like this, you can do top, left and right as well
row.Cells[0].Borders.Bottom.Visible = false;
Doesn't look nice but if anyone has a better solution do post it up
First off, I'm not sure if I phrased the title correctly. There are UserControls which are added via a ViewModel and I find them by searching the VisualTree and add them to a ObservableCollection<Grid>. What I would like to do is Print each instance of the UserControl that I retrieve from the VisualTree into a FixedDocument but with each UserControl being on a single page until it fills that page and moves on to the next page.
Here is the code for my current Print Button Click Event:
private async void btnPrint_Click(object sender, RoutedEventArgs e)
{
try
{
if (tabMain.Items.Count > 0)
{
tab = new TabLayout();
tab.Payslip = new ObservableCollection<Grid>();
foreach (var grid in FindVisualChildren<Grid>(this))
{
if (grid.Name == "pdfFile")
{
tab.Payslip.Add(grid);
}
}
FrameworkElement toPrint = new FrameworkElement();
PrintDialog printDialog = new PrintDialog();
PrintCapabilities capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
Size pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
Size visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
FixedDocument fixedDoc = new FixedDocument();
StackPanel panel = new StackPanel(); //was trying to stack them in a stackpanel first but it threw an exception about same instance of usercontrol blah blah...
foreach (var doc in tab.Payslip.ToList())
{
double yOffset = 0;
doc.Measure((new Size(double.PositiveInfinity, double.PositiveInfinity)));
doc.Arrange(new Rect(new Point(0, 0), doc.DesiredSize));
Size size = doc.DesiredSize;
while (yOffset < size.Height)
{
VisualBrush vb = new VisualBrush(doc);
vb.Stretch = Stretch.None;
vb.AlignmentX = AlignmentX.Left;
vb.AlignmentY = AlignmentY.Top;
vb.ViewboxUnits = BrushMappingMode.Absolute;
vb.TileMode = TileMode.None;
vb.Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height);
FixedPage page = new FixedPage();
PageContent pageContent = new PageContent();
((IAddChild)pageContent).AddChild(page);
fixedDoc.Pages.Add(pageContent);
page.Width = fixedDoc.DocumentPaginator.PageSize.Width;
page.Height = fixedDoc.DocumentPaginator.PageSize.Height;
Canvas canvas = new Canvas();
FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
canvas.Width = visibleSize.Width;
canvas.Height = visibleSize.Height;
canvas.Background = vb;
page.Children.Add(canvas);
yOffset += visibleSize.Height;
}
}
//printDialog.PrintDocument(fixedDoc.DocumentPaginator, "");
ShowPrintPreview(fixedDoc);
}
}
catch(Exception ex)
{
var exceptionDialog = new MessageDialog
{
Message = { Text = ex.ToString() }
};
await DialogHost.Show(exceptionDialog, "RootDialog");
}
}
This is how it looks when I try printing three Tabs (UserControls are hosted in Tabs):
As you can see here it prints three separate pages
I want all three on one page and if I print 10 tabs, then it should fill the first page and go on to the next page.
The last time I asked a similar question I was questioned on whether I wrote the code. Bits and pieces of this code came from similar FixedDocument questions on StackOverflow but it has been edited to the point where it actually works for me. So yes I know that the FixedPage reference inside the foreach is whats causing the creation of the three separate pages and I do understand the code.
Summary:
What I want to know is how to get the UserControls from each Tab, onto a single page until its full, without getting the "Specified element is already the logical child of another element. Disconnect it first." error.
I ended up using ItemsControl to hold my ObservableCollection of Controls as a list and print from the ItemsControl using this XpsDocumentWriter method.
public void PrintItemsTo(ItemsControl ic, String jobName)
{
PrintDialog dlg = new PrintDialog();
dlg.UserPageRangeEnabled = true;
if (dlg.ShowDialog().GetValueOrDefault())
{
PageRange range = dlg.PageRange;
// range check - user selection starts from 1
if (range.PageTo > ic.Items.Count)
range.PageTo = ic.Items.Count;
dlg.PrintQueue.CurrentJobSettings.Description = jobName;
XpsDocumentWriter xdw = PrintQueue.CreateXpsDocumentWriter(dlg.PrintQueue);
if (dlg.UserPageRangeEnabled == false || range.PageTo < range.PageFrom)
WriteAllItems(ic, xdw);
else
WriteSelectedItems(ic, xdw, range);
}
}
private void WriteAllItems(ItemsControl ic, XpsDocumentWriter xdw)
{
PageRange range = new PageRange(1, ic.Items.Count);
WriteSelectedItems(ic, xdw, range);
}
private void WriteSelectedItems(ItemsControl ic, XpsDocumentWriter xdw, PageRange range)
{
IItemContainerGenerator generator = ic.ItemContainerGenerator;
// write visuals using a batch operation
VisualsToXpsDocument collator = (VisualsToXpsDocument)xdw.CreateVisualsCollator();
collator.BeginBatchWrite();
if (WritePageRange(collator, generator, range))
collator.EndBatchWrite();
}
private bool WritePageRange(VisualsToXpsDocument collator, IItemContainerGenerator generator, PageRange range)
{
// Get the generator position of the first data item
// PageRange reflects user's selection starts from 1
GeneratorPosition startPos = generator.GeneratorPositionFromIndex(range.PageFrom - 1);
// If PageFrom > PageTo, print in reverse order
// UPDATE: never occurs; PrintDialog always 'normalises' the PageRange
GeneratorDirection direction = (range.PageFrom <= range.PageTo) ? GeneratorDirection.Forward : GeneratorDirection.Backward;
using (generator.StartAt(startPos, direction, true))
{
for (int numPages = Math.Abs(range.PageTo - range.PageFrom) + 1; numPages > 0; --numPages)
{
bool newlyRealized;
// Get or create the child
UIElement next = generator.GenerateNext(out newlyRealized) as UIElement;
if (newlyRealized)
{
generator.PrepareItemContainer(next);
}
// The collator doesn't like ContentPresenters and produces blank pages
// for pages 2-n. Finding the child of the ContentPresenter and writing
// that solves seems to solve the problem
if (next is ContentPresenter)
{
ContentPresenter presenter = (ContentPresenter)next;
presenter.UpdateLayout();
presenter.ApplyTemplate(); // not sure if this is necessary
DependencyObject child = VisualTreeHelper.GetChild(presenter, 0);
if (child is UIElement)
next = (UIElement)child;
}
try
{
collator.Write(next);
}
catch
{
// if user prints to Microsoft XPS Document Writer
// and cancels the SaveAs dialog, we get an exception.
return false;
}
}
}
return true;
}
PrintItemsTo(), displays a PrintDialog to print to any printer while WriteAllItems displays a Dialog to save as PDF.
My travails in trying to use both "generic" textbox-type controls and multiline ones (that have greater height/are taller) are detailed here
What can I do to use an iTextSharp Textfield (or its basic equivalent), with the only difference being that it is multiline (covers more vertical space on the form)?
This gives me back the "textboxes" that I want:
public class DynamicTextbox : IPdfPCellEvent
{
private string fieldname;
public DynamicTextbox(string name)
{
fieldname = name;
}
public void CellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases)
{
PdfWriter writer = canvases[0].PdfWriter;
iTextSharp.text.pdf.TextField text = new iTextSharp.text.pdf.TextField(writer, rectangle, fieldname);
//Microsoft.SharePoint.WebControls.TextField text = new TextField(writer, rectangle, fieldname);
PdfFormField field = text.GetTextField();
writer.AddAnnotation(field);
}
}
...but this derivation on that theme, attempting to generate a "taller" version of that, fails:
public class DynamicMultilineTextbox : IPdfPCellEvent
{
private string fieldname;
public DynamicMultilineTextbox(string name)
{
fieldname = name;
}
public void CellLayout(PdfPCell cell, Rectangle rectangle, PdfContentByte[] canvases)
{
Rectangle wreckTangle = new Rectangle(30, 60); // changed from 300, 600
PdfWriter writer = canvases[0].PdfWriter;
iTextSharp.text.pdf.TextField text = new iTextSharp.text.pdf.TextField(writer, wreckTangle, fieldname);
PdfFormField field = text.GetTextField();
writer.AddAnnotation(field);
}
}
The failure is in that, if I use a rectangle of 300, 600, it produces a monstrous Blob that threatens to cover this county and the next. If I use 30,60 it shows nothing - and in either case, where I expect the "tall textboxes" to be just sports horizontal lines, like so:
Am I barking up the wrong tree? How is what I'm trying to accomplish (add multline controls to a PDF file) possible?
UPDATE
Awedly enough, if I just give the textboxes any old literal string, it works:
The code for that is this:
PdfPCell cellNotesMultilineTextBox = new PdfPCell()
{
CellEvent = new DynamicTextbox("multilineTextboxNotes"),
Phrase = new Phrase("I will be darned like a sock", timesRoman9Font)
};
tblMultilineTextAreas.AddCell(cellNotesMultilineTextBox);
Phrase blankPhrase = new Phrase();
PdfPCell blankCell = new PdfPCell(blankPhrase);
blankCell.BorderWidth = 0;
tblMultilineTextAreas.AddCell(blankCell);
PdfPCell cellAccountCodesMultilineTextBox = new PdfPCell()
{
CellEvent = new DynamicTextbox("multilineTextboxAccountCodes"),
Phrase = new Phrase("I will be dammed like a reservoir", timesRoman9Font)
};
tblMultilineTextAreas.AddCell(cellAccountCodesMultilineTextBox);
Phrase blankPhrase2 = new Phrase();
PdfPCell blankCell2 = new PdfPCell(blankPhrase2);
blankCell2.BorderWidth = 0;
tblMultilineTextAreas.AddCell(blankCell2);
PdfPCell cell1099TaxReportableMultilineTextBox = new PdfPCell()
{
CellEvent = new DynamicTextbox("multilineTextbox1099TaxReportable"),
Phrase = new Phrase("I will be the uncle of a monkey", timesRoman9Font)
};
tblMultilineTextAreas.AddCell(cell1099TaxReportableMultilineTextBox);
doc.Add(tblMultilineTextAreas);
...but, of couse, that won't do. Accessing the InnerText of the HtmlTextArea controls on the WebPart, which are coded up like this:
HtmlTextArea txtarNotes = null;
. . .
txtarNotes = new HtmlTextArea();
txtarNotes.Cols = 40;
txtarNotes.Rows = 6;
...results in the "no-usable-height" controls as shown in the first scream shot.
And referencing a Textbox control on the WebPart (instead of a HtmlTextArea control) also results in the "horizontal lines" only. Is this a result of the value being empty (if the string is empty, no space is allotted for it)?
UPDATE 2
Apparently so, because doing this:
String s = txtarAccountCodes.InnerText;
if (String.IsNullOrEmpty(s))
{
s = " ";
}
PdfPCell cellNotesMultilineTextBox = new PdfPCell()
{
CellEvent = new DynamicTextbox("multilineTextboxNotes"),
Phrase = new Phrase(s, timesRoman9Font)
};
...works (the textboxes, albeit empty, display in their expected sizes/heights).
UPDATE 3
It dawned on me that maybe I needed to incrase the size of the cell first (prior to worrying about the size of the "multiline textbox" within the cell). SO I changed the code to this:
PdfPCell cellNotesMultilineTextBox = new PdfPCell()
{
CellEvent = new DynamicTextbox("multilineTextboxNotes"),
Phrase = new Phrase(notes, timesRoman9Font),
MinimumHeight = 120,
NoWrap = false,
Rowspan = 40
};
(the MinimumHeight, NoWrap, and Rowspan values are new). This, though, does not solve the "won't wrap" problem that I've got - the area is large enough, but I can only enter one line of text; the more text I enter, the smaller the text gets:
Is there a solution to this conundrum? It seems what I need is a way to tell the "Textbox" being created to "be multiline" (increase its height, or "rowcount", or make it wrappable, as in the case with the Cell itself above) but there seems to be no such capability "on the surface" - is there something beneath the covers that exposes this functionality?
I have a similar requirement and achieved with the following code. Let me know if I misunderstood something or your requirement is something else.
TextField tf = new TextField(stamper.Writer, new Rectangle(llx, lly, urx, ury), property.ControlId)
{
Options = TextField.MULTILINE | TextField.READ_ONLY,
FontSize = 11
};
Screenshot from Adobe Acrobat: