Добавление существующего пользовательского свойства не обновляет документ

#c# #.net #docx

#c# #.net #docx

Вопрос:

На самом деле я использую библиотеку «DocX» для создания документа Word (2007 ) из .Net. Что хорошо, так это то, что он может использовать шаблон «docx» для воссоздания или обновления документа.

Проблема: когда я «AddCustomProperty (…)«, это не обновляет документ word. На самом деле мне нужно открыть его, а затем выбрать все и нажать F9. Мне было интересно, есть ли способ автоматического обновления «пользовательских свойств» с использованием библиотеки DocX.

Чтобы воспроизвести мою проблему, вы можете выполнить следующие шаги:

  1. Откройте «образец», доступный в проекте DocX.
  2. Запустите его один раз (это создаст файлы в debug docs)
  3. Откройте шаблон счета, а затем добавьте строку (с текстом или без текста) и сохраните файл
  4. Повторно запустите тот же пример проекта (он будет использовать существующий шаблон)
  5. Откройте результат счета. Когда вы это сделаете, вы увидите, что таблица была создана, НО все остальные поля не были обновлены, пока вы не выберете все, а затем не нажмете CTRL F9

Если у кого-нибудь есть решение, я бы с удовольствием хотел услышать об этом.

(Примечание: я не хочу, чтобы взаимодействие с MS Word)

Проект и образцы доступны по адресу:http://docx.codeplex.com /

Ответ №1:

Проблема заключается в том, что мы используем MS Word (я использую версию 2010), а затем мы изменяем шаблон и сохраняем его. Это изменяет то, что содержит документ.

Вот что мы имеем при первом создании шаблона с использованием DocX:

 <w:fldSimple w:instr="DOCPROPERTY company_name * MERGEFORMAT" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:r>
    <w:t>
      <w:rPr>
        <w:b />
        <w:sz w:val="24" />
        <w:szCs w:val="24" />
        <w:color w:val="1F497D" />
      </w:rPr>Company Name</w:t>
  </w:r>
</w:fldSimple>
  

И когда мы редактируем с помощью Word (добавляем строку разрыва или какой-либо текст) и сохраняем его, он перезаписывает fldSimple на что-то вроде этого:

 <w:p w:rsidR="006D64DE" w:rsidRDefault="006B25B1">
        <w:r>
          <w:fldChar w:fldCharType="begin" />
        </w:r>
        <w:r>
          <w:instrText>DOCPROPERTY company_name * MERGEFORMAT</w:instrText>
        </w:r>
        <w:r>
          <w:fldChar w:fldCharType="separate" />
        </w:r>
        <w:r>
        <w:rPr>
           <w:b />
          <w:color w:val="1F497D" />
          <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  <w:t>Company Name</w:t>
  </w:r>
  ...
  <w:r>
    <w:rPr>
      <w:b />
      <w:color w:val="1F497D" />
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
    <w:fldChar w:fldCharType="end" />
  </w:r>
</w:p>
  

Вместо того, чтобы ждать, пока кто-нибудь исправит проблему, я просто попытался сделать первый набросок реализации. Я фактически модифицировал метод UpdateCustomPropertyValue(…) . Я фактически добавил код первого foreach. Второй foreach уже был там, и это применимо к документу, созданному из DocX.

  internal static void UpdateCustomPropertyValue(DocX document, string customPropertyName, string customPropertyValue)
        {
            foreach (XElement e in document.mainDoc.Descendants(XName.Get("instrText", w.NamespaceName))) 
            {
                string attr_value = e.Value.Replace(" ", string.Empty).Trim();
                string match_value = string.Format(@"DOCPROPERTY  {0}  * MERGEFORMAT", customPropertyName).Replace(" ", string.Empty);

                if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase))
                {
                    XNode node = e.Parent.NextNode;
                    bool found = false;
                    while (true)
                    {
                        if (node.NodeType == XmlNodeType.Element)
                        {
                            var ele = node as XElement;
                            var match = ele.Descendants(XName.Get("t", w.NamespaceName));
                            if (match.Count() > 0)
                            {
                                if (!found)
                                {
                                    match.First().Value = customPropertyValue;
                                    found = true;
                                }
                                else
                                {
                                    ele.RemoveNodes();
                                }
                            }
                            else
                            {
                                match = ele.Descendants(XName.Get("fldChar", w.NamespaceName));
                                if (match.Count() > 0)
                                {
                                    var endMatch = match.First().Attribute(XName.Get("fldCharType", w.NamespaceName));
                                    if (endMatch != null amp;amp; endMatch.Value == "end")
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        node = node.NextNode;
                    }
                }
            }

            foreach (XElement e in document.mainDoc.Descendants(XName.Get("fldSimple", w.NamespaceName))) 
            {
                string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim();
                string match_value = string.Format(@"DOCPROPERTY  {0}  * MERGEFORMAT", customPropertyName).Replace(" ", string.Empty);

                if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase))
                {
                    XElement firstRun = e.Element(w   "r");
                    XElement firstText = firstRun.Element(w   "t");
                    XElement rPr = firstText.Element(w   "rPr");

                    // Delete everything and insert updated text value
                    e.RemoveNodes();

                    XElement t = new XElement(w   "t", rPr, customPropertyValue);
                    Novacode.Text.PreserveSpace(t);
                    e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
                }
            }
}