Заменить поле в верхнем и нижнем колонтитуле в Word с помощью Interop

Как заменить "FIELD" в верхнем/нижнем колонтитуле?

Пример: файл документа Word с именем файла и датой. вместо пути к файлу - [FilePath] вместо C://Documents/Location/Filename.doc, [Date] вместо 18/07/2013.

Я могу заменить любой текст с диапазоном.

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]"); 
}

Это отлично подходит для имени файла, однако для даты невозможно угадать формат для замены. Это все потому, что я не могу уловить точную информацию о поле, которую нужно заменить.

В приведенном ниже коде также я не могу использовать

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);

Единственный способ, который я вижу на данный момент, - это обработать все возможные форматы дат и заменить, но это не похоже на хороший подход ко мне.

Обновление в соответствии с комментарием, заданным с помощью Storyrange.

Не дает мне точной информации о поле, говорящей [DATE]. Когда я повторяю диапазон сюжетов, информация о типе, которую я получаю wdstorytype, который содержит информацию о разделе, nt о информации о поле.

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:  Выглядит то, что помогает мне здесь, но, похоже, не работает. Любая идея, как я могу заставить объект документа использовать ниже перед экспортом.

field.ShowCodes = true;

Ответ 1

Наконец, пройдя через плохую документацию по introp.word, получил решение

// 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]");

            }
        }
    }
}

Ответ 2

Джей,

Может быть, немного поздно, но в любом случае...

Не могу комментировать, поэтому я отвечаю.

Немногие вещи, хотя я могу быть полезен вам (или другим) в один прекрасный день с точки зрения текущего принятого ответа.

  • Чтобы ответить на ваш вопрос из последнего Обновить, вы можете использовать что-то вроде этого, чтобы включить коды полей, а затем использовать "Найти" для поиска полей:

    wordDocument.ActiveWindow.View.ShowFieldCodes = true;
    

    Итак, вы должны включить это, прежде чем искать (если уже на нем уже) и восстановить его, когда закончите.

  • Решение, которое вы предоставили себе, будет работать для большинства сценариев, и я использовал что-то подобное в течение некоторого времени. Однако я столкнулся с документом с 2000 разделами. И цикл через эти разделы будет, в свою очередь, проходить через одни и те же заголовки снова и снова. В моем случае обработка документа вычеркнута (с учетом допустимого времени обработки)

  • решение с StoryRanges может быть лучшим подходом (в сочетании с кодами полей переключения)
    Некоторые примеры его использования (общий поиск и замена):
    http://word.mvps.org/faqs/customization/ReplaceAnywhere.htm
    https://wls.wwco.com/blog/2010/07/03/find-and-replace-in-word-using-c-net/

  • Одна вещь, которую нужно помнить: не забывайте искать вещи в Shapes of Range

  • Я думаю, вы поняли, как заменить поле. В любом случае, я фактически конвертирую простой текст в поле.

    Как только Find.Execute ударит что-то, диапазон будет выбран, и я сделаю

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

TL; DR: Если ваши документы предсказуемы в формате и имеют только небольшое количество разделов, а текст не находится в пределах форм, не беспокойтесь обо всем этом.

Ответ 3

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 - это объект "MSWord.Document", который имеет текущий документ, т.е.

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);

Затем примените цикл к "Разделам" текущего объекта oDoc. Основываясь на разделах, вы получите диапазон нижнего колонтитула. Тогда вы сможете найти и заменить текст в нижнем колонтитуле.