Mancy
Mancy

Reputation: 123

Place a custom table in word document programmatically usin openxml dll

I am creating a mail merge document using OpenXML dll. I have a requirement to add a dynamic table to the word document. Currently I have been able to add the table @ the end of the document but I need to add it some where in the middle of the page. I have 4 pages in the word document and this table has to be added to the start of the 3rd page. I have been able to get the table. The only issue that I have is to add the table here. The following is the code:

void createTemplate(string newFileName,string folderName,ArrayList mailMergeList,DataTable observations) 
    {
        FileInfo newFile = new FileInfo(newFileName);
        if (!IsFileLocked(newFile))
        {
            //declare and open a Word document object                
            WordprocessingDocument objWordDocx = WordprocessingDocument.Open(newFileName, true);
            //get the main document section of the document
            OpenXmlElement objMainDoc = objWordDocx.MainDocumentPart.Document;

            //var wordDoc = new Microsoft.Office.Interop.Word.Document();

            //Loop through merge fields
            string FieldDelimiter = " MERGEFIELD ";

            foreach (FieldCode field in objWordDocx.MainDocumentPart.RootElement.Descendants<FieldCode>())
            {
                var fieldNameStart = field.Text.LastIndexOf(FieldDelimiter, System.StringComparison.Ordinal);                    
                String fieldname = field.Text.Substring(fieldNameStart + FieldDelimiter.Length).Trim();
                fieldname = fieldname.Substring(0, fieldname.IndexOf(' '));                    
                //  fieldname
                var fieldValue = "";

                fieldValue = GetMergeValue(fieldname, mailMergeList);

                // Go through all of the Run elements and replace the Text Elements Text Property
                foreach (Run run in objWordDocx.MainDocumentPart.Document.Descendants<Run>())
                {
                    foreach (Text txtFromRun in run.Descendants<Text>().Where(a => a.Text == "«" + fieldname + "»"))
                    {
                        if (fieldname.Equals("ObservationsTable"))
                        {
                            //observations
                            if (observations.Rows.Count > 0) //only if there is data in the Resi Obs NOI sheet we need to create a table
                            {
                                txtFromRun.Text = CreateTable(objWordDocx, newFileName, observations).ToString();
                            }
                        }
                        else
                        {
                            txtFromRun.Text = GetMergeValue(fieldname, mailMergeList);
                        }
                    }
                }
            }
            //save this part
            objWordDocx.MainDocumentPart.Document.Save();
            //save and close the document
            objWordDocx.Close();
        }
    }

I have been given a solution below but it is not feasible for me as I am not using Word.Interop dll.

Please guide.

Upvotes: 1

Views: 2262

Answers (2)

Alex
Alex

Reputation: 626

Here's an open xml example. I created a dummy table:

var tab = new Table();

for (var z = 0; z < 2; z++)
{
    var tr = new TableRow();

    for (var j = 0; j < 2; j++)
    {
       var tc = new TableCell();
       tc.Append(new Paragraph(new Run(new Text("i: " + z + " j:" + j))));
       tr.Append(tc);
    }

    tab.Append(tr);
}

In my word.docx I have:

Some text «Table» some other text

And to loop over the merge fields:

WordprocessingDocument objWordDocx = WordprocessingDocument.Open(newFileName, true);
OpenXmlElement objMainDoc = objWordDocx.MainDocumentPart.Document;

foreach (var field in objMainDoc.Descendants<SimpleField>())
{
    if (field.Instruction.Value.Trim().EndsWith("Table"))
    {
        var tabRun = new Run(tab);
        field.Parent.ReplaceChild<SimpleField>(tabRun, field);
    }
}

objWordDocx.MainDocumentPart.Document.Save();
objWordDocx.Close();

EDIT: Version with FieldCode:

foreach (var field in objMainDoc.Descendants<FieldCode>())                
{
    if (field.InnerText.Trim().EndsWith("Table"))
    {
        var tabRun = new Run(tab);
        var anc = field.Ancestors<Paragraph>().FirstOrDefault();
        anc.RemoveAllChildren();
        anc.Append(tabRun);
    }
}

Note: this works for me as the only thing in my paragrah is the field code. If you have stuff in your paragraph which shouldn't be removed, modify the code.

Upvotes: 3

Alex
Alex

Reputation: 626

In your document (wordDoc below) add a mergefield, "CustomTable" for example.

Object oMissing = System.Reflection.Missing.Value;
Object oTemplatePath = templatePath; // Path
var wordApp = new Microsoft.Office.Interop.Word.Application();
var wordDoc = new Microsoft.Office.Interop.Word.Document();
wordDoc = wordApp.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);

foreach (Field field in wordDoc.Fields)
{
    var fieldText = field.Code.Text;
    var fieldName = fieldText.Substring(11).Split(new string[] { "\\" }, StringSplitOptions.None)[0].Trim();
    field.Select();

    if (fieldText.StartsWith(" MERGEFIELD"))
    {
        if (fieldName == "CustomTable")
        {
            var tab = wordDoc.Tables.Add(wordApp.Selection.Range, noOfColumns, noOfRows);

            tab.Cell(1, 1).Range.Text = "Some text";
            // ETC
        }
    }
}

Upvotes: 1

Related Questions