I am using iTextSharp to create table in PDF document. I need several lines inside table cell to appear one under another like this:
First line text
Second Line Text
Third Line Text
Fourth line text
Some times with extra line like this :
First line text
Second Line Text
Third Line Text
Fourth line text
I have tried several approaches, with Paragraphs, Chunks, Phrases, did research online but still can not get this result. Please help.
Also, how to make columns to adjust width dynamically to content ? (not wrapping)
Thank you
If you need to align at the text level you'll need to switch to a fixed-width font. But if you're just looking to indent you can just add spaces to new lines within a paragraph:
var p = new Paragraph();
p.Add("First line text\n");
p.Add(" Second line text\n");
p.Add(" Third line text\n");
p.Add("Fourth line text\n");
myTable.AddCell(p);
You could also get complicated and use a sub-table if you need more control:
var subTable = new PdfPTable(new float[] { 10, 100 });
subTable.AddCell(new PdfPCell(new Phrase("First line text")) { Colspan = 2, Border = 0 });
subTable.AddCell(new PdfPCell() { Border = 0 });
subTable.AddCell(new PdfPCell(new Phrase("Second line text")) { Border = 0 });
subTable.AddCell(new PdfPCell() { Border = 0 });
subTable.AddCell(new PdfPCell(new Phrase("Third line text")) { Border = 0 });
subTable.AddCell(new PdfPCell(new Phrase("Fourth line text")) { Colspan = 2, Border = 0 });
myTable.AddCell(subTable);
Though pretty tedious, but for setting font, following seem to work:
Font myFont = FontFactory.GetFont("Arial", 8, Font.NORMAL);
string line1 = "First line of text" + "\n";
string line2= "Second line of text" + "\n";
string line3= " Third Line of text";
Paragraph p1 = new Paragraph();
Phrase ph1 = new Phrase(line1, myFont);
Phrase ph2 = new Phrase(line2, myFont);
Phrase ph3 = new Phrase(line3, myFont);
p1.Add(ph1);
p1.Add(ph2);
p1.Add(ph3);
PdfPCell mycell = new PdfPCell(p1);
You can also do it the following way ..
var xstring = "Your first line \n Your 2nd line";
Phrase p = new Phrase();
p.Add(new Chunk(xstring, yourFontFace));
I text will notice the new line return code and render your phrase on two separate lines.
Your first line
Your 2nd line
Cheers
#region .!!
PdfPTable tbl_A = new PdfPTable(1);
tbl_A.WidthPercentage = 98f;
//float[] colWidthUnderTaking1 = { 1300 };
//tblUnderTaking1.SetWidths(colWidthUnderTaking1);
#region For Page Space
PdfPCell cell_A;
cell_A = new PdfPCell(new Phrase(" ", Smallspace));
cell_A.HorizontalAlignment = 1;
cell_A.BorderWidth = 0;
cell_A.Colspan = 2;
tbl_A.AddCell(cell_A);
cell_A = new PdfPCell(new Phrase(" ", Smallspace));
cell_A.HorizontalAlignment = 1;
cell_A.BorderWidth = 0;
cell_A.Colspan = 2;
tbl_A.AddCell(cell_A);
#endregion
Chunk cMem = new Chunk("The Member ", TableFontmini_ARBold8Nor);
Chunk cName = new Chunk(dt.Rows[0]["EmpName"].ToString(), TableFontmini_ARBold10);
Chunk cjoin = new Chunk(" Has joined On ", TableFontmini_ARBold8Nor);
Chunk cDOJ = new Chunk(" " + dt.Rows[0]["DOJPF"].ToString(), TableFontmini_ARBold10);
Chunk chas = new Chunk("and has been alloted PF Member ID ", TableFontmini_ARBold8Nor);
Chunk cPF = new Chunk(" " + dt.Rows[0]["PFNo"].ToString(), TableFontmini_ARBold10);
Phrase paira = new Phrase();
paira.Add(cMem);
paira.Add(cName);
paira.Add(cjoin);
paira.Add(cDOJ);
paira.Add(chas);
paira.Add(cPF);
Paragraph pName = new Paragraph();
pName.Add(paira);
PdfPCell cell_A2 = new PdfPCell(pName);
cell_A2.HorizontalAlignment = 0;/**Left=0,Centre=1,Right=2**/
cell_A2.BorderWidth = 0;
cell_A2.Colspan = 2;
tbl_A.AddCell(cell_A2);
doc.Add(tbl_A);
#endregion
Related
I'm creating a table with abcpdf. It should begin in the middle of the first page and break before the footer. Then it should restart at the beginning of the new page (it depends on the number of the rows).
Here is the code:
string theText = System.IO.File.ReadAllText(#"C:\Users\..file.txt")
Doc theDoc = new Doc();
theDoc.AddGrid();
theDoc.Rect.String = "10 200 600 780";
theDoc.FrameRect();
PDFTable theBigTable = new PDFTable(theDoc, 1);
theBigTable.NextRow();
theBigTable.SetRowHeight(200);
theBigTable.NextRow();
theBigTable.SetRowHeight(300);
PDFTable theTable = new PDFTable(theDoc, 5);
theTable.CellPadding = 5;
theTable.HorizontalAlignment = 1;
theText = theText.Trim();
theText = theText.Replace("\r\n", "\r");
string[] theRows = theText.Split(new char[] { '\r' });
for (int i = 0; i < theRows.Length; i++)
{
theTable.NextRow();
string[] theCols = theRows[i].Split(new char[] { '\t' });
theTable.AddHtml(theCols);
theTable.FrameColumns();
}
theTable.Frame();
theDoc.Flatten();
//footer
theDoc.Rect.String = "10 10 600 60";
theDoc.FrameRect();
theDoc.Save("output.pdf");
theDoc.Clear();
The issue is that the table re-starts in the new page in the same position (and not from the beginning) and it overrides the footer that appears only in the last page.
Any suggestions?
using Word = Microsoft.Office.Interop.Word;
public static void CreateWord()
{
Word.Application objWord = new Word.Application();
Word.Document objDoc = objWord.Documents.Add();
Word.Paragraph objPara;
objPara = objDoc.Paragraphs.Add();
objPara.Range.Text = "Bold text aligned center";
objPara.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
objPara.Range.Bold = 1;
objPara.Range.InsertParagraphAfter();
objPara = objDoc.Paragraphs.Add();
objPara.Range.Text = "Regular text aligned left";
objPara.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
objPara.Range.Bold = 0;
objPara.Range.InsertParagraphAfter();
objPara = objDoc.Paragraphs.Add();
objPara.Range.Text = "Regular text aligned center\nwith something on the next line";
objPara.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
objPara.Range.Bold = 0;
objPara.Range.InsertParagraphAfter();
objPara = objDoc.Paragraphs.Add();
objPara.Range.Text = "Regular text aligned left, with some Bold text here\nand some regular text on next line";
objPara.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
objPara.Range.Bold = 0;
objPara.Range.InsertParagraphAfter();
objWord.Visible = true;
objWord.WindowState = Word.WdWindowState.wdWindowStateNormal;
}
The code above creates a Word document and writes text to it, but it looks like this:
I'm assuming that text in Microsoft.Office.Interop.Word is not supposed to act like that, or text should be added in some other way, but I'm failing to find any good information on how to do this.
So, my question is - how to add text from c# to a newly created word document with the right properties, so the result looks like this:
P.S. tips about creating tables using .Interop.Word would also be appreciated.
The key to working with content in Word documents is to understand how to work with Range objects. There's more than one way to achieve a goal of this nature. The following code snippet is my preference: collapsing the Range for each step (think of it like pressing the right-arrow key to "collapse" a selection to a point), rather than mixing Add, InsertAfter and similar methods.
For each change of formatting the Range must be "collapsed". So if you have bold in the middle of a line, that's a separate step. If numerous paragraphs should have the same formatting, they can be combined.
Environment.NewLine and \n can be used interchangeably.
Generally, assign text content, then format the Range.
object oCollapseEnd = Word.WdCollapseDirection.wdCollapseEnd;
doc.Paragraphs.Add();
Word.Range objRange = doc.Content;
objRange.Collapse(ref oCollapseEnd);
objRange.Text = "Bold text aligned center" + Environment.NewLine;
objRange.Bold = 1;
objRange.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
objRange.Collapse(ref oCollapseEnd);
objRange.Text = "Regular text aligned left" + Environment.NewLine;
objRange.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
objRange.Bold = 0;
objRange.Collapse(ref oCollapseEnd);
objRange.Text = "Regular text aligned center\nwith something on the next line" + Environment.NewLine;
objRange.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
objRange.Bold = 0;
objRange.Collapse(ref oCollapseEnd);
objRange.Text = "Regular text aligned left, with some ";
objRange.Collapse(ref oCollapseEnd);
objRange.Text = "Bold text here";
objRange.Bold = 1;
objRange.Collapse(ref oCollapseEnd);
objRange.Text = "\nand some regular text on next line" + Environment.NewLine;
objRange.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
objRange.Bold = 0;
In my C# windows Form application I use below code. it works fine. but I need to add line space for this paragraph.
var linkFont = FontFactory.GetFont(FontFactory.HELVETICA, 13, iTextSharp.text.Font.UNDERLINE, BaseColor.BLUE);
List<Anchor> anchor = new List<Anchor>();
foreach (string tName in templateName)
{
Anchor anch = new Anchor(tName, linkFont);
anch.Reference = "#" + tName;
anchor.Add(anch);
}
Paragraph templateData = new Paragraph();
templateData.Alignment = Element.ALIGN_LEFT;
for (int z = 0; z < anchor.Count; z++)
{
templateData.Add(anchor[z]);
templateData.Add(" , ");
}
output of this code is below.
Output of above code
if I use following code nothing changed.
Paragraph templateData = new Paragraph();
templateData.Alignment = Element.ALIGN_LEFT;
templateData .SetLeading(15, 1);
How can I fix this issue and add line space for this paragraph ?
Thanks
Change value of Y in:
templateData.SetLeading(15, 10); //'1' to '10' or whatever you want
I have a RichTextBox for a simple chat where I add lines programmatically.
I make the usernames bold and the messages in regular style.
After some lines I want to delete the first lines to keep the chat in a acceptably length. But when I do so I lose the text format and everything appears bold. What am I doing wrong and how can I fix this?
EDIT
I could solve the problem where I wasn't able to delete the first line.
I had to set the the ReadOnly property to false. Even though I was able to add new lines it prevented deleting lines. So the following code works to delete lines. Thanks to #TaW!
if (ChatText.Lines.Length >= 10)
{
int p = 0; int count = 0;
do
{
p = ChatText.Text.IndexOf("\n\r");
if (p >= 0)
{
ChatText.SelectionStart = p;
ChatText.SelectionLength = 2; // length of "\n\r"
ChatText.SelectedText = "\n";
count++;
}
}
while(p >= 0);
int nll = 1; // <<=== pick the length of your new line character(s)!!
int pS = ChatText.Lines.Take(0).Select(x => x.Length + nll).Sum() - nll;
int pL = ChatText.Lines.Take(1).Select(x => x.Length + nll).Sum() - nll;
if (pS < 0) { pS = 0; pL++; }
ChatText.SelectionStart = pS;
ChatText.SelectionLength = pL - pS;
ChatText.Cut();
}
//////////////////////////////////
// now add new lines
//////////////////////////////////
string[] chatstr;
// string text is given as method parameter
chatstr = text.Split(new string[] { ": " }, 2, StringSplitOptions.None);
// go to the end of the text
ChatText.SelectionStart = ChatText.Text.Length;
ChatText.SelectionLength = 0;
// make text bold
ChatText.SelectionFont = new Font(ChatText.Font, FontStyle.Bold);
// add username (chatstr[0]) and colon
ChatText.AppendText(chatstr[0] + ": ");
// make text regular
ChatText.SelectionFont = new Font(ChatText.Font, FontStyle.Regular);
// add message (chatstr[1])
ChatText.AppendText(chatstr[1] + "\n");
// and finaly scroll down
ChatText.ScrollToCaret();
So deleting lines works and new lines are added as intended. Finaly!
solved :)
Never change the Text of a RichtTextBox if it contains any formatting.
Changing the Lines property (by Skip) is just another way to change the Text.
Instead only use the functions the RTB provides: Always start by selecting the portion you want to format, then apply one or more of the functions and/or set one or more of the properties..:
To delete portions use Cut.
Here is a function that will delete a number of entire lines:
void DeleteLines(RichTextBox rtb, int fromLine, int count)
{
int p1 = rtb.GetFirstCharIndexFromLine(fromLine);
int p2 = rtb.GetFirstCharIndexFromLine(fromLine + count);
rtb.SelectionStart = p1;
rtb.SelectionLength = p2 - p1;
bool readOnly = rtb.ReadOnly; // allow change even when the RTB is readonly
rtb.ReadOnly = false; ;
rtb.Cut();
rtb.ReadOnly = readOnly;
}
Trying to keept the formatting alive yourself is a tedious and error-prone waste of your time.
In addition to font properties you would also have to resore all other things you can set with the SelectedXXX properties, like colors, alignment, spacing etc etc..
To delete the first 3 lines use:
DeleteLines(yourRTB, 0, 3);
To restrict the text to 10 lines use:
DeleteLines(yourRTB, 0, yourRTB.Lines.Length - 10);
Note that the function above should have a few checks for valid input; I left them out as the checks somehow need a decision what to do, if count or fromLine if greater than Lines.Length or if fromLine is negative..
While we are at it, here is how to append a bold line:
yourRTB.SelectionStart = yourRTB.Text.Length;
yourRTB.SelectionLength = 0;
using (Font font = new Font(yourRTB.SelectionFont, FontStyle.Bold))
yourRTB.SelectionFont = font;
yourRTB.AppendText(yourNewLine + textOfNewLine);
Of course it really shold go into a reuseable function that the the bolding as a parameter..
Update:
since you are using WordWrap you may prefer this function. It deletes the actual lines, not the visible ones:
void DeleteLinesWW(RichTextBox rtb, int fromLine, int count)
{
int nll = 1; // <<=== pick the length of your new line character(s)!!
int pS = rtb.Lines.Take(fromLine).Select(x => x.Length + nll).Sum() - nll;
int pL = rtb.Lines.Take(fromLine + count).Select(x => x.Length + nll).Sum() - nll;
if (pS < 0) { pS = 0; pL++; }
rtb.SelectionStart = pS;
rtb.SelectionLength = pL - pS ;
bool readOnly = rtb.ReadOnly;
rtb.ReadOnly = false; // allow change even when the RTB is readonly
rtb.Cut();
rtb.ReadOnly = readOnly;
}
A word on NewLine: Do note that I have not used the Environment.NewLine constant as it not really a good idea. If you add multiline text to the RichTextBox in the designer and then look at it you will see that it uses simple '\n' new lines, no returns, no NL-CR, just '\n'. So this seems to be the generic way in a winforms RTB and I recommend using it..
The new function relies on all lines having a newline of the same length!
To make sure you can use this replacement function:
int RTBReplace(RichTextBox rtb, string oldText, string newText)
{
int p = 0; int count = 0;
do
{
p = richTextBox1.Text.IndexOf(oldText);
if (p >= 0)
{
richTextBox1.SelectionStart = p;
richTextBox1.SelectionLength = oldText.Length;
richTextBox1.SelectedText = newText;
count ++;
}
}
while (p >= 0);
return count;
}
Calling it like this:
RTBReplace(yourrichTextBox, "\r\n", "\n");
Update 2:
Here is an example how to add your chat lines:
private void button1_Click(object sender, EventArgs e)
{
string cLine = "Taw: Hello World"; // use your own lines!
var chatstr = cLine.Split(new string[] { ": " }, 2, StringSplitOptions.None);
AppendLineBold(yourrichTextBox, "\n" + chatstr[0], true);
AppendLineBold(yourrichTextBox, chatstr[1], false);
yourrichTextBox.ScrollToCaret();
}
void AppendLineBold(RichTextBox rtb, string text, bool bold)
{
rtb.SelectionStart = richTextBox1.Text.Length;
rtb.SelectionLength = 0;
using (Font font = new Font(rtb.SelectionFont,
bold ? FontStyle.Bold : FontStyle.Regular))
rtb.SelectionFont = font;
rtb.AppendText(text);
}
Update 3:
Looks like the ReadOnly property disallows the use of Cut. So we need to temporatily allow changes.
Funny: SelectedText can't be set either, but AppendText works fine..
To keep text formatting, you can also try the following (it's a little shorter and should also do the trick)
string text = "Username: hello this is a chat message";
// delete the first line when after 10 lines
if (ChatText.Lines.Length >= 10)
{
ChatText.SelectionStart = 0; // set SelectionStart to the beginning of chat text (RichTextBox)
ChatText.SelectionLength = ChatText.Text.IndexOf("\n", 0) + 1; // select the first line
ChatText.SelectedText = ""; // replace by an empty string
ChatText.SelectionStart = ChatText.Text.Length; // set SelectionStart to text end to make SelectionFont work for appended text
}
// split the string in chatstr[0] = username, chatstr[1] = message
string[] chatstr = text.Split(new string[] { ": " }, 2, StringSplitOptions.None);
// make the username bold
ChatText.SelectionFont = new Font(ChatText.Font, FontStyle.Bold);
ChatText.AppendText(chatstr[0] + ": ");
// make the message regular
ChatText.SelectionFont = new Font(ChatText.Font, FontStyle.Regular);
ChatText.AppendText(chatstr[1] + Environment.NewLine);
ChatText.ScrollToCaret();
I have a text file as shown below
Name:xxxx Address:xxxxx Contact No: xxx NIC No: xxxx
in a single string.
I want to read the text file and extract only the name address contact number and NIC no using c# into an excel sheet.
I was able to read the whole string and save it into an excel sheet.
Apparently, you already know how to read a textfile and how to write to Excel. Remains the problem of how to split the line into separate values.
IF all those lines have the same field labels and field order, then you could use a regex to parse the line:
string line = "Name: xx xx Address:yyy yyYY Contact No: 1234 NIC No: xXxX";
var regex = new Regex(#"Name:\s*(.*)\s*Address:\s*(.*)\s*Contact No:\s*(.*)\s*NIC No:\s*(.*)\s*");
var match = regex.Match(line);
if (match.Success)
{
var name = match.Groups[1].Value;
var address = match.Groups[2].Value;
var contactNo = match.Groups[3].Value;
var nic = match.Groups[4].Value;
// TODO write these fields to Excel
}
This regex uses the field labels ("Name:", "Address:", etc) to find the values you need. The \s* parts mean that any whitespace around the values is ignored. The (.*) parts capture values into Groups in the match class, counting from 1.
If your Name, Address Contact No etc. fields are separated using a tab delimiter (\t) then you can split the string using tab delimiter like this:
string.Split('\t');
Instead of \t you can use whatever delimiter is there is the text file.
If you have a space then you might have a problem because the fields and field values may have spaces in between.
It is not clear if you have only one record in each file.
Let's suppose your data in a single file is:
Name:N1 Address:A1 W. X, Y - Z Contact No: C1 NIC No: I1 Name:N2 Address:A2 W. X, Y - Z Contact No: C2 NIC No: I2
So there are 2 records on a single line (but there could be more)
Name:N1 Address:A1 W. X, Y - Z Contact No: C1 NIC No: I1
Name:N2 Address:A2 W. X, Y - Z Contact No: C2 NIC No: I2
I don't think splitting by white spaces is practical because fields like name and address may contain spaces. Ideally colon symbol (:) is used only as delimiter between keys and values and it's not used in any value. Otherwise the solution gets more complicated.
Also, I assume that the order of keys is guaranteed to be as in the example above:
Name
Address
Contact No
NIC No
Use a list of custom objects or a DataTable to hold your structured data.
In this example I will use DataTable:
var separators = new char[] { ':' };
var data = new DataTable();
data.Columns.Add("Name", typeof(string));
data.Columns.Add("Address", typeof(string));
data.Columns.Add("ContractNo", typeof(string));
data.Columns.Add("NICNo", typeof(string));
For each file with records, open the file, read the file content and "process" it:
foreach (string fileName in fileNames)
{
//read file content
string fileContent = ...;
string[] tokens = fileContent.Split(separators);
//we skip first token. It will always be 'Name'.
for(int i = 0; i < (tokens - 1) / 4; i++)
{
var record = data.NewRow();
string token = tokens[i * 4 + 1];
record["Name"] = token.Substring(0, token.Lenght - 7).Trim(); // Remove 'Address' from end and trim spaces
token = tokens[i * 4 + 2];
record["Address"] = token.Substring(0, token.Length - 10).Trim(); //Remove 'Contact No' from end and trim spaces
token = tokens[i * 4 + 3];
record["ContractNo"] = token.Substring(0, token.Length - 6).Trim(); //Remove 'NIC No' from end and trim spaces
token = tokens[i * 4 + 4];
if (token.EndsWith('Name')) //if there are multiple records
token = token.Substring(0, token.Length - 4);
record["NICNo"] = token.Trim();
data.Rows.Add(record);
}
}
This will also work if each file contains only one record.
Now that you have the structured data in a data table it should be easy to insert them in excel worksheet.
static void Main(string[] args)
{
//Application.WorkbookBeforeSave += new Excel.AppEvents_WorkbookBeforeSaveEventHandler(Application_WorkbookBeforeSave);
string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Name");
dt.Columns.Add("Address");
dt.Columns.Add("Contact No");
dt.Columns.Add("NIC");
foreach (string txtName in Directory.GetFiles(#"D:\unityapp\tab02", "*.txt"))
{
StreamReader sr = new StreamReader(txtName);
//string line = "Name: Address: Contact No: NIC No:";
string[] token1 = sr.ReadLine().Split(new string[] { "Name: ", "Address: ", "Contact No: ", "NIC No:" }, StringSplitOptions.None);
dt.Rows.Add(token1[1], token1[2], token1[3], token1[4]);
}
Microsoft.Office.Interop.Excel.Application x = new Microsoft.Office.Interop.Excel.Application();
// Workbook wb = x.Workbooks.Open(#"C:\Book1.xlsx");
Workbook wb = x.Workbooks.Add();
Worksheet sheet = (Microsoft.Office.Interop.Excel.Worksheet)wb.Worksheets.get_Item(1);
// Microsoft.Office.Interop.Excel.Workbook wb = new Microsoft.Office.Interop.Excel.Workbook();
// Microsoft.Office.Interop.Excel.Worksheet sheet = new Microsoft.Office.Interop.Excel.Worksheet();
sheet.Cells[1, 1] = "Name";
sheet.Cells[1, 1].Interior.ColorIndex = 10;
sheet.Cells[1, 2] = "Address";
sheet.Cells[1, 2].Interior.ColorIndex = 20;
sheet.Cells[1, 3] = "Contact No";
sheet.Cells[1, 3].Interior.ColorIndex = 30;
sheet.Cells[1, 4] = "NIC";
sheet.Cells[1, 4].Interior.ColorIndex = 40;
int rowCounter = 2;
int columnCounter = 1;
foreach (DataRow dr in dt.Rows)
{
sheet.Cells[rowCounter, columnCounter] = dr["Name"].ToString();
columnCounter += 1;
sheet.Cells[rowCounter, columnCounter] = dr["Address"].ToString();
columnCounter += 1;
sheet.Cells[rowCounter, columnCounter] = dr["Contact No"].ToString();
columnCounter += 1;
sheet.Cells[rowCounter, columnCounter] = dr["NIC"].ToString();
rowCounter += 1;
columnCounter = 1;
}
wb.SaveAs(#"D:\Unity.xlsx");
wb.Close();
x.Quit();
Process.Start(#"D:\Unity.xlsx");
}
}
}