I've got several textboxes on a PDF form. Most display fine, with data in them where appropriate, such as the "Required Date" textbox. Others display fine when passed no data (such as "Payment Amount"). Those at the bottom, though, do not display at all. e.g., look at the bottom section of the form, from "Requester / Payee Signature" down through the bottom of that ("Authorization") section - only horizontal lines appear below those labels, rather than the TextBoxes that should be there:
The code they use is virtually the same:
// "Request Date" is an example of those which displays fine:
PdfPCell cellReqDateTextBox = new PdfPCell()
{
CellEvent = new DynamicTextbox("textBoxReqDate", boxRequestDate.Text)
};
tblFirstRow.AddCell(cellReqDateTextBox);
. . .
doc.Add(tblFirstRow);
// Requester / Payee Signature" stands for all those who foul up:
PdfPCell cellTextBoxRequesterPayeeSignature = new PdfPCell()
{
CellEvent = new DynamicTextbox("textBoxRequesterPayeeSignature", "Enter signature here")
};
tblSection6_Row2.AddCell(cellTextBoxRequesterPayeeSignature);
. . .
doc.Add(tblSection6_Row2);
They both call this:
public class DynamicTextbox : IPdfPCellEvent
{
private string fieldname;
private string fieldvalue;
public DynamicTextbox(string name, string value)
{
fieldname = name;
fieldvalue = value;
}
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);
text.Text = fieldvalue;
PdfFormField field = text.GetTextField();
writer.AddAnnotation(field);
}
}
The only difference I can see in how they call "DynamicTextbox()" is that the ones that display pass the Text value of a Textbox as the second arg to DynamicTextbox(), whereas the ones that don't work pass a raw string - why would that matter?
Are the "horizontal lines" below the labels the TextBoxes? If so, why are they of such diminutive height?
All the other text fields belong to a cell in a row that has other content. This other content determines the height of the cell they belong too and as such also the height of the row.
The text fields that look as if they consist of a single line belong to a row with cells that have no content. These cells are added, but their height is zero. When the cell event is executed, the position parameter is a rectangle with zero height, hence the result that the fields added in such an event consist of nothing more than a line.
To avoid this, you can either define a minimum height or a fixed height. Minimum height means that the height can get a greater value than the value you define, if you add more content. Fixed height means that content that doesn't fit the height you defined won't be shown.
Use:
cellTextBoxRequesterPayeeSignature.FixedHeight = 20f;
or:
cellTextBoxRequesterPayeeSignature.MinimumHeight = 20f;
Adapt the value 20f to whichever value is most appropriate in the context of your application. The measurement unit is user units. The default is that 72 user units equal 1 inch.
Related
I'm using EPPlus and C# and trying to autosize/autofit the height of a row to accommodate the height needed to show all of the contents of a merged cell with text wrapping. However no matter what I try the text always truncates. Since I'm repeating this process with various text sizes on various worksheets, I don't want to hard code the row height (except to enforce a minimum height for the row). If possible I'd like to do this within EPPlus/C#.
With the cells A2:E2 merged and WrapText = true:
Cell with Text Truncated
Here's what it should look like with desired Cell Height
Here's my relevant and short C# code
Int32 intToCol;
intToCol = 5;
eppWorksheet.Cells[2, 1, 2, intToCol].Merge = true;
eppWorksheet.Cells[2, 1].Style.WrapText = true;
//Check if at the minimum height. If not, resize the row
if (eppWorksheet.Row(2).Height < 35.25)
{
eppWorksheet.Row(2).Height = 35.25;
}
I've looked at Autofit rows in EPPlus and it didn't seem to directly answer my question unless I'm reading it wrong.
Here is the solution in a reusable method. Pass in the text value, font used for the cell, summed width of the columns merged, and receive back the row height. Set the row height with the result.
Use of Method
eppWorksheet.Row(2).Height = MeasureTextHeight(cell.Value, cell.Style.Font, [enter the SUM of column widths A-E]);
Reuseable Method
public double MeasureTextHeight(string text, ExcelFont font, double width)
{
if (text.IsNullOrEmpty()) return 0.0;
var bitmap = _bitmap ?? (_bitmap = new Bitmap(1, 1));
var graphics = _graphics ?? (_graphics = Graphics.FromImage(bitmap));
var pixelWidth = Convert.ToInt32(width * 7); //7 pixels per excel column width
var fontSize = font.Size * 1.01f;
var drawingFont = new Font(font.Name, fontSize);
var size = graphics.MeasureString(text, drawingFont, pixelWidth, new StringFormat { FormatFlags = StringFormatFlags.MeasureTrailingSpaces });
//72 DPI and 96 points per inch. Excel height in points with max of 409 per Excel requirements.
return Math.Min(Convert.ToDouble(size.Height) * 72 / 96, 409);
}
I have used a workaround for this and I a had print area A:Q.
I copied merged cells value to column z.
set width of column z to merge cells width.
Then set auto row height true in format.
Hide the z column.
Set print area A:Q
Cons:
There are duplicate data. But we are okay since report is printing and not print z column.
Pros:
Row height works correctly not like calculation method.
Had to tweak the code a little bit by removing the multiplication factor at the return line. May be because i am using this code to get the width of the column.
ws1.Column(colIndx).Width * 7
The multiplication factor is the number of columns been merged.
How to set up paragraph width in MigraDoc? All what I imagine is create table and set the column width and then paragraph populate all width. But I need something like next:
var paragraph016 = section.AddParagraph();
paragraph016.Format.Borders.Bottom.Visible = true;
paragraph016.Format.WidowControl = true;
//here must be define paragraph width
Or maybe anybody know how can I draw line on the page, where I can setup width and position of my line?
I use paragraph width as a part of my 'add a horizontal rule' helper method. Using left and right indent works great:
public static void AddHorizontalRule(Section section, double percentWidth, Color? color = null)
{
double percent = (percentWidth < 0.0 || percentWidth > 1.0) ? 1.0 : percentWidth;
Color hrColor = color ?? new Color(96, 96, 96); // Lt Grey default
Unit contentWidth = section.PageSetup.PageWidth - section.PageSetup.LeftMargin - section.PageSetup.RightMargin;
Unit indentSize = (contentWidth - (percent * contentWidth)) / 2.0;
Paragraph paragraph = section.AddParagraph();
paragraph.Format.LeftIndent = indentSize;
paragraph.Format.RightIndent = indentSize;
paragraph.Format.Borders.Top.Visible = true;
paragraph.Format.Borders.Left.Visible = false;
paragraph.Format.Borders.Right.Visible = false;
paragraph.Format.Borders.Bottom.Visible = false;
paragraph.Format.Borders.Top.Color = hrColor;
}
Note that because a section's PageSetup values are 0 and therefore use the default document settings, that to use the client area width as shown above, you need to explicitly set these values in the section.PageSetup before calling this method. I do it this way so that I don't have to pass around the document nor depend on document.LastSection being the section that I am working on. I just pass in a Section object and have at it.
Enjoy!
Brian
You can set the width indirectly by specifying left and right indent. I don't know if this leads to the desired line, but it's worth a try.
A table will work.
An image would also work - best with a vector image (could be PDF), but a raster image with a single pixel in the desired color should also work.
I am usign a code a code like this and when the text gets long, it cuts it off and doesn't show the whole text :( In this aspect I want it to behave like a list box item. One line was for one item in the list box and didn't have this trucnacted text issue.
listView1.Scrollable = true;
listView1.View = View.Details;
listView1.HeaderStyle = ColumnHeaderStyle.None;
ColumnHeader header = new ColumnHeader();
header.Text = "MyHeader";
header.Name = "MyColumn1";
listView1.Columns.Add(header);
listView1.Items.Add("TooLongTextDoesntShow");
listView1.Items.Add("short");
listView1.Items.Add("abcd");
I think it is just easier to attach a picture of the issue. Please notice how it is not displaying full text of the highlighted item :(
Thanks for your help.
Just specify a column header width.
ColumnHeader header = new ColumnHeader();
header.Text = "MyHeader";
header.Name = "MyColumn1";
header.Width = listView1.Width //Same Width as Entire List Control
listView1.Columns.Add(header);
Alternative ways to do, is during the add.
You can make use of: ListView.ColumnHeaderCollection.Add
public virtual ColumnHeader Add(
string text,
int width //width of the header
)
Ok, I found a solution, please let me know if there are better ways of doing it too
AFTER adding items to list view is done, we should call this:
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
We take an example of ListView with 2 columns and resize on contents and then to minimum width.
// Auto resize of ListView Columns to minimum width
private int[] ColumnsWidth = { 35, 322 };
/// <summary>
/// Resize the columns based on the items entered
/// </summary>
private void ResizeColumns()
{
// Auto Resize Columns based on content
m_urlsListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
// Make sure to resize to minimum width
if (m_urlsListView.Columns[0].Width < ColumnsWidth[0])
{
m_urlsListView.Columns[0].Width = ColumnsWidth[0];
}
if (m_urlsListView.Columns[1].Width < ColumnsWidth[1])
{
m_urlsListView.Columns[1].Width = ColumnsWidth[1];
}
}
The content is being truncated because of (practically invisible) column. You can tell the ListView to adjust the column widths automatically:
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
listView1.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
You can just add a column and define its width according to your text size requirement. Moreover "Scrollable" property can be set to true if the actual width of the listview control is smaller
ListView_Column_Width_Image
I'm setting the following properties for a DataGridView in my C# project ...
sampleDataGridView.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
sampleDataGridView.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
But I notice that the heading's (i.e. text in header cell is offset slightly to the left, for some reason .. The data rows alignment in perfectly in center though ...
What can be causing this ?
It is because there is a sorting glyph (little arrow) for which the DataGridView reserves some space to show the sort order. If you want to disable the sorting glyph, set the SortMode on your column to NotSortable, and your text should then be centered.
Old topic,
i had this problem, and i found out that the problem was that i had the grid datasource-linked to my stuff, and when the columns where created they put the ALLOW SORT ON by default, which created the arrow down button to sort, and the text gets pushed to the left.
small fix to this is:
private void MyDataGridView_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
e.Column.SortMode = DataGridViewColumnSortMode.NotSortable;
}
I had the same problem as you and it seems it's a framework issue: MS Connect
Figure out the glyph width without refection and supress when out of line:
In the following code I turn on and off sorting while autoadjusting column width to the column header text width. The difference in width between sorting on/off will reveal the width used by the column sort glyph.
As column looses the glyph when column width is set less than autoadjusted width I supress it by inserting symetric left and right column padings.
I also use a dictionary to store ColumnWidth events by datagridview instance to turn width events on and off while seting the width.
I call this crazy code both to autoadjust initial column widths and to manage the column header padings when user drags column widths.
void AdaptColumnHeaderText(DataGridViewColumn column, bool autoSize=false)
{
//Supress column width events
if (dataGridViewColumnWidthEventHandlers.ContainsKey(column.DataGridView))
{
dataGridView1.ColumnWidthChanged -= dataGridViewColumnWidthEventHandlers[column.DataGridView];
}
//Save initial column with as preferred
var w_preferred = column.Width;
if (
column.SortMode.Equals(DataGridViewColumnSortMode.Automatic) &&
column.HeaderCell.Style.Alignment.Equals(DataGridViewContentAlignment.MiddleCenter))
{
//remove all header padding
column.HeaderCell.Style.Padding = new Padding(0, 0, 0, 0);
//Fit column width to header text with AND sort glyph
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;
//save column width sort enabled
var w_sort = column.Width;
//Fit column width to header text with NO sort glyph
column.SortMode = DataGridViewColumnSortMode.NotSortable;
//save column width when sort disable
var w_nosort = column.Width;
//Calculate width consumed by sort glyph
var w_glyph = w_sort - w_nosort;
//Nominal column width if glyph width applied left and right of header text
var w_nominal = w_glyph + w_nosort + w_glyph;
//Disable column width autosize
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
//Enable column autosorting
column.SortMode = DataGridViewColumnSortMode.Automatic;
//If autosize option - ignore preferred width and set to nominal
if (autoSize)
{
w_preferred = w_nominal;
}
//Pad depending on final column width
if (w_preferred >= w_nominal)
{
//Preferred width greater than nominal - pad left of text to balance width used by glyph
column.HeaderCell.Style.Padding = new Padding(w_glyph, 0, 0, 0);
}
else
{
//Two symetric glyphs will not fit - pad left and right to supress glyph
w_glyph = (w_preferred - w_nosort) / 2;
column.HeaderCell.Style.Padding = new Padding(w_glyph, 0, w_glyph, 0);
}
column.Width = w_preferred;
Console.WriteLine("name:{0}, glyph:{1}, w_preferred:{2}", column.Name, w_glyph, w_preferred);
}
//re-enable column width events
if (dataGridViewColumnWidthEventHandlers.ContainsKey(column.DataGridView))
{
dataGridView1.ColumnWidthChanged += dataGridViewColumnWidthEventHandlers[column.DataGridView];
}
}
You can add two spaces at the beginning of the column name to compensate the space reseved for the glyph.
I have a Panel that I'm creating programmatically; additionally I'm adding several components to it.
One of these components is a Label which will contain user-generated content.
I don't know how tall the label should be, but it does have a fixed width.
How can I set the height so that it displays all the text, without changing the width?
Just use the AutoSize property, set it back to True.
Set the MaximumSize property to, say, (60, 0) so it can't grow horizontally, only vertically.
Use Graphics.MeasureString:
public SizeF MeasureString(
string text,
Font font,
int width
)
The width parameter specifies the
maximum value of the width component
of the returned SizeF structure
(Width). If the width parameter is
less than the actual width of the
string, the returned Width component
is truncated to a value representing
the maximum number of characters that
will fit within the specified width.
To accommodate the entire string, the
returned Height component is adjusted
to a value that allows displaying the
string with character wrap.
In other words, this function can calculate the height of your string based on its width.
If you have a label and you want have control over the the vertical fit, you can do the following:
MyLabel.MaximumSize = new Size(MyLabel.Width, 0)
MyLabel.Height = MyLabel.PreferredHeight
MyLabel.MaximumSize = new Size(0, 0)
This is useful for example if you have a label in a container that can be resized. In that case, you can set the Anchor property so that the label is resized horizontally but not vertically, and in the resize event, you can fit the height using the method above.
To avoid the vertical fitting to be interpreted as a new resize event, you can use a boolean:
bool _inVerticalFit = false;
And in the resize event:
if (_inVerticalFit) return;
_inVerticalFit = true;
MyLabel.MaximumSize = new Size(MyLabel.Width, 0)
MyLabel.Height = MyLabel.PreferredHeight
MyLabel.MaximumSize = new Size(0, 0)
_inVerticalFit = false;