1

I have a winForm app written in c# and i have a treeview contains files from a directory. It also contains data about each files (fullpath,creation time,size) it look like this:

This is my treeview

I am trying to export this data to MS-Word template look like this: enter image description here

My problem is to duplicate the mergeFields for each File and to insert each file properties (The number of files changes) in place to look like this:

enter image description here

This is my Code:

private void btnExportWord_Click_1(object sender, EventArgs e)
    {
        object oMissing = Missing.Value;
        Word.Application oWord = new Word.Application();
        Word.Document oWordDoc = new Word.Document();
        oWord.Visible = false;
        oWordDoc = oWord.Documents.Add(ref oMissing, ref oMissing, ref oMissing, ref oMissing);           
        Object oTemplatePath = @"C:\test\MyXMLTemplate.dotx";         
        oWordDoc = oWord.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);

        for (int i = 0; i < treeViewXMLFiles.Nodes[0].Nodes.Count; i++)
        {
            string strFilename = treeViewXMLFiles.Nodes[0].Nodes[i].Text;
            string strFull_path = treeViewXMLFiles.Nodes[0].Nodes[i].Nodes[0].Text;
            string strCreationTime = treeViewXMLFiles.Nodes[0].Nodes[i].Nodes[1].Text;
            string strSize = treeViewXMLFiles.Nodes[0].Nodes[i].Nodes[2].Text;

            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 == "File_Name")
                    {
                        myMergeField.Select();
                        oWord.Selection.TypeText(strFilename);
                    }
                    if (fieldName == "Full_Path")
                    {
                        myMergeField.Select();
                        oWord.Selection.TypeText(strFull_path);
                    }
                    if (fieldName == "CreationTime")
                    {
                        myMergeField.Select();
                        oWord.Selection.TypeText(strCreationTime);
                    }
                    if (fieldName == "Size")
                    {
                        myMergeField.Select();
                        oWord.Selection.TypeText(strSize);
                    }
                }
            }                
        }           
        Object oSaveAsFile = (Object)@"C:\test\FINISHED_XML_Template.doc";            
        oWordDoc.SaveAs(ref oSaveAsFile, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,
ref oMissing, ref oMissing);

        oWordDoc.Close(false, ref oMissing, ref oMissing);
        oWord.Quit(ref oMissing, ref oMissing, ref oMissing);
    }

I'm tying to look for an answer for a long time with no success.
I hope anyone here could help me.

Nissim
  • 31
  • 1
  • 5
  • You seem to have nested the *foreach* loops in wrong order. First, iterate over each treeview node, and for each such node add a new (merged) document. Then, fill the merge fields of that newly added documents with the data from the node. (Currently, you only create **one** merged document and set the merge fields of the same merged document over and over again...) However, it looks like you want to have this all on one page in one document only, correct? –  Apr 16 '14 at 22:15
  • Yes i want to duplicate my merge fields for each file during running. i will try to switch the loope and put the for loop first but still i have a problem with the merge fields – Nissim Apr 17 '14 at 07:33
  • This is my correct code but It fills only the details of the first file and do not duplicate the merge fields for each file – Nissim Apr 17 '14 at 07:44
  • I changed the code above and it work fine now but it fills only the details of the first file and do not duplicate the merge fields for each file which is my main issue. so plz can u help me? – Nissim Apr 17 '14 at 07:54
  • Again, do you want to duplicate the merge fields within the same **single** document (as your pictures suggest), or do you want to have a separate document for each tree node (as your code implies)? If the answer is the former (that is: only one single document), then your given code needs to be altered and expanded substantially. However, if the answer is the latter (separate documents for each treee node), then the code given here would be a right approach - although it still has some issues that need to be worked out... –  Apr 17 '14 at 13:33
  • I want to write all my data at the same document not separated – Nissim Apr 17 '14 at 13:55

1 Answers1

1

If duplicating merge fields in a single document you should do the following:

  1. Create the single target document.

  2. Load the template with the merge field as another document.

  3. In the for (int i = 0; i < treeViewXMLFiles.Nodes[0].Nodes.Count; i++) loop, do the following:

    3.1 Select the content of the template and append it to the target document.

    3.2 Replace(!) the merge fields in the target document(!) with the data from the current treeview node. Note that you need to replace the fields in the target document, so that the fields are gone and just 'plain' text remains. If you don't do that, the for-loop stumbles over the very same fields again during following iterations and messing up previously copied content. (Your code does seem to do the field replacements properly already.)


Any text which should only appear once before or after the sequence with the merge fields (like the "Hello all" introductory phrase, for example) needs to be appended to the target document before/after the for-loop executes.

Keeping these text snippets in separate template files keeps your code comparatively easy, but you will have to deal with up to three template files instead of just a single one. However, after you got substantial experience with programming C# and Word, you might think about an approach allowing you to maintain only a single template. (There are different ways to do that; for example, you might use specific formatting styles in your template to mark content to be duplicated for each treeview node and content which should appear only once in the target document.)

  • It seems like a good advice to load only the merge field to other document each time. Can you help me with the code of there because I dont know how to copy text and mergeFields from one file to another – Nissim Apr 17 '14 at 15:55
  • Sorry, can't help you with particular code since i don't have much experience with the Microsoft.Office.Interop.Word interfaces and neither i have Office Tools for VS installed. But you know already how to manipulate a (selection) range. For adding text to a document, you would just need an (empty) range at the end of the doc to insert the text. A simple way of doing it is to add a Paragraph and insert the text into the paragraph's range (see [here](http://stackoverflow.com/questions/21139450/how-to-add-a-text-in-existing-docx-file-on-desired-location) for some suggestions about how to do it.) –  Apr 17 '14 at 17:08
  • However, don't use the Selection.TypeText method for copying the template content including fields, but rather use the Range.Copy and Range.Paste methods. –  Apr 17 '14 at 17:15