C# MigraDoc margins incorrect size? - c#

Left and top margins are not 7mm. Why?
Document document = new Document();
Section sec = document.AddSection();
sec.PageSetup.PageWidth = Unit.FromMillimeter(210);
sec.PageSetup.PageHeight = Unit.FromMillimeter(297);
sec.PageSetup.LeftMargin = Unit.FromMillimeter(7);
sec.PageSetup.TopMargin = Unit.FromMillimeter(7);
sec.PageSetup.RightMargin = Unit.FromMillimeter(7);
sec.PageSetup.BottomMargin = Unit.FromMillimeter(7);
Table table = sec.AddTable();
table.AddColumn(Unit.FromMillimeter(196));
Row row = table.AddRow();
row.HeightRule = RowHeightRule.Exactly;
row.Height = Unit.FromPoint(70);
row.Cells[0].AddParagraph("TABLE TEXT");
Color blackColor = new Color(0, 0, 0);
row.Shading.Color = blackColor;
In result PDF, left margin is 5.95mm and top margin is 6.86mm.
image of result PDF

You should set table.Rows.LeftIndent to 0. This will increase the left margin.
By default, text in the table is exactly at 7 mm (in your case) - thus the left margin is a bit smaller if you measure from the edge of the table.
Setting table.Rows.LeftIndent to 0 will bring the edge of the table to 7 mm.
Maybe you have to set the width of the table border to 0 to get exactly 7 mm. The border is drawn on both sides, so half of the border width will be subtracted from top and left margins.

Related

C# MSChart - charts area limits

I have one Chart and three ChartArea that are aligned in view, zoom, cursor:
this is my related previous post. All things works well except that the three ChartArea are not aligned at the beginning. Following an image of the problem:
I think it depends from the digit's number of Y values axis. From some research I try the following configuration:
// selezione e zoom
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.Interval = 1;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserEnabled = true;
dlChart.ChartAreas[VOLTAGE_AREA].CursorX.IsUserSelectionEnabled = true;
// generale
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.LabelStyle.Format = "dd/MM/yy - HH:mm:ss.fff";
dlChart.ChartAreas[VOLTAGE_AREA].AxisX.ScaleView.Zoomable = true;
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
In witch the last row:
dlChart.ChartAreas[VOLTAGE_AREA].AxisY.LabelStyle.Format = "D5";
should specifies always five digits. This mitigate in some way the problem but it doesn't desappers. Furthermore with this row the program starts to throws very lots exceptions of form below any time I scroll the graph:
Generate exception: 'System.FormatException' in mscorlib.dll
Does anyone knows the solution for this problem? Thanks in advance.
You may want to take control of the size of the InnerPlotPosition.
(But Baddack's solution is simpler and more flexible!)
Here is an example:
After setting up a Chart with three CharAreas, setting Minima and Maxima as well as adding one DataPoint to each we get this :
Your issue is showing clearly.
After setting the InnerPlotPosition to a fixed percentage it looks like this:
Here is how to set the InnerPlotPosition size:
ca1.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca2.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
ca3.InnerPlotPosition = new ElementPosition(10, 5, 80, 90);
Note that both ChartArea.Position and ChartArea.InnerPlotPosition are called 'Position' but really are areas of percentages referring to the respective containers!
So my example has a Left distance of 10%, a Top space of 5% and Width of 80% and Height of 90%. Which leaves 10% space at the Bottom and 5% at the Right. Note: All are referring to the ChartAreas not the ClientArea of the Chart! (Which are still at Auto, which maximizes the size.)
This was my initial setup:
ChartArea ca1 = chart.ChartAreas[0];
ChartArea ca2 = chart.ChartAreas[1];
ChartArea ca3 = chart.ChartAreas[2];
Series s1 = chart.Series[0];
Series s2 = chart.Series.Add("Series2");
Series s3 = chart.Series.Add("Series3");
s2.ChartArea = ca2.Name;
s3.ChartArea = ca3.Name;
s1.Points.AddXY(1, 7);
s2.Points.AddXY(1, 777);
s3.Points.AddXY(1, Math.PI);
Have you tried using the chart area alignment options? I would try something like:
//define inner plot position of the chart areas
dlChart.ChartAreas[0].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[1].InnerPlotPosition.Auto = true;
dlChart.ChartAreas[2].InnerPlotPosition.Auto = true;
//set our second chart area's alignments to match our first chart area
dlChart.ChartAreas[1].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[1].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[1].AlignWithChartArea = dlChart.ChartAreas[0].Name;
//set our third chart area's alignments to match our first chart area
dlChart.ChartAreas[2].AlignmentOrientation = AreaAlignmentOrientations.Vertical;
dlChart.ChartAreas[2].AlignmentStyle = AreaAlignmentStyles.All;
dlChart.ChartAreas[2].AlignWithChartArea = dlChart.ChartAreas[0].Name;

How to get MigraDoc to produce PDF with dynamic page width?

I have a PDF doc that I am trying to create, with about 20 columns, varying width. It gets about half of the columns on the first page and then cuts off the rest.I would like it to determine the page width and move the remaining columns onto the second page. Is there a way to specify this in rendering or PageSetup? I think I'll have to calculate the width, create the first page and then create the second.
Table table = new Table();
PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = doc;
doc.DefaultPageSetup.Orientation = MigraDoc.DocumentObjectModel.Orientation.Landscape;
//create the columns
for (int i = 1; i < tripReportGrid.Columns.Count; i++)
{
col = table.AddColumn(tripReportGrid.Columns[i].Width);
col.Format.Alignment = ParagraphAlignment.Center;
}
...fill the content same way
renderer.RenderDocument();
The width of the page is what you set - or A4 if you set nothing.
You can set the width of the page to any value. That will probably be OK when viewing the PDF file on the screen.
Or you can only add as many columns to one table as fit on one page. A4 in landscape format is 29.7 cm. Default margins are 2.5 cm left and right.
And BTW: you should never modify the DefaultPageSetup. Assign a Clone() of the DefaultPageSetup to the PageSetup of your Section and change that as needed.

GridSplitter behavior

I am trying to add columns and gridsplitters to a grid, but can't get the exact behavior.
After the user specifies where he wants a vertical splitter to appear:
// Get current Col0 width, size new col and existing Col0
double col0Width = LayoutRoot.ColumnDefinitions[0].ActualWidth;
double newCol0Width = col0Width - 5 - pt.X;
LayoutRoot.ColumnDefinitions[0].Width = new GridLength(newCol0Width);
// New Column 0
var c = new ColumnDefinition();
c.Width = new GridLength(pt.X);
LayoutRoot.ColumnDefinitions.Insert(0, c);// Attach GridSplitter to left edge of existing first column
var gss = new GridSplitter();
gss.Background = new SolidColorBrush(Colors.DarkSlateBlue);
gss.Width = 5; gss.Cursor = Cursors.ScrollWE;
gss.ResizeBehavior = GridResizeBehavior.BasedOnAlignment;
gss.HorizontalAlignment = HorizontalAlignment.Left;
LayoutRoot.Children.Add(gss);
// Add to current left-most colunn
Grid.SetColumn(gss, 0);
// Create new column, insert
// New Column 0
var c = new ColumnDefinition();
c.Width = new GridLength(pt.X);
LayoutRoot.ColumnDefinitions.Insert(0, c);
// Move existing content from Col 0 to new Col 1.
I can repeat this and create an arbitrary number of vertical splitters.
The required resize behavior: moving a splitter resizes only the columns immed. to the left and right of the splitter.
The current resize behavior: moving a splitter treats everything to the right of the splitter as one object, expanding or shrinking the column to the left of the splitter, while moving everything to the right. That is, if there are 3 columns, moving the left-most splitter appears to push col 2 to the right and shrinking col 3, without resizing col 2.
(I hope I explained that clearly enough.)
I have tried putting the GridSplitters in their own columns, and tried various GridResizeBehaviors, but haven't found the correct combination.
Any tips would be appreciated....
And a related question: In an event handler for GridSplitter's OnDragDelta, is there a way to stop the splitter from traveling any further in a certain direction? I would like to prevent them from shrinking the right-most column below a certain width, while allowing them to move the splitter back to the left.
Thanks.
As my comment suggested, it looks like the columns need to be '*' sized.
So, after adding the new column and splitter, I fixed up the widths like this (first clumsy cut at solution):
// Get all col widths, set appropriate '*' sizes.
foreach (ColumnDefinition col in LayoutRoot.ColumnDefinitions)
{
colWidths.Add(col.Width);
total += col.Width.Value;
Debug.WriteLine($" Width : {col.Width}");
}
Debug.WriteLine($"{total}");
for (int i = 0; i < LayoutRoot.ColumnDefinitions.Count; i++)
{
double d = colWidths[i].Value;
double ratio = d / total;
int ii = (int) (ratio * 100);
LayoutRoot.ColumnDefinitions[i].Width = new GridLength(ii, GridUnitType.Star);
}

How to put a table in the center of the page?

With MigraDoc I'm trying to put a table in the center of the page.
I'm using this code (c#, VS).
Section secondPage = new Section();
Table table = new Table();
AddColumns(table);
AddFirstRow(table);
AddSecondRow(table);
table.Format.Alignment=ParagraphAlignment.Center;
secondPage.Add(table);
I get a table aligned to the right of the page; how can I obtain a table in the center of the page?
To center a table in the center of a section.
table.Rows.Alignment = RowAlignment.Center;
You can set table.Rows.LeftIndent to indent the table. To get a centered table, calculate the indent based on paper size, page margins, and table width.
Example: Paper size is A4 (21 cm wide), left and right margins are 2.5 cm each. Thus we have a page body of 16 cm.
To center a table that is 12 cm wide, table.Rows.LeftIndent must be set to 2 cm (16 cm body width minus 12 cm table width gives 4 cm remaining space - half of the remaining space must be set as the LeftIndent).
From the code snippet in the original question, remove table.Format.Alignment=ParagraphAlignment.Center; and replace it with table.Rows.LeftIndent="2cm";.
Note that this will also work if the table is slightly wider than the body, but still within page edges. Using the page setup from the previous example, a table that is 18 cm wide can be centered with a LeftIndent of -1 cm.
Sample code (the table has just a single column):
var doc = new Document();
var sec = doc.AddSection();
// Magic: To read the default values for LeftMargin, RightMargin &c.
// assign a clone of DefaultPageSetup.
// Do not assign DefaultPageSetup directly, never modify DefaultPageSetup.
sec.PageSetup = doc.DefaultPageSetup.Clone();
var table = sec.AddTable();
// For simplicity, a single column is used here. Column width == table width.
var tableWidth = Unit.FromCentimeter(8);
table.AddColumn(tableWidth);
var leftIndentToCenterTable = (sec.PageSetup.PageWidth.Centimeter -
sec.PageSetup.LeftMargin.Centimeter -
sec.PageSetup.RightMargin.Centimeter -
tableWidth.Centimeter) / 2;
table.Rows.LeftIndent = Unit.FromCentimeter(leftIndentToCenterTable);
table.Borders.Width = 0.5;
var row = table.AddRow();
row.Cells[0].AddParagraph("Hello, World!");
The sample code uses Centimeter for calculations. You can also use Inches, Millimeter, Picas or Points.
Default page size is A4 and in the sample the LeftIndent will be 4 cm.

How to generate text box with max height in iTextSharp (auto-grow?)

We have a vehicle "Description" that could be anywhere from a few words to a few paragraphs. It needs to not go beyond a certain height (like 100px or whatever). Perfect solution would allow the text box to auto-grow (i.e. be as small as possible, but be able to grow up to a max height). There doesn't seem to be a way to restrict the height of a Paragraph or Phrase or anything. I have been messing with ColumnText but I can't seem to figure out how to make a ColumnText go into the flow of the document, so the next element after the Description goes below it and not on top of it. I have also seen ct.SetTextMatrix(xPos, yPos), but that still doesn't get me a max height box. Have I just not found what I'm needing yet, or does it not exist in iTextSharp?
Thank you so much, #Chris Haas! My solution was eventually found by the link he posted.
First, at the top of the page, we do the table height calculation:
PdfPTable tempTable = new PdfPTable(1);
tempTable.SetTotalWidth(new float[] { 540 }); //540 is width of PageSize.LETTER minus 36*2 for margins
string itemDescription = item.Description;
tempTable.AddCell(itemDescription);
float descriptionTableHeight = CalculatePdfPTableHeight(tempTable);
Then, the code for actually generating the PDF:
using (MemoryStream ms = new MemoryStream())
{
using (Document document = new Document(PageSize.LETTER))
{
using (PdfWriter writer = PdfWriter.GetInstance(document, ms))
{
document.Open();
//document properties
float margin = 36f;
document.SetMargins(margin, margin, margin, margin);
document.NewPage();
//description
customFont = FontFactory.GetFont("Helvetica", 10);
Phrase description = new Phrase(itemDescription, customFont);
table = new PdfPTable(1);
table.WidthPercentage = 100;
cell = new PdfPCell(description);
cell.Border = 0;
float maxHeight = 98f;
if (descriptionTableHeight > maxHeight)
cell.FixedHeight = maxHeight;
table.AddCell(cell);
document.Add(table);
}
}
}
So since we now have the table's height, we can check to see if it is greater than a maximum value and set the FixedHeight of the cell if so. And since we are able to add the table to the document, it goes in the normal flow of the page.
Thanks to the commenters for the leads!

Categories