I have to merge 2 pdfs forms into one. The input pdfs have fillable fields, and the output should also have the same fields. I was able to achieve this, but, when I merge PDFs with same value for fields, only the first field is coming aas a field and second one is flattened. (Lets say pdf 1 has fields 'Name' and 'Comment1'; pdf 2 has fields, 'Name' and 'Comment2'; when I merge, in the output pdf, 2nd 'Name' field is flattend.)
_stamp = new PdfStamper(_reader, pdfStream);
AcroFields fields = _stamp.AcroFields;
if (!(fields == null))
{
_stamp.FormFlattening = false;
}
_stamp.Close();
_stamp = null;
In your code, you are using PdfStamper. That's a class to fill out forms, not to merge them. Merging forms is done using PdfCopy:
public void createPdf(String filename, PdfReader[] readers) throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(filename));
copy.setMergeFields();
document.open();
for (PdfReader reader : readers) {
copy.addDocument(reader);
}
document.close();
for (PdfReader reader : readers) {
reader.close();
}
}
You can find the full code samples here. You'll have to adapt it to C# (the method names are slightly different, but the code is similar).
It is very important that you don't forget to tell PdfCopy that you want to merge the fields, otherwise the form will not be copied.
You explain that you have a field named Name in one PDF and a field named Name in the other. If you merge both forms, this will result in a single field Name with only one value. You can't have a field Name on one page with one value and a field Name on another page with another value. That's why we also provide a sample where the fields are renamed. You can find that example here. You probably don't need that example; I'm only adding it for the sake of completeness.
Related
I'm trying to read all the tables from a word file into a list, although for some reason the count is 0 regardless of how many tables are in the file. Here's my code.
public void FindAndReplace(string DocPath)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(DocPath, true))
{
using (StreamReader reader = new StreamReader(doc.MainDocumentPart.GetStream()))
{
//Text titlePlaceholder = doc.MainDocumentPart.Document.Body.Descendants<Text>().Where((x) => x.Text == "Compliance Review By:").First();
List<Table> tables = doc.MainDocumentPart.Document.Descendants<Table>().ToList();
System.Console.WriteLine(tables.Count);
tables.Count = 0. What am I doing wrong?
If all you're trying to do is READ the tables, then there's no need to open the document for editing (which is what you're doing currently)
Set the second parameter to false in WordprocessingDocument.Open() to open for reading. This will prevent the error related to opening an entry more than once in Update mode (I assume that's what you're running into anyway).
Solution based on chatter
The real culprit here has to do with using the wrong OpenXml namespace when examining tables in the document. When looking for Descendants of type Table, the passed-in type must be OpenXml.Wordprocessing.Table, NOT OpenXml.Drawing.Table
I don't know what type of object the OpenXml.Drawing.Table is used for. I'll ask about this in a separate question.
You probably are referencing a wrong Table. This should work:
var tables = doc.MainDocumentPart.Document.Descendants<DocumentFormat.OpenXml.Wordprocessing.Table>().ToList();
Anu start had the answer in the comments. The problem was that I was using an incorrect namespace. Instead of using DocumentFormat.OpenXml.Wordprocessing.Table I was using DocumentFormat.OpenXml.Drawing.Table
I have a word document template which contains several form fields that need to be filled using c# code.
below is the document image
The code below is used to reach and fill the document form fields,
But when i reach the table sections sometimes the rows need to be filled are more than what is pre defined inside the template.
red marked area is the table which i want to fill it with data and create as many rows as needed.
the code i use for filling the data is
string fileName = Path.GetTempFileName();
File.WriteAllBytes(fileName, Properties.Resources.DocumentTemplate);
Word.Application word = new Word.Application();
Word.Document doc = new Word.Document();
doc = word.Documents.Add(fileName);
doc.Activate();
doc.FormFields["file_num"].Range.Text = "some text";
doc.FormFields["fam_size"].Range.Text = "another text";
doc.FormFields["nationality"].Range.Text = "another text";
for(int i =0; i< rowsInDatabaseCount; i++)
{
//i don't know how to add row and reach each form field inside
}
I hope someone can help me on how to achieve what i want.
Thank you in advance...
There are multiple ways to handle that.
1) Since the data is coming from a database, one way is to use InsertDatabase method.
2) You could insert the block as tab or comma separated text then convert to a table using ConvertToTable() method.
3) You might use Rows and Cols collections (of Table) and .Add method to add new rows.
4) You might instead create your template as an XSL and transform data (XML) using that XSL to generate final HTM. Word is able to open an HTM file.
(All these options worked for me in "resume", "test results" ... creations which have similar layouts to the ones you gave. I found final option 4 to be the most dynamic one, where end users could define their own templates using simple HTML editors - worked better than word templates for me).
Hello I am automating a word document from a winforms application using c#. The document contains a number of mail merge fields that I fill from my code. This works fine for fixed fields.
However the document contains a few recurring sections that are repeated n times at run time. Can someone tell me how to create a block of some sort that can be inserted multiple times?
I have tried inserting the text between two bookmarks however this messes up the page formatting.
Any advice would be much appreciated.
Edit:
The function below is what I use to merge the data on to the word template. The Dictionary holds the field name in the first string and the content in the second.
The user is given a sample word template with all the field codes in the document and is then able to change the order of the fields and the styling on his own.
public static void CreateBody(Application wApp, Document wDoc, Dictionary<string, string> fieldContent)
{
//Loop through fields in document body.
foreach (Field mergeField in wDoc.Fields)
{
//Find mailmerge fields in the Word document body.
if (mergeField.Type == WdFieldType.wdFieldMergeField)
{
//Get the fieldName from the template file.
string fieldText = mergeField.Code.Text;
string fieldName = GetFieldName(fieldText);
if (fieldContent.ContainsKey(fieldName))
{
mergeField.Select();
if (fieldContent[fieldName] != "")
{
wApp.Selection.TypeText(fieldContent[fieldName]);
}
else
{
//If the field has no content remove the field text from the word file.
wApp.Selection.TypeText(" ");
}
}
}
}
Now I am looking for a way to repeat a block of mail merge fields in the template and have them be inserted multiple times, once for each record.
Here is MSDN link which help you to resolve your issue.
Building a Word Document Using SQL Server Data
When I run the following code on a .docx file the child2.innerText will print out the information I am after (although without seperating text from the seperate columns of the table).
My problem is that the associated innerXml is completely incomprehensible for me. I thought that there would be an 'get cell from table' method or such. I have literally no idea how to extract columns/rows from the xml I've been given though.
I'm completely new to C#, so I might be missing something obvious.
I am using the openxml and the file is .docx.
using (WordprocessingDocument wdoc = WordprocessingDocument.Open(pathToMiniToktrapport, false))
{
var table = wdoc.MainDocumentPart.Document.Body.Elements<Table>();
foreach (var child in table)
{
foreach (var child2 in child) {
System.Console.WriteLine(child2.InnerXml);
System.Console.WriteLine(child2.InnerText);
System.Console.ReadLine();
}
}
}
Thanks!
Please go through the link in MSDN which shows the typical structure and sample code
http://msdn.microsoft.com/en-us/library/office/cc850835.aspx
So I have been working on this ppt add-in. I have been saving strings mostly using the tags hash and it has worked fine thus far; however, now I need to essentially save a 2D array to the presentation. I chose the use the datagridview component and placed it in a new form.
Once the user inputs his data and the form is ready to close I have no idea where to save the grid. I essentially would like to access it later as a 2D array of some sort (there are probably easier ways to access this data); however, first I need to save it to the presentation some how.
Does powerpoint just serialize the entire presentation object and save it entirely? In this case can I just do something like:
PowerPoint.Presentation preso = Globals.ThisAddIn.Application.ActivePresentation;
preso.myGrid = theGridViewFromTheForm;
Or something along those lines?
Ideas?
I simply saved everything using Tags. I suppose you can save things in other ways that aren't so obvious.
There are two option to save data of datagridview.
First using serialize class
second using Datatable.
Second solution:
Serialize your datatable in text and save it into presentation or slide tag.
public static string TableToString(this DataTable data)
{
string xmlString = string.Empty;
using (TextWriter writer = new StringWriter())
{
data.WriteXml(writer,XmlWriteMode.WriteSchema );
xmlString = writer.ToString();
}
return xmlString;
}