What I'm trying to achieve
In my c# application I would like to generate a report (word document) from data in my application, I figured that the best way to do this would be to perform something like a mail merge using the data source from my application.
What I've tried
I tried following this
Mail Merge into word
however this uses GemBox which you need to pay for
I have tried using Microsoft.Office.Interop.Word however I fell
short when I didn't know how to reference the saved template document:
Dictionary<string, string> MailMerge = new Dictionary<string, string>()
{
{ "ID", "123" },
{ "Name", "Test" },
{ "Address1", "Test" },
{ "Address2", "Test" },
{ "Address3", "Test" },
{ "Address4", "Test" },
{ "PostCode", "Test" },
{ "Year End", "Test" },
{ "SicCode", "123" },
};
Document doc = new Document();
doc.MailMerge.Execute(MailMerge);
Summary
I'm looking for some guidance as to what to research further as I believe there must be a 'standard' way of doing this.
Can't believe third party software charge thousands for interface functions with Word. I have perfectly solved this mail merge thing in my project -- no third party, no particular demands on IIS, just use OpenXML.
So, add these 4 functions to your project:
public static void dotx2docx(string sourceFile, string targetFile)
{
MemoryStream documentStream;
using (Stream tplStream = File.OpenRead(sourceFile))
{
documentStream = new MemoryStream((int)tplStream.Length);
CopyStream(tplStream, documentStream);
documentStream.Position = 0L;
}
using (WordprocessingDocument template = WordprocessingDocument.Open(documentStream, true))
{
template.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart mainPart = template.MainDocumentPart;
mainPart.DocumentSettingsPart.AddExternalRelationship("http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate",
new Uri(targetFile, UriKind.Absolute));
mainPart.Document.Save();
}
File.WriteAllBytes(targetFile, documentStream.ToArray());
}
public static void CopyStream(Stream source, Stream target)
{
if (source != null)
{
MemoryStream mstream = source as MemoryStream;
if (mstream != null) mstream.WriteTo(target);
else
{
byte[] buffer = new byte[2048];
int length = buffer.Length, size;
while ((size = source.Read(buffer, 0, length)) != 0)
target.Write(buffer, 0, size);
}
}
}
public static void Mailmerge(string templatePath, string DestinatePath, DataRow dr, DataColumnCollection columns)
{
try
{
dotx2docx(templatePath, DestinatePath);
}
catch //incase the server does not support MS Office Word 2003 / 2007 / 2010
{
File.Copy(templatePath, DestinatePath, true);
}
using (WordprocessingDocument doc = WordprocessingDocument.Open(DestinatePath, true))
{
var allParas = doc.MainDocumentPart.Document.Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>();
Text PreItem = null;
string PreItemConstant = null;
bool FindSingleAnglebrackets = false;
bool breakFlag = false;
List<Text> breakedFiled = new List<Text>();
foreach (Text item in allParas)
{
foreach (DataColumn cl in columns)
{
//<Today>
if (item.Text.Contains("«" + cl.ColumnName + "»") || item.Text.Contains("<" + cl.ColumnName + ">"))
{
item.Text = item.Text.Replace("<" + cl.ColumnName + ">", dr[cl.ColumnName].ToString())
.Replace("«" + cl.ColumnName + "»", dr[cl.ColumnName].ToString());
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
}
else if //<Today
(item.Text != null
&& (
(item.Text.Contains("<") && !item.Text.Contains(">"))
|| (item.Text.Contains("«") && !item.Text.Contains("»"))
)
&& (item.Text.Contains(cl.ColumnName))
)
{
FindSingleAnglebrackets = true;
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"\<" + cl.ColumnName + #"(?!\w)", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"\«" + cl.ColumnName + #"(?!\w)", dr[cl.ColumnName].ToString());
}
else if //Today> or Today
(
PreItemConstant != null
&& (
(PreItemConstant.Contains("<") && !PreItemConstant.Contains(">"))
|| (PreItemConstant.Contains("«") && !PreItemConstant.Contains("»"))
)
&& (item.Text.Contains(cl.ColumnName))
)
{
if (item.Text.Contains(">") || item.Text.Contains("»"))
{
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
}
else
{
FindSingleAnglebrackets = true;
}
if (PreItemConstant == "<" || PreItemConstant == "«")
{
PreItem.Text = "";
}
else
{
PreItem.Text = global::System.Text.RegularExpressions.Regex.Replace(PreItemConstant, #"\<" + cl.ColumnName + #"(?!\w)", dr[cl.ColumnName].ToString());
PreItem.Text = global::System.Text.RegularExpressions.Regex.Replace(PreItemConstant, #"\«" + cl.ColumnName + #"(?!\w)", dr[cl.ColumnName].ToString());
}
if (PreItemConstant.Contains("<") || PreItemConstant.Contains("«")) // pre item is like '[blank]«'
{
PreItem.Text = PreItem.Text.Replace("<", "");
PreItem.Text = PreItem.Text.Replace("«", "");
}
if (item.Text.Contains(cl.ColumnName + ">") || item.Text.Contains(cl.ColumnName + "»"))
{
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"(?<!\w)" + cl.ColumnName + #"\>", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"(?<!\w)" + cl.ColumnName + #"\»", dr[cl.ColumnName].ToString());
}
else
{
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"(?<!\w)" + cl.ColumnName + #"(?!\w)", dr[cl.ColumnName].ToString());
}
}
else if (FindSingleAnglebrackets && (item.Text.Contains("»") || item.Text.Contains(">")))
{
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"(?<!\w)" + cl.ColumnName + #"\>", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"(?<!\w)" + cl.ColumnName + #"\»", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"^\s*\>", "");
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"^\s*\»", "");
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
}
else if (item.Text.Contains("<") || item.Text.Contains("«")) // no ColumnName
{
}
} //end of each columns
PreItem = item;
PreItemConstant = item.Text;
if (breakFlag
|| (item.Text.Contains("<") && !item.Text.Contains(">"))
|| (item.Text.Contains("«") && !item.Text.Contains("»"))
)
{
breakFlag = true;
breakedFiled.Add(item);
string combinedfiled = "";
foreach (Text t in breakedFiled)
{
combinedfiled += t.Text;
}
foreach (DataColumn cl in columns)
{
//<Today>
if (combinedfiled.Contains("«" + cl.ColumnName + "»") || combinedfiled.Contains("<" + cl.ColumnName + ">"))
{
//for the first part, remove the last '<' and tailing content
breakedFiled[0].Text = global::System.Text.RegularExpressions.Regex.Replace(breakedFiled[0].Text, #"<\w*$", "");
breakedFiled[0].Text = global::System.Text.RegularExpressions.Regex.Replace(breakedFiled[0].Text, #"<\w*$", "");
//remove middle parts
foreach (Text t in breakedFiled)
{
if (!t.Text.Contains("<") && !t.Text.Contains("«") && !t.Text.Contains(">") && !t.Text.Contains("»"))
{
t.Text = "";
}
}
//for the last part(as current item), remove leading content till the first '>'
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"^\s*\>", dr[cl.ColumnName].ToString());
item.Text = global::System.Text.RegularExpressions.Regex.Replace(item.Text, #"^\s*\»", dr[cl.ColumnName].ToString());
FindSingleAnglebrackets = false;
breakFlag = false;
breakedFiled.Clear();
break;
}
}
}
}//end of each item
#region go through footer
MainDocumentPart mainPart = doc.MainDocumentPart;
foreach (FooterPart footerPart in mainPart.FooterParts)
{
Footer footer = footerPart.Footer;
var allFooterParas = footer.Descendants<Text>();
foreach (Text item in allFooterParas)
{
foreach (DataColumn cl in columns)
{
if (item.Text.Contains("«" + cl.ColumnName + "»") || item.Text.Contains("<" + cl.ColumnName + ">"))
{
item.Text = (string.IsNullOrEmpty(dr[cl.ColumnName].ToString()) ? " " : dr[cl.ColumnName].ToString());
FindSingleAnglebrackets = false;
}
else if (PreItem != null && (PreItem.Text == "<" || PreItem.Text == "«") && (item.Text.Trim() == cl.ColumnName))
{
FindSingleAnglebrackets = true;
PreItem.Text = "";
item.Text = (string.IsNullOrEmpty(dr[cl.ColumnName].ToString()) ? " " : dr[cl.ColumnName].ToString());
}
else if (FindSingleAnglebrackets && (item.Text == "»" || item.Text == ">"))
{
item.Text = "";
FindSingleAnglebrackets = false;
}
}
PreItem = item;
}
}
#endregion
#region replace \v to new Break()
var body = doc.MainDocumentPart.Document.Body;
var paras = body.Elements<Paragraph>();
foreach (var para in paras)
{
foreach (var run in para.Elements<Run>())
{
foreach (var text in run.Elements<Text>())
{
if (text.Text.Contains("MS_Doc_New_Line"))
{
string[] ss = text.Text.Split(new string[] { "MS_Doc_New_Line" }, StringSplitOptions.None);
text.Text = text.Text = "";
int n = 0;
foreach (string s in ss)
{
n++;
run.AppendChild(new Text(s));
if (n != ss.Length)
{
run.AppendChild(new Break());
}
}
}
}
}
}
#endregion
doc.MainDocumentPart.Document.Save();
}
}
public static void MergeDocuments(params string[] filepaths)
{
//filepaths = new[] { "D:\\one.docx", "D:\\two.docx", "D:\\three.docx", "D:\\four.docx", "D:\\five.docx" };
if (filepaths != null && filepaths.Length > 1)
using (WordprocessingDocument myDoc = WordprocessingDocument.Open(#filepaths[0], true))
{
MainDocumentPart mainPart = myDoc.MainDocumentPart;
for (int i = 1; i < filepaths.Length; i++)
{
string altChunkId = "AltChunkId" + i;
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(
AlternativeFormatImportPartType.WordprocessingML, altChunkId);
using (FileStream fileStream = File.Open(#filepaths[i], FileMode.Open))
{
chunk.FeedData(fileStream);
}
DocumentFormat.OpenXml.Wordprocessing.AltChunk altChunk = new DocumentFormat.OpenXml.Wordprocessing.AltChunk();
altChunk.Id = altChunkId;
//new page, if you like it...
mainPart.Document.Body.AppendChild(new Paragraph(new Run(new Break() { Type = BreakValues.Page })));
//next document
mainPart.Document.Body.InsertAfter(altChunk, mainPart.Document.Body.Elements<Paragraph>().Last());
}
mainPart.Document.Save();
myDoc.Close();
}
}
And use them like this:
DataTable dt = new DataTable();
dt.Columns.Add("Date");
dt.Columns.Add("Today");
dt.Columns.Add("Addr1");
dt.Columns.Add("Addr2");
dt.Columns.Add("PreferContact");
dt.Columns.Add("TenantName");
//......
DataRow nr = dt.NewRow();
nr["Date"] = DateTime.Now.ToString("dd/MM/yyyy");
nr["Today"] = DateTime.Now.ToString("dd/MM/yyyy");
//......
dt.Rows.Add(nr);
string sourceFile = "c:\my_template.docx"; //this is where you store your template
string filePath = "c:\final.docx"; //this is where your result file locate
Mailmerge(sourceFile, filePath, nr, dt.Columns);
Your template(c:\my_template.docx) will be just like normal .docx file, and you need to specify your fields in it:
<field>
So, your template(c:\my_template.docx) should be like:
<Today>
<DebtorName>
<DebtorADDR>
<DebtorEmail>
Dear <Dear>,
Congratulations on yourr property <PlanNo> <BuildAddress>. Your unit number is <LotNo> ...............
In addition, if some of your fields contain line breaks, use this:
nr["Address"] = my_address_text_contains_line_breaks.Replace(Environment.NewLine, "MS_Doc_New_Line");
This is quite simple by using Microsoft.Office.Interop.Word. Here is a simple step by step tutorial on how to do this.
The code to replace a mergefield with a string is like this:
public static void TextToWord(string pWordDoc, string pMergeField, string pValue)
{
Object oMissing = System.Reflection.Missing.Value;
Object oTrue = true;
Object oFalse = false;
Word.Application oWord = new Word.Application();
Word.Document oWordDoc = new Word.Document();
oWord.Visible = true;
Object oTemplatePath = pWordDoc;
oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
foreach (Word.Field myMergeField in oWordDoc.Fields)
{
Word.Range rngFieldCode = myMergeField.Code;
String fieldText = rngFieldCode.Text;
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11, endMerge - 11);
fieldName = fieldName.Trim();
if (fieldName == pMergeField)
{
myMergeField.Select();
oWord.Selection.TypeText(pValue);
}
}
}
}
originally posted here and here
In case you wish to use a dictionary to replace many fields at once use the code below:
public static void TextToWord(string pWordDoc, Dictionary<string, string> pDictionaryMerge)
{
Object oMissing = System.Reflection.Missing.Value;
Object oTrue = true;
Object oFalse = false;
Microsoft.Office.Interop.Word.Application oWord = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document oWordDoc = new Microsoft.Office.Interop.Word.Document();
oWord.Visible = true;
Object oTemplatePath = pWordDoc;
oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
foreach (Microsoft.Office.Interop.Word.Field myMergeField in oWordDoc.Fields)
{
Microsoft.Office.Interop.Word.Range rngFieldCode = myMergeField.Code;
String fieldText = rngFieldCode.Text;
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11, endMerge - 11);
fieldName = fieldName.Trim();
foreach (var item in pDictionaryMerge)
{
if (fieldName == item.Key)
{
myMergeField.Select();
oWord.Selection.TypeText(item.Value);
}
}
}
}
}
I am also using the same thing but I have more complexity. I have to check the if condition also. In word template file
{ IF «Installment» = Monthly "then the table will appear" "nothing to show" }
when I use the above code shared in the answer. and for if condition in c# I have written
Range rngFieldCode = myMergeField.Code;
String fieldText = rngFieldCode.Text.Trim();
if (fieldText.ToUpper().StartsWith("IF"))
{
myMergeField.UpdateSource();}
so the output is like
{ IF Monthly = Monthly "then table will appear" "nothing to show" }
but the desired output is only "then the table will appear".
Related
I have a simple PDF file that has the Link and the Footnote on a page. When I run the annotation check using iTextSharp, both of the links return the sub type as Link. Is there a way to tell the difference between those two items?
I did examine through an intellisence the structure of an annotation dictionary and notice the annotation object dictionary for the Footnote has once extra item, which is named "F", and that item has a value of 4. That item is NOT present at all in the annotation dictionary for the Link. Can I use the 'F' item/parameter as a way to tell the difference between the Link and the Footnote?
Thank you very much in advance
Here is the PDF file
Here is our code
public string AnyPDFCheckComments(string inFileName, string strUsername, string strFilename)
{
string strCommentType = string.Empty;
string strWidgetFound = string.Empty;
string strPageNumber = string.Empty;
string message = string.Empty;
string strComments = string.Empty;
string strCommentsFound = string.Empty;
int intCommentCount = 0;
PdfReader reader = new PdfReader(inFileName);
for (int i = 1; i <= reader.NumberOfPages; ++i)
{
strPageNumber = i.ToString();
PdfDictionary pagedic = reader.GetPageN(i);
PdfArray annotarray = (PdfArray)PdfReader.GetPdfObject(pagedic.Get(PdfName.ANNOTS));
if (annotarray == null || annotarray.Size == 0)
{
continue;
}
// Finding out the links
foreach (object annot in annotarray.ArrayList)
{
PdfDictionary annotationDic = null;
if (annot is PdfIndirectReference)
{
annotationDic = (PdfDictionary)PdfReader.GetPdfObject((PdfIndirectReference)annot);
}
else
{
annotationDic = (PdfDictionary) annot;
}
PdfName subType = (PdfName)annotationDic.Get(PdfName.SUBTYPE);
if ((subType.Equals(PdfName.TEXT)) && (strCommentsVariables.IndexOf("text") != -1))
{
strCommentType = "text";
//break;
}
else if ((subType.Equals(PdfName.LINK)) && (strCommentsVariables.IndexOf("Link") != -1))
{
strCommentType = "Link";
//break;
}
if ((strCommentType != ""))
{
strCommentsFound = "Yes";
intCommentCount = ++intCommentCount;
strComments = strComments + "<BR>" + "A comment type of '" + "<b>" + strCommentType + "</b>" + "' has been found on page no: " + "<b>" + strPageNumber + "</b>";
if (intCommentCount == 5)
{
break;
}
else
{
strCommentType = string.Empty;
}
}
}
}
return strComments;
}
This code worked for us
var footnoteIdentifier = annotationDic.Get(PdfName.F);
if (footnoteIdentifier != null)
{
continue;
}
Am tryinng to read PDf and inside PDF controls. my pdf is generated by adobe pdf library. getting null acro fields.but my form have 4 check boxes. 4 check boxed i can use to check or uncheck . i want checkbox is checked or not.
i used itextsharp to read pdf but, it is not finding controls.
private static string GetFormFieldNamesWithValues(PdfReader pdfReader)
{
return string.Join("\r\n", pdfReader.AcroFields.Fields
.Select(x => x.Key + "=" +
pdfReader.AcroFields.GetField(x.Key) + "=" + pdfReader.AcroFields.GetFieldType(x.Key)).ToArray());
}
static void Main(string[] args)
{
DataTable filedDetails;
DataRow dr;
string cName="";
string cType = "";
string cValue = "";
int txtCount = 0;
int btnCount = 0;
int chkBoxCount = 0;
int rdButtonCount = 0;
int dropDownCount = 0;
var fileName = "C:\\PreScreenings\\ViewPDF Cien.pdf";// PDFFileName.Get(context);
//var fileName = #"C:\Users\465sanv\Downloads\Read-PDF-Controls-master\ReadPDFControl\Input\David1990.pdf";
var fields = GetFormFieldNamesWithValues(new PdfReader(fileName));
string[] splitRows = fields.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
filedDetails = new DataTable("PDF Table");
filedDetails.Columns.AddRange(new[] { new DataColumn("Control Name"), new DataColumn("Control Type"), new DataColumn("Control Value") });
foreach (string row in splitRows)
{
dr = filedDetails.NewRow();
string[] str = row.Split("=".ToCharArray(), StringSplitOptions.None);
cName = str[0].ToString();
cValue = str[1].ToString();
if (str[2].ToString() == "1")
{
btnCount++;
cType = "Button" + btnCount.ToString();
}
else if (str[2].ToString() == "2")
{
chkBoxCount++;
cType = "Check Box" + chkBoxCount.ToString();
}
else if (str[2].ToString() == "3")
{
rdButtonCount++;
cType = "Radio Button" + rdButtonCount.ToString();
}
else if (str[2].ToString() == "4")
{
txtCount++;
cType = "Text Field" + txtCount.ToString();
}
else if (str[2].ToString() == "6")
{
dropDownCount++;
cType = "Drop Down" + dropDownCount.ToString();
}
dr[0] = cName;
dr[1] = cType;
dr[2] = cValue;
filedDetails.Rows.Add(dr);
}
}
I wrote c# code to read emails from my gmail account, using openpop.net library, and save them into a database. Everything is going right but it is so slow in loading the emails. I tried a parallel.for loop but it gave the error:
write method can not begin while other write method is running
Is there any way to use parallel processing in this case?
This is my read emails function:
public void Read_Emails()
{
Pop3Client pop3Client;
if (Session["Pop3Client"] == null)
{
pop3Client = new Pop3Client();
pop3Client.Connect("pop.gmail.com", 995, true);
pop3Client.Authenticate(usermail, pwd, AuthenticationMethod.UsernameAndPassword);
Session["Pop3Client"] = pop3Client;
}
else
{
pop3Client = (Pop3Client)Session["Pop3Client"];
}
int count = pop3Client.GetMessageCount();
for (int i = count; i >= 1; i--)
{
Message message = pop3Client.GetMessage(i);
FFromAdress = message.Headers.From.Address;
ddate = message.Headers.DateSent;
MMessageNO = i; //message.Headers.MessageId;
List<MessagePart> attachments = message.FindAllAttachments();
DataTable dt = get_Health_Institutions();
DataTable dt1 = get_INTERIOR_Institutions();
foreach (DataRow row in dt.Rows){health_result = FFromAdress.Equals(row["mail"]);}
foreach (DataRow row in dt1.Rows){interior_result = FFromAdress.Equals(row["mail"]);}
bool result = FFromAdress.Equals("sersersetrerttrtail.com");
if (health_result == true) //|| interior_result == true)
{ SSubject = message.Headers.Subject.Split(':')[1];
MessagePart body = message.FindFirstHtmlVersion();
body = message.FindFirstPlainTextVersion();
if (body != null)
{
string BBody1 = body.GetBodyAsText();
BBody = BBody1.Replace(' ', '\n');
}
if (attachments.Count == 0)
{
atta_count = 0;
AAtachments_Path = SSubject;
if (CHKsubjectexist_Health_Date(SSubject) == 0)
{ insertmail_health_date(FFromAdress, SSubject, ddate, BBody, AAtachments_Path, MMessageNO, atta_count); }
}
else
{ for (int m = 0; m < attachments.Count; m++)
{
atta_count = attachments.Count;
if (health_result == true & interior_result == false)
{ imagename = "healthRESULT_answer" + m+".jpg"; }
Foldername = SSubject.Trim();
AAtachments_Path = Foldername;
byte[] bdata = attachments[m].Body;
string folderpathh = "d:\\asdf\\" + Foldername;
System.IO.Directory.CreateDirectory(folderpathh);
string pathh = folderpathh + "\\" + imagename;
System.IO.File.WriteAllBytes(pathh, bdata);
////write image
String st = Server.MapPath(imagename);
FileStream fs = new FileStream(st, FileMode.Create, FileAccess.Write);
fs.Write(bdata, 0, bdata.Length);
fs.Close();
}
if (CHKsubjectexist_Health_final(SSubject) == 0)
{ insertmail_Health_Final(FFromAdress, SSubject, ddate, BBody, AAtachments_Path, MMessageNO, atta_count); }
}
}
else if (interior_result == true)
{
SSubject = message.Headers.Subject.Split(':')[1];
MessagePart body = message.FindFirstHtmlVersion();
body = message.FindFirstPlainTextVersion();
if (body != null)
{
string BBody1 = body.GetBodyAsText();
BBody = BBody1.Replace(' ', '\n');
}
if (attachments.Count == 0)
{
atta_count = 0;
AAtachments_Path = SSubject;
}
else
{
for (int m = 0; m < attachments.Count; m++)
{
atta_count = attachments.Count;
imagename = "Interior_answer" + m+".jpg";
Foldername = SSubject.Trim();
AAtachments_Path = Foldername;
byte[] bdata = attachments[m].Body;
string folderpathh = "d:\\asdf\\" + Foldername;
// System.IO.Directory.CreateDirectory(folderpathh);
string pathh = folderpathh + "\\" + imagename;
System.IO.File.WriteAllBytes(pathh, bdata);
////write image
String st = Server.MapPath(imagename);
FileStream fs = new FileStream(st, FileMode.Create, FileAccess.Write);
fs.Write(bdata, 0, bdata.Length);
fs.Close();
}
}
if (CHKsubjectexist_Interior(SSubject) == 0)
{ insertmail_interior(FFromAdress, SSubject, ddate, BBody, AAtachments_Path, MMessageNO, atta_count); }
}
else if (result == true)
{
SSubject = message.Headers.Subject;
if (CHKsubjectexist(SSubject) == 0)
{
MessagePart body = message.FindFirstHtmlVersion();
if (body != null)
{
BBody = body.GetBodyAsText();
}
else
{
body = message.FindFirstPlainTextVersion();
if (body != null)
{
BBody = body.GetBodyAsText();
}
}
if (attachments.Count == 0)
{
AAtachments_Path = " ";
}
else
{
foreach (MessagePart attachment in attachments)
{
atta_count = attachments.Count;
string filenameee = attachment.FileName;
imagename = filenameee.Split('/', '/')[3];
Foldername = SSubject;
AAtachments_Path = Foldername;
byte[] bdata = attachment.Body;
string folderpathh = "d:\\asdf\\" + Foldername;
System.IO.Directory.CreateDirectory(folderpathh);
string pathh = folderpathh + "\\" + imagename;
System.IO.File.WriteAllBytes(pathh, bdata);
////write image
String st = Server.MapPath(imagename);
FileStream fs = new FileStream(st, FileMode.Create, FileAccess.Write);
fs.Write(bdata, 0, bdata.Length);
fs.Close();
}
}
if (CHKsubjectexist(SSubject) == 0)
{ insertmail(FFromAdress, SSubject, ddate, BBody, AAtachments_Path, MMessageNO, atta_count); }
}
}
}
}
This is my code which return me attribute values in the selected block,
but I want these values in a table to show on the dwg file. And the text must be single mtext object.
[CommandMethod("NLTAB")]
public void ListAttributes()
{
Document acDoc = Application.DocumentManager.MdiActiveDocument;
Editor ed = acDoc.Editor;
Database db = acDoc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
try
{
TypedValue[] filList = new TypedValue[2] { new TypedValue((int)DxfCode.Start, "INSERT"), new TypedValue((int)DxfCode.HasSubentities, 1) };
SelectionFilter filter = new SelectionFilter(filList);
PromptSelectionOptions opts = new PromptSelectionOptions();
opts.MessageForAdding = "Select block references: ";
PromptSelectionResult res = ed.GetSelection(opts, filter);
// Do nothing if selection is unsuccessful
if (res.Status != PromptStatus.OK)
return;
SelectionSet selSet = res.Value;
ObjectId[] idArray = selSet.GetObjectIds();
PromptPointResult ppr;
PromptPointOptions ppo = new PromptPointOptions("");
ppo.Message = "\n Select the place for print output:";
//get the coordinates from user
ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d startPoint = ppr.Value.TransformBy(ed.CurrentUserCoordinateSystem);
Vector3d disp = new Vector3d(0.0, -2.0 * db.Textsize, 0.0);
TextStyleTable ts = (TextStyleTable)tr.GetObject(db.TextStyleTableId, OpenMode.ForRead);
ObjectId mtStyleid = db.Textstyle;
if (ts.Has("NAL-TEXT"))
{
mtStyleid = ts["NAL-FORMAT"];
}
var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
MText _outputHeading = new MText();
_outputHeading.Location = startPoint;
_outputHeading.Width = 75.207;
_outputHeading.Height = 1.488;
_outputHeading.TextStyleId = mtStyleid;
string file = acDoc.Name;
string str1 = Path.GetFileNameWithoutExtension(file);
//string str1 = ("534-W10A-R1");
//var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
Match match = Regex.Match(str1, #"^(\w+-[CSDWM]\d+[A-Z]-.)$");
var pattern = #"^(\d+)-[A-Z](\d+)([A-Z])-";
var groups = Regex.Match(str1, pattern).Groups;
var _projectCode = groups[1].Value;
var _phaseCode = _projectCode + "-" + groups[2].Value;
var _zoneCode = _phaseCode + groups[3].Value;
curSpace.AppendEntity(_outputHeading);
tr.AddNewlyCreatedDBObject(_outputHeading, true);
db.TransactionManager.QueueForGraphicsFlush();
startPoint += disp;
HashSet<string> attValues = new HashSet<string>();
foreach (ObjectId blkId in idArray)
{
BlockReference blkRef = (BlockReference)tr.GetObject(blkId, OpenMode.ForRead);
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForWrite);
AttributeCollection attCol = blkRef.AttributeCollection;
foreach (ObjectId attId in attCol)
{
AttributeReference attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);
string str = (attRef.TextString);
string tag = attRef.Tag;
if (attValues.Contains(str))
continue;
if (btr.Name == "NAL-TAG crs ref")
{
var curSpace1 = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
MText mtext = new MText();
mtext.Location = startPoint;
mtext.Contents = tag.ToString() + " : " + str + "\n";
//ed.WriteMessage(text);
curSpace.AppendEntity(mtext);
tr.AddNewlyCreatedDBObject(mtext, true);
db.TransactionManager.QueueForGraphicsFlush();
attValues.Add(str);
startPoint += disp;
}
}
}
tr.Commit();
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
ed.WriteMessage(("Exception: " + ex.Message));
}
}
}
To crate a table, at this blog post, you'll find a sample code in C# that should work for you. The result should look like the image below.
And here is the source code. After creating the table, if you really need the texts, you can call .Explode() on it and extract all the text entities.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace TableCreation
{
public class Commands
{
[CommandMethod("CRT")]
static public void CreateTable()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptPointResult pr =
ed.GetPoint("\nEnter table insertion point: ");
if (pr.Status == PromptStatus.OK)
{
Table tb = new Table();
tb.TableStyle = db.Tablestyle;
tb.NumRows = 5;
tb.NumColumns = 3;
tb.SetRowHeight(3);
tb.SetColumnWidth(15);
tb.Position = pr.Value;
// Create a 2-dimensional array
// of our table contents
string[,] str = new string[5, 3];
str[0, 0] = "Part No.";
str[0, 1] = "Name ";
str[0, 2] = "Material ";
str[1, 0] = "1876-1";
str[1, 1] = "Flange";
str[1, 2] = "Perspex";
str[2, 0] = "0985-4";
str[2, 1] = "Bolt";
str[2, 2] = "Steel";
str[3, 0] = "3476-K";
str[3, 1] = "Tile";
str[3, 2] = "Ceramic";
str[4, 0] = "8734-3";
str[4, 1] = "Kean";
str[4, 2] = "Mostly water";
// Use a nested loop to add and format each cell
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 3; j++)
{
tb.SetTextHeight(i, j, 1);
tb.SetTextString(i, j, str[i, j]);
tb.SetAlignment(i, j, CellAlignment.MiddleCenter);
}
}
tb.GenerateLayout();
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
BlockTable bt =
(BlockTable)tr.GetObject(
doc.Database.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
btr.AppendEntity(tb);
tr.AddNewlyCreatedDBObject(tb, true);
tr.Commit();
}
}
}
}
}
I am working with a project where I am generating PDF Files from PSR Files. The PDF Files works fine if its a single page but if It has more than two PSR Files and I generate two files it does not open on iPad and works fine on Desktop.
The Third library tool I am using here is 'dbatuotrack' and I am using C#.
Can anyone please guide me how to resolve this problem?
Thanks,
S.
foreach (var pdfform in pdfPagesID)
{
//dbAutoTrack.PDFWriter.Document objDoc = null;
//dbAutoTrack.PDFWriter.Page objPage = null;
objDoc = new dbAutoTrack.PDFWriter.Document();
pdfPagesID.Clear();
pdfPagesID = GetSpecPageID(pdfform);
if (pdfPagesID.Count > 1)
{
foreach (var pdfPage in pdfPagesID)
{
dbAutoTrack.PDFWriter.Page objPage2 = null;
var lastItem = pdfPagesID.Last();
prefixPageID = prefixSpecPageID(pdfPage);
suffixPageIDPSR = prefixPageID + ".psr";
if (File.Exists(PSRPath + suffixPageIDPSR))
{
objDs = new CDatasheet(this.PSRPath + suffixPageIDPSR, false);
objDs.pdfDbHelper = pdfhelper;
//Giving the specformId as SpecFornName
pdfFormName = "Form" + pdfform + ".pdf";
if (!(pdfPage == pdfPagesID.First()))
{
objPage2 = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage2);
}
else
{
objPage = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage);
}
if (objPage != null)
{
if (pdfWithNotePage == true && pdfPage.Equals(lastItem))
{
objNotePage = objDs.GetNotePage();
objDoc.Pages.Add(objPage);
objDoc.Pages.Add(objNotePage);
}
else
{
//objDoc.Pages.Add(objPage);
//objDoc.Pages.Add(objPage2);
}
fsOutput = new FileStream(TemplatePath + pdfFormName, FileMode.Create, FileAccess.Write);
objDoc.Generate(fsOutput);
}
if (fsOutput != null)
{
fsOutput.Close();
fsOutput.Dispose();
fsOutput = null;
}
}
}
objDoc = null;
objPage = null;
}
This how I tweaked the code to make it work. Thanks for the suggestion DJ KRAZE
foreach (var pdfform in pdfPagesID)
{
//dbAutoTrack.PDFWriter.Document objDoc = null;
//dbAutoTrack.PDFWriter.Page objPage = null;
objDoc = new dbAutoTrack.PDFWriter.Document();
pdfPagesID.Clear();
pdfPagesID = GetSpecPageID(pdfform);
if (pdfPagesID.Count > 1)
{
foreach (var pdfPage in pdfPagesID)
{
dbAutoTrack.PDFWriter.Page objPage2 = null;
var lastItem = pdfPagesID.Last();
prefixPageID = prefixSpecPageID(pdfPage);
suffixPageIDPSR = prefixPageID + ".psr";
if (File.Exists(PSRPath + suffixPageIDPSR))
{
objDs = new CDatasheet(this.PSRPath + suffixPageIDPSR, false);
objDs.pdfDbHelper = pdfhelper;
//Giving the specformId as SpecFornName
pdfFormName = "Form" + pdfform + ".pdf";
if (!(pdfPage == pdfPagesID.First()))
{
objPage2 = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage2);
}
else
{
objPage = objDs.Generate_PDFReport();
objDoc.Pages.Add(objPage);
}
if (objPage != null)
{
if (pdfWithNotePage == true && pdfPage.Equals(lastItem))
{
objNotePage = objDs.GetNotePage();
objDoc.Pages.Add(objPage);
objDoc.Pages.Add(objNotePage);
}
else
{
//objDoc.Pages.Add(objPage);
//objDoc.Pages.Add(objPage2);
}
}
}
}
fsOutput = new FileStream(TemplatePath + pdfFormName, FileMode.Create, FileAccess.Write);
objDoc.Generate(fsOutput);
//This region was the problem, disposing the output everytime.
//Needed it to be included after completion of iteration
if (fsOutput != null)
{
fsOutput.Close();
fsOutput.Dispose();
fsOutput = null;
}
}