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
Related
I have a scenario where I have to replace the certain variables from slide template with tabular data but in this case data and slide text is overlapping and after some research I found out that PowerPoint is not designed for such cases [MS Link] (img 1). To overcome this I though instead of replacing the variables with tabular data, I should replace the variable with the link which will point the newly created slide where I can post my tabular data (img 2).
So come back to my question, Is there any way I can write the data without messing the template? OR How can I replace the variable with the hyperlink to the slide?
According to the Documentation you can do something like this, just adjust to your case and how to find the variable1.
// Open the presentation file as read-only.
using (PresentationDocument document = PresentationDocument.Open(fileName, false))
{
// Iterate through all the slide parts in the presentation part.
foreach (SlidePart slidePart in document.PresentationPart.SlideParts)
{
IEnumerable<Drawing.HyperlinkType> links = slidePart.Slide.Descendants<Drawing.HyperlinkType>();
// Iterate through all the links in the slide part.
foreach (Drawing.HyperlinkType link in links)
{
// Iterate through all the external relationships in the slide part.
foreach (HyperlinkRelationship relation in slidePart.HyperlinkRelationships)
{
// If the relationship ID matches the link ID…
if (relation.Id.Equals(link.Id))
{
// Add the URI of the external relationship to the list of strings.
ret.Add(relation.Uri.AbsoluteUri);
}
}
}
}
}
I need to import a Word document by parts and store in a DB. The following code works well with paragraphs, but other items like Tables, images are missing.
foreach (Word.Paragraph item in this.oDoc.Paragraphs)
{
r = item.Range;
r.Copy();
SaveInDB();
}
I need to keep the document order of paragraphs,tables,etc. as they appear so I cannot process each separately unless there were some way to check the order of each item.
I have some VBA code that iterates through a document to remove tables from a document. The following code works fine in VBA:
Set wrdDoc = ThisDocument
With wrdDoc
For Each tbl In wrdDoc.Tables
tbl.Select
Selection.Delete
Next tbl
End With
Unfortunately, I cannot easily translate this code to C#, presumably because there is a newer Range.Find method. Here are three things I tried, each failing.
First attempt (re-write of the VBA code):
foreach (var item in doc.Tables)
{
item.Delete; //NOPE! No "Delete" function.
}
I tried this:
doc = app.Documents.Open(sourceFolderAndFile); //sourceFolderAndFile opens a standard word document.
var rng = doc.Tables;
foreach(var item in rng)
{
item.Delete; //NOPE! No "Delete" function.
}
I also tried this:
doc = app.Documents.Open(sourceFolderAndFile); //sourceFolderAndFile opens a standard word document.
var rng = doc.Tables;
Range.Find.Execute(... //NOPE! No Range.Find available for the table collection.
...
Could someone please help me understand how I can use C# and Word Interop (Word 2013 and 2016) to iterate through a document, find a table, and then perform a function, like selecting it, deleting it, or replacing it?
Thanks!
It took me some time to figure this answer out. With all the code samples online, I missed the need to create an app. For posterity, here is how I resolved the problem.
Make sure you have a Using statement, like this:
using MsWord = Microsoft.Office.Interop.Word;
Open the document and then work with the new msWord reference, the range, and the table. I provide a basic example below:
//open the document.
doc = app.Documents.Open(sourceFolderAndFile, ReadOnly: true, ConfirmConversions: false);
//iterate through the tables and delete them.
foreach (MsWord.Table table in doc.Tables)
{
//select the area where the table is located and delete it.
MsWord.Range rng = table.Range;
rng.SetRange(table.Range.End, table.Range.End);
table.Delete();
}
//don't forget doc.close and app.quit to clean up memory.
You can use the Range (rng) to replace the table with other items, like text, images, etc.
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).
i am working with c# on VS 2013. in my program, i want to get a word file as an input from to an openfiledialog. then i want to access into it and extract the tables which exist on it and finally, store them into a datagridview.
please i need a Tutorial to follow.
Thank you!!
I presume you are working with OpenXML SDK.. In that case maybe something like that will give you access to all of the tables:
Body body = doc.MainDocumentPart.Document.Body;
foreach (Table t in body.Descendants<Table>())
{
...
}
See this as well: https://msdn.microsoft.com/en-us/library/office/cc850835(v=office.14).aspx