12
votes

How to replace a "FIELD" in the header/footer?

Ex: Word doc file with File Name & Date. in place of file path - [FilePath] instead C://Documents/Location/Filename.doc ,[Date] instead 18/07/2013.

I can replace any text with range.

foreach (Microsoft.Office.Interop.Word.Section section in wordDocument.Sections)
{
   section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.Text.Replace(sourceDocPath, "[File Path]");

   section.Footers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.Text.Replace(sourceDocPath, "[File Path]"); 
}

This works fine for The Filename, however for Date, it is not possible to guess the format to replace. This is all because I'm not able to catch the exact field info to replace.

The below code also I can't use

wordApp.Selection.Find.Execute(ref textToReplace, ref typeMissing, 
        ref typeMissing, ref typeMissing, ref typeMissing, ref typeMissing, 
        ref typeMissing, ref typeMissing, ref typeMissing, ref typeMissing, 
        ref replaceTextWith, ref replaceAll, ref typeMissing, ref typeMissing, 
        ref typeMissing, ref typeMissing);

Only way that I see as of now is handle all possible date formats and replace,but this doesn't seems like a good approach to me.

Update as per the comment given using Storyrange.

Doesn't give me the exact Field information saying [DATE].When I iterate through story range the type info I'm getting wdstorytype which is about section information, nt about the field information.

foreach (Microsoft.Office.Interop.Word.Range tmpRange in wordDocument.StoryRanges)
                    {
                        string strtype = tmpRange.StoryType.ToString();
                        tmpRange.Find.Text = "18/07/2013";
                        tmpRange.Find.Replacement.Text = "";
                        tmpRange.Find.Replacement.ParagraphFormat.Alignment =
                            Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphJustify;

                        tmpRange.Find.Wrap = Microsoft.Office.Interop.Word.WdFindWrap.wdFindContinue;
                        object replaceAll = Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll;

                        tmpRange.Find.Execute(ref missing, ref missing, ref missing,
                            ref missing, ref missing, ref missing, ref missing,
                            ref missing, ref missing, ref missing, ref replaceAll,
                            ref missing, ref missing, ref missing, ref missing);
                    }

Update: Looks something that helps me here, but doesn't seems to be working. Any idea how can i force the document object use the below before export.

field.ShowCodes = true;
3
File name is with Path. I'm using this before exporting into XPS. I don't want to change the initial document which is opened with read only.Jay
It sounds as if you want to replace the fields by their results, perhaps selectively. If so, you need to iterate through the collection of fields in the given StoryRange, check the field type, and use .Unlink on those fields where you want the result instead (e.g., perhaps you do not want to replace { PAGE } by its result). Otherwise, it's not clear what you want to replace date fields with, exactly.user1379931
@bibadiak updated the question with your approach, even no luck.am I missing anything here!!Jay

3 Answers

14
votes

Finally after going through the poor documentation about introp.word, got the solution

// Loop through all sections
foreach (Microsoft.Office.Interop.Word.Section section in wordDocument.Sections) {

    wordDocument.TrackRevisions = false; //Disable Tracking for the Field replacement operation

    //Get all Headers
    Microsoft.Office.Interop.Word.HeadersFooters headers = section.Headers;

    //Section headerfooter loop for all types enum WdHeaderFooterIndex. wdHeaderFooterEvenPages/wdHeaderFooterFirstPage/wdHeaderFooterPrimary;                          
    foreach (Microsoft.Office.Interop.Word.HeaderFooter header in headers)
    {
        Fields fields = header.Range.Fields;

        foreach (Field field in fields)
        {
            if (field.Type == WdFieldType.wdFieldDate)
            {
                field.Select ();
                field.Delete ();
                wordApplication.Selection.TypeText ("[DATE]");
            }
            else if (field.Type == WdFieldType.wdFieldFileName)
            {
                field.Select ();
                field.Delete ();
                wordApplication.Selection.TypeText ("[FILE NAME]");

            }
        }
    }

    //Get all Footers
    Microsoft.Office.Interop.Word.HeadersFooters footers = section.Footers;

    //Section headerfooter loop for all types enum WdHeaderFooterIndex. wdHeaderFooterEvenPages/wdHeaderFooterFirstPage/wdHeaderFooterPrimary; 
    foreach (Microsoft.Office.Interop.Word.HeaderFooter footer in footers)
    {
        Fields fields = footer.Range.Fields;

        foreach (Field field in fields)
        {
            if (field.Type == WdFieldType.wdFieldDate)
            {
                field.Select ();
                field.Delete ();
                wordApplication.Selection.TypeText ("[DATE]");
            }
            else if (field.Type == WdFieldType.wdFieldFileName)
            {
                field.Select ();
                field.Delete ();
                wordApplication.Selection.TypeText ("[FILE NAME]");

            }
        }
    }
}
3
votes

Jay,

Maybe a bit late but anyway ...

Can't comment so I answer.

Few things I though may be useful to you (or others) one day in terms of current accepted answer.

  1. To answer your question from the last Update, you can use something like this to turn on field codes and then use Find to search for fields stuff:

    wordDocument.ActiveWindow.View.ShowFieldCodes = true;
    

    So, you would turn that ON before searching (unless on already) and restore it back when you are done.

  2. The solution you provided to yourself will work for most scenarios and I used something like that for some time. However, I bumped into a document with 2000 sections. And looping through those sections will in turn loop through the same header(s) over and over again. In my case processing the document timed out (given the acceptable processing time)

  3. the solution with StoryRanges might be a better approach (combined with switching field codes)
    Some examples of using it (generic search & replace):
    http://word.mvps.org/faqs/customization/ReplaceAnywhere.htm
    https://wls.wwco.com/blog/2010/07/03/find-and-replace-in-word-using-c-net/

  4. One thing to remember: don't forget to search for things in Shapes of Range

  5. I guess you figured out how to replace the field. In any case, I am actually converting simple text to a field.

    Once Find.Execute has hit something, the range will be selected and I do

    theDoc.Fields.Add(range, WdFieldType.wdFieldDocVariable, "myDocVar");
    

TL;DR: If your documents are predictable in format and only have a small number of sections and text is not within shapes then don't worry about all this.

1
votes
object replaceAll = MSWord.WdReplace.wdReplaceAll;
foreach (Microsoft.Office.Interop.Word.Section section in oDoc.Sections)
{
    Microsoft.Office.Interop.Word.Range footerRange =  section.Footers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
    footerRange.Find.Text = "Some Text";
    footerRange.Find.Replacement.Text = "Replace Text";
    footerRange.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref replaceAll, ref missing, ref missing, ref missing, ref missing);
}

oDoc is a "MSWord.Document" object which has current doc i.e.

oDoc = oMSWord.Documents.Open(ref "DocPath", ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);

Then apply loop on "Sections" of current oDoc object. Based on "Sections" you will get range of Footer. Then you will able to find and replace the text in Footer.