Migradoc Header, Paragraph with multiple text alignments - c#

I use a Header in my Migradoc documents. Right now I just add a Paragraph to the Header but it doesnt really fit my needs as I want to have lets say two texts that have a different Alignment. For example:
Middle-ALigned.Text Right-Aligned-Text
second line second line
Before I used two textframes and added them to the section (not as Header). That worked somehow but cant be the right choice as I want to print the text on every page and thats what headers are for.
So the question is how do I align the two texts differently in one paragraph or how do I get two paragraphs to appear on the same height in the header.
I hope someone can help with that.
Cheers

Keep it Simple: Use a Tab Stop
The best way to do this is the same as you would do in most word processing tools: with a right-aligned tab-stop, placed on the right margin of the page, with the "left" text, being center-aligned. This is pretty straight forward, but I couldn't find the "full" solution anywhere, so here's what you need:
// Grab the current section, and other settings
var section = documentWrapper.CurrentSection;
var footer = section.Footers.Primary;
var reportMeta = documentWrapper.AdminReport.ReportMeta;
// Format, then add the report date to the footer
var footerDate = string.Format("{0:MM/dd/yyyy}", reportMeta.ReportDate);
var footerP = footer.AddParagraph(footerDate);
// Add "Page X of Y" on the next tab stop.
footerP.AddTab();
footerP.AddText("Page ");
footerP.AddPageField();
footerP.AddText(" of ");
footerP.AddNumPagesField();
// The tab stop will need to be on the right edge of the page, just inside the margin
// We need to figure out where that is
var tabStopPosition =
documentWrapper.CurrentPageWidth
- section.PageSetup.LeftMargin
- section.PageSetup.RightMargin;
// Clear all existing tab stops, and add our calculated tab stop, on the right
footerP.Format.TabStops.ClearAll();
footerP.Format.TabStops.AddTabStop(tabStopPosition, TabAlignment.Right);
The hardest part of this, is figuring out what your tab stop position should be. Because I'm boring and really like encapsulation, I dynamically calculate the tab stop position, based on the page width, less the horizontal page margins. However, getting the current page width wasn't as easy as I'd thought it'd be, because I'm using PageFormat to set the page dimensions.
Next Challenge: Getting Your Page Width, Dynamically
I really hate having tightly coupled code (think: fan-in and fan-out), so even though I know at this point in time what my page width is, even to the point of hard-coding it, I still want to hard code it in only a single place, then refer to that one place everywhere else.
I keep a custom "has-a"/wrapper class to keep this stuff encapsulated into; That's documentWrapper in my code here. Additionally, I don't expose any of the PDFSharp/MigraDoc types to the rest of my application, so I'm using ReportMeta as a way to communicate settings.
Now for some code. When I setup the section, I'm using the MigraDoc PageFormat to define the size of my page for the current section:
// The tab stop will need to be on the right edge of the page, just inside the margin
// We need to figure out where that is
var tabStopPosition =
documentWrapper.CurrentPageWidth
- section.PageSetup.LeftMargin
- section.PageSetup.RightMargin;
// Clear all existing tab stops, and add our calculated tab stop, on the right
footerP.Format.TabStops.ClearAll();
footerP.Format.TabStops.AddTabStop(tabStopPosition / 2, TabAlignment.Center);
footerP.Format.TabStops.AddTabStop(tabStopPosition, TabAlignment.Right);
footerP.Format.Alignment = ParagraphAlignment.Center;
What's really important here, is that I'm storing the CurrentPageWidth, this becomes really important when setting up our tab stops. The CurrentPageWidth property, is simply a MigraDoc Unit type. I am able to determine what this is by using MigraDoc's PageSetup.GetPageSize with my chosen PageFormat.
Results

You can add TextFrames to the header - then they will appear on every page.
Or use one paragraph as header. Use TabStops to position the text (as in Word there are left-aligned, center-aligned, and right-aligned TabStops. With TabStops you have to deal with the linebreaks like this:
(TabStop)Middle Text(TabStop)RightText(LineBreak)(TabStop)MT Second Line(TabStop)RT Second Line.
See also:
https://stackoverflow.com/a/29250830/1015447

Related

MigraDoc: Align text or a table at the bottom of the page above the footer

I am using MigraDoc to generate a PDF. I want to align some content to the bottom of the last page. This is boilerplate disclaimer information that my company always includes in these types of documents. The goal is to keep the content altogether and always have it appear just above the footer on the last page. If there isn't room on the last page of actual content to keep it together, there should be a page break and the boilerplate content will be on a page by itself.
I would like to do this without measuring the height of the content.
I get the impression that I can use TextFrame to assist with this in some way, but I can't find any documentation on it. The questions and examples I've found online refer to being able to "absolutely position" the TextFrame, but none of the examples seem to do that, exactly.
As a starting point, I am trying to position a paragraph of text in the way I described on an otherwise blank page. Here's my latest experiment:
static void AddBoilerPlate(Section section) {
var sectionWidth = PdfSharp.PageSizeConverter.ToSize(PageSize.Letter).Width - section.Document.DefaultPageSetup.LeftMargin.Point -
section.Document.DefaultPageSetup.RightMargin.Point;
section.AddPageBreak();
var frame = section.AddTextFrame();
frame.RelativeVertical = RelativeVertical.Page;
frame.Width = sectionWidth;
frame.Top = ShapePosition.Bottom;
frame.AddParagraph(DisclaimerText);
}
The text starts just above the footer (the blue line in this screenshot) and then runs over the footer:
Once I get a paragraph of text aligned, then I think I will be able to use a table with one column and one row instead, and then put all of my content in there.
Update: here is a screenshot showing my goal (faked using a page break and SpaceBefore):
Update: here are some related articles that don't quite get me where I'm trying to go:
Centering a table on a page using a TextFrame: http://forum.pdfsharp.net/viewtopic.php?p=753#p753
Seems to answer the same question, but doesn't provide information about how to absolutely position the TextFrame: http://forum.pdfsharp.com/viewtopic.php?f=2&t=587
Keeping table together on a page ("in one piece"). This will be useful once I figure out the issue with aligning relative to the bottom of the page: Keep table in one piece MigraDoc / PDFsharp
Update: Note that adding a height to the TextFrame does make the text align the way I need it to. It's not ideal, because I would rather not hard-code the height. But it does produce the desired effect:
static void AddBoilerPlate(Section section) {
var sectionWidth = PdfSharp.PageSizeConverter.ToSize(PageSize.Letter).Width - section.Document.DefaultPageSetup.LeftMargin.Point -
section.Document.DefaultPageSetup.RightMargin.Point;
section.AddPageBreak();
var frame = section.AddTextFrame();
frame.RelativeVertical = RelativeVertical.Page;
**frame.Height = new Unit(75, UnitType.Millimeter);**
frame.Width = sectionWidth;
frame.Top = ShapePosition.Bottom;
frame.AddParagraph(DisclaimerText);
}
Update: Note, though, that setting the TextFrame height doesn't resolve the ultimate issue. Content added before the boilerplate should push the boilerplate to the next page if there isn't enough space for it, and that's not happening.
Update: After trying it out myself (I've had the same Problem), add an invisible element with the Height you want to have just before the bottom element. In case the invisible Element doesn't fit it will seem that the page break occurred because of the bottom element.
Works like a charm.
(tip I added a border to both elements for testing so I was able to make sure the layout was proper)

PDFsharp MigraDoc set height of element

Is there a way to set fixed height of an element? Could be a table, row or section. This element is dynamically generated from database and it can have a variable number of rows. I need to do that, because the section below needs to be in a fixed position for print out. I am using WPF v1.31. I know it is not the latest, but it's an addition to a quite old application.
You can set the height of a Paragraph or a table Row.
I think you cannot set the height of a Table - but that will be the sum of the heights of all rows. Automatic page breaks will make things complicated if a table does not fit a single page.
A Section always starts on a new page.
TextFrame can be used to place text at a fixed position. Depending on the requirements, this could be simple or complicated.
You can prepare a document to let MigraDoc determine sizes and positions. Then you code can decide whether the items with the fixed position will be on the same page or on a new page.
Here is sample code that shows how to show the progress while creating a PDF:
http://forum.pdfsharp.net/viewtopic.php?f=8&t=3172
The same technique can be used to stitch several MigraDoc documents together to create a single PDF. If I understand your requirements correctly, this could be the way to go - without setting the height of any elements.

How to control the space between two labels during run time

Im using Visual Studio 2015 Community C#.
I have two labels on a Windows form suppose Label1 and Label2.
These labels will get filled up with user input namely first name and last name.
How to put even space between them so that during runtime the first name doesn't over lap the last name.
AbrahLincoln Abraham Lincoln
(Label1^)(^Label2) (^Label1) (^Label2)
For example: how to make this ^ INTO that >>>>>>>>>>>>^^
Because if I put space in the Form Design before runtime then for other names It will come like this: John(unnecessary space)Doe
Hope you have understood my problem.
Thanks for your time. :D
Controls are located in a form based on coordinates. Luckily for you these controls have properties that tell you the coordinate for the top, left, right, bottom of a control. So you could dynamically move the right label after setting the text.
Label2.Point = new Point(Label1.Right + 5, Y-coord);
An easier way would be to play about with the labels properties in the designer.
You could also try to anchor label1 to the right and label2 to the left. That way you should have a clean middle line, and as the text grows larger it pushes outwards on does not overlap inwards over each other.
However you need an object to anchor to and luckily the SplitContainer works excellent for this.
Also consider setting the autosize property to off and maxing the widths of the labels. Large enough for the string you expect.
Have you considered making it one label?
As in
theOnlyLabel.Text = $"{dataObject.FirstName} {dataObject.LastName}";
or, if you're using textboxes, something like
theOnlyLabel.Text = $"{txtFirstName.Text} {txtLastName.Text}";
Otherwise, I'm afraid, you'd have to realign these two labels every time your first or last name changes.

Drawing formatted text

I set up a draw rectangle to draw simple formatted text first aligned to the left as
*item 1
[1]Something
content
[2]Something else
<a> subsomething else
content
<b> another subsomething else
content
*item 2
The end.
and I would also like it to automatically create a new column (after checking for the longest string in the first column [drawn stuff on the left hand side]) to draw the rest into it.
In order to keep track of the paddings and itemized sections and subsections, I think of using a stack which I can push and pop the current and next positions needed to draw a text line each time I leave a content. Yet, I can't figure out how to jump back to a certain subsection position because stack doesn't offer an inline sub-scripting method.
Then I look into a hash-map (in C# I have tried Dictionary) to keep track of it and to access the value via specific key. For that I also use a external global variable to maintain the number of subsections the user may have entered and increase one each time a new subsection is created; and the float value is used to store the x-coordinate value for the drawstring to be done. This is complicated to me at least at present when I don't really have a nerve to go into it anymore. I can only receive false simulated outcomes.
So I am asking for an easier approach to tackle this problem, which I think is simple to many of you sure experiencing the same situation. I am desperately looking forward to seeing a short easy method to do this.
Draw formatted text using ..
..whatever works. I suggest a JLabel, which will render (simple) HTML/CSS formatted content.
See LabelRenderTest.java for an example.

PDF footer at the bottom using iTextSharp

I am trying to create a pdf document in c# using iTextSharp 5.0.6. I want to add header and footer to every page in OnStartPage and OnEndPage events respectively.
In case of footer there is a problem that the footer is created right where the page ends whereas I would like to be at the bottom of page.
Is there a way in iTextSharp to specify page height so that footer is always created at the bottom.
Thanks!
The page's height is always defined:
document.PageSize.Height // document.getPageSize().getHeight() in Java
Keep in mind that in PDF 0,0 is the lower left corner, and coordinates increase as you go right and UP.
Within a PdfPageEvent you need to use absolute coordinates. It sounds like you're either getting the current Y from the document, or Just Drawing Stuff at the current location. Don't do that.
Also, if you want to use the same exact footer on every page, you can draw everything into a PdfTemplate, then draw that template into the various pages on which you want it.
PdfTemplate footerTmpl = writer.getDirectContent().createTemplate( 0, 0, pageWidth, footerHeight );
footerTmpl.setFontAndSize( someFont, someSize );
footerTmpl.setTextMatrix( x, y );
footer.showText("blah");
// etc
Then in your PdfPageEvent, you can just add footerTempl at the bottom of your page:
writer.getDirectContent().addTemplateSimple( footerTmpl, 0, 0 );
Even if most of your footer is the same, you can use this technique to save memory, execution time, and file size.
Furthermore, if you don't want to mess with PdfContentByte drawing commands directly, you can avoid them to some extent via ColumnText. There are several SO questions tagged with iText or iTextSharp dealing with that class. Poke around, you'll find them.

Categories