none
Microsoft Office Interop Word Issue RRS feed

  • Question

  • Hello,

    I have documents with Conditional statements and merge fields.
    I am trying to change the logic of the conditions to be true or false , and then update the fields.
    The result of the Field may contains text ,Merge Fields, table ,.....

    The issue appear if the result has a formatted text (table format or Bold,Italic text). the format will be removed form the generated document after updating the fields.

    Attached you will find example of the issue:

    static void Main(string[] args)
            {
                //Document Name will be passed as parameter
                try
                {                 
    
                    Object oMissing = System.Reflection.Missing.Value;
                    string templateName = "Sample1.docx";
                    string templateSourceDirectory = "c:\\DocSamples\\";
                    string templateDestinationDirectory = "c:\\DocSamples\\DocSamplesBlank\\";
    
                    Object sourceTemplate = string.Format("{0}{1}", templateSourceDirectory, templateName);
                     
                    Object destinationBlankTemplate = string.Format("{0}{1}", templateDestinationDirectory, templateName);
    
                    Microsoft.Office.Interop.Word.Application wordApp = new Application();
    
                    Document wordDoc = new Document();
    
                    wordDoc = wordApp.Documents.Add(ref sourceTemplate, ref oMissing, ref oMissing, ref oMissing);                              
                     
                    foreach (Field myMergeField in wordDoc.Fields)
                    {
                        
                        Range rngFieldCode = myMergeField.Code;                     
                        String fieldText = rngFieldCode.Text;
                        fieldText = fieldText.Replace("IF  MERGEFIELD  Form_PaymentMethodACHOverride  <> \"True\"", "IF   \"True\"  = \"True\" ");
                        rngFieldCode.Text = fieldText;
                    }
                    wordDoc.Fields.Update();
                    wordDoc.SaveAs(destinationBlankTemplate);
                     
                    ((_Application)wordApp).Quit();
                    
                }
                catch (Exception ex)
                {
                    //Logg error                 
    
                }
            }

    2- screen shot of the code

    3- screen shot of the issue.

    Thanks,


    Monday, March 14, 2016 8:29 AM

Answers

  • Your approach simply won't work. Taking the second example from my previous post, if you replace the mergefields for fields 3 & 4 with '-----', all you'd get is syntax errors!

    Mailmerge field coding can be vastly more complex than you seem to envisage. See for example, the field constructions in the Mailmerge Tips and Tricks thread at:
    http://windowssecrets.com/forums/showthread.php/163017-Word-Mailmerge-Tips-amp-Tricks - and those fields are not especially complex. If you want to appreciate the complexity you might encounter, consider:

    {QUOTE
    {SET Delay 14}
    {SET a{=INT((14-{MERGEFIELD MergeDate \@ M})/12)}}
    {SET b{={MERGEFIELD MergeDate \@ yyyy}+4800-a}}
    {SET c{={MERGEFIELD MergeDate \@ M}+12*a-3}}
    {SET d{MERGEFIELD MergeDate \@ d}}
    {SET jd{=d+INT((153*c+2)/5)+365*b+INT(b/4)-INT(b/100)+INT(b/400)-32045+Delay}}
    {SET e{=INT((4*(jd+32044)+3)/146097)}}
    {SET f{=jd+32044-INT(146097*e/4)}}
    {SET g{=INT((4*f+3)/1461)}}
    {SET h{=f-INT(1461*g/4)}}
    {SET i{=INT((5*h+2)/153)}}
    {SET dd{=h-INT((153*i+2)/5)+1}}
    {SET mm{=i+3-12*INT(i/10)}}
    {SET yy{=100*e+g-4800+INT(i/10)}}
    "{dd}-{mm}-{yy}" \@ "dddd, d MMMM yyyy"}

    and:

    {QUOTE{IF{MERGESEQ}= 1 "{SET Key1 ""}{SET Key2 ""}{SET LastKey {REF Key1}}" {SET LastKey {REF Key1}}}{IF{MERGEFIELD State}<> {REF Key1} "{IF{MERGESEQ}> 1 "
    If you require more details about the above sales figures, please contact your {REF LastKey} Sales Manager.
    Sincerely,
    Customer Service Manager (National)
    {DATE \@ "dddd, d MMMM yyyy"}
    {IF{MERGEFIELD State}<> 0 {QUOTE 12}}"}{IF{={IF{MERGESEQ}= 1 1 0}+{IF{MERGEFIELD State}<> 0 1 0}}>= 1 "Director,
    Retail Sales {MERGEFIELD State}{SET Key1 {MERGEFIELD State}}
    These are the sales totals for {MERGEFIELD State \* Charformat}
    City Representative Sales
    "}"}"{IF{MERGEFIELD State}<> 0 "{IF{MERGEFIELD City}<> {REF Key2} "{MERGEFIELD City}{SET Key2 {MERGEFIELD City}}" "    '' ''"} {MERGEFIELD Representative} {MERGEFIELD Sales \# $,0.00}
    "}"}

    These examples are taken from two of my tutorials: the first adds 14 day to a date returned by a mergefield; the second manages a directory merge that groups records by two categories. Simply replacing a mergefield's output with '-----' would give a meaningless output in either case.

    If you want a record of how the various fields are coded, I suggest you use code like the following, which replaces all fields in a document with formatted text representations of their original structure & content:

    Sub FieldCodesToFormattedText()
    Application.ScreenUpdating = False
    ActiveWindow.View.ShowFieldCodes = True
    Dim RngCode As Range
    With ActiveDocument
      While .Fields.Count > 0
        With .Fields(1)
          Set RngCode = .Code
          With RngCode
            .MoveEndUntil Chr(21), wdForward
            .MoveStartUntil Chr(19), wdBackward
            .Cut
          End With
          .Delete
        End With
        With RngCode
          .Text = "{}"
          .Start = .Start + 1
          .Collapse wdCollapseStart
          .Paste
          If InStr(.Text, Chr(20)) > 0 Then
            .MoveStartUntil Chr(20), wdForward
            .Delete
          End If
        End With
      Wend
    End With
    ActiveWindow.View.ShowFieldCodes = False
    Application.ScreenUpdating = True
    End Sub 

    Having extracted the structure, you can then other tools to edit the text representations of the fields, if that's what you really want to do.


    Cheers
    Paul Edstein
    [MS MVP - Word]


    • Edited by macropodMVP Tuesday, March 15, 2016 10:22 AM Code enhancement
    • Marked as answer by MAsseedeh Monday, March 21, 2016 7:36 AM
    Tuesday, March 15, 2016 9:21 AM

All replies

  • Hello,

    In the future please post code in a code block, not a screenshot. I am moving your question to the Outlook for developers forum as this is a question best asked there.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Monday, March 14, 2016 9:14 AM
  • Thank you .

    Code block was added.

    Monday, March 14, 2016 9:19 AM
  • It's not clear what you're trying to do but you cannot add a condition to or modify a MERGEFIELD with code like:

    Replace("IF  MERGEFIELD  Form_PaymentMethodACHOverride  <> \"True\"", "IF   \"True\"  = \"True\" ");

    All you're doing is destroying the test of { MERGEFIELD  Form_PaymentMethodACHOverride }, replacing a formatted field containing:
    { IF { MERGEFIELD  Form_PaymentMethodACHOverride } <> "True" "AUTOMATIC PAYMENTS (etc.)" "Invoice to Mohammad Assida" }
    with an unformatted field containing:
    { IF "True" "True" "AUTOMATIC PAYMENTS (etc.)" "Invoice to Mohammad Assida" }

    If all you want to do is change a formatted field with:
    { IF { MERGEFIELD  Form_PaymentMethodACHOverride } <> "True" "AUTOMATIC PAYMENTS (etc.)" "Invoice to Mohammad Assida" }
    to a formatted field with:
    { IF { MERGEFIELD  Form_PaymentMethodACHOverride } = "True" "AUTOMATIC PAYMENTS (etc.)" "Invoice to Mohammad Assida" }
    you would need something equivalent to the following VBA code (I don't do C#):

    Dim WdFld As Field, WdDoc As Document, WdRng As Range, StrCode As String
    ActiveWindow.View.ShowFieldCodes = True
    Set WdDoc = ActiveDocument
    For Each WdFld In WdDoc.Fields
      With WdFld
        If .Type = wdFieldIf Then
          Set WdRng = .Code
          With WdRng
            If InStr(.Text, Chr(21)) > 0 Then
              .MoveStartUntil Chr(21), wdForward
              .MoveStart wdCharacter, 1
              StrCode = Trim(.Text)
              While InStr(StrCode, "  ") > 0
                StrCode = Replace(StrCode, "  ", " ")
              Wend
              If InStr(StrCode, "<> " & Chr(34) & "True" & Chr(34)) = 1 Then
                .Collapse wdCollapseStart
                .MoveEndUntil Chr(34), wdForward
                .Text = Replace(.Text, "<>", "=")
              End If
            End If
          End With
        End If
      End With
    Next
    ActiveWindow.View.ShowFieldCodes = False


    Cheers
    Paul Edstein
    [MS MVP - Word]

    Monday, March 14, 2016 11:10 AM
  • Thank you Paul for fast response,

    I have multiple word templates , each template has multiple IF statements, merge fields,Formulas to be used in a merge process to generate documents depending on the variables that were passed to the document.

    No I want to generate "Blank" docs (No variables will be passed to the template) :

    - All merge fields (that are not in the IF statement expression ) should be replaced by "______" blank space.

    - IF statement have True Text and False Text, Some of the documents should have the true text and the others should have the false text.

    What I am trying to do is to change the expression of the IF statement to be true or false, and update the document fields .

    At the end the output document should have:

    1- All merge fields out of the expression of the IF statement should be replaced by "______" blank space.

    2- True Text or False Text of the IF statement depend on the new expression .

    Thanks,

    Monday, March 14, 2016 12:37 PM
  • And what happens to mergefields that are used on both sides of the IF test or are themselves part of the conditional output, e.g.:

    { IF { MERGEFIELD Field1 } <> { MERGEFIELD Field2 } "Some formatted text { MERGEFIELD Field1 } more text { MERGEFIELD Field2 }" "{ MERGEFIELD Field3 } or { MERGEFIELD Field4 }" }

    Furthermore, what are the criteria for assigning a true or false condition to a given field?

    Any programmatic solution would also have to take account that IF fields can be nested up to 20 levels deep and may or may not have anything for the 'false' part of the expression, e.g.:

    { IF { MERGEFIELD Field1 } <> { MERGEFIELD Field2 } "{IF { MERGEFIELD Field1 } = { MERGEFIELD Field3 } "some text { MERGEFIELD Field2 }" "{={ MERGEFIELD Field3 } + { MERGEFIELD Field4 } \# "$,0.00"}"} }

    Has it occurred to you that you could achieve what seems to be most, if not all, of your desired result by connected the mailmerge main documents to a dummy data source with data that will cause the output to produce documents with the required true/false outputs - including mergefields replaced by "______"? No code required.


    Cheers
    Paul Edstein
    [MS MVP - Word]



    • Edited by macropodMVP Tuesday, March 15, 2016 1:52 AM Extra considerations
    Monday, March 14, 2016 9:18 PM
  • Hi Paul ,

    Below you will find an example:

    Some Text: { MERGEFIELD Field1 } more text { MERGEFIELD Field2 },{ MERGEFIELD Field3 }
    { IF { MERGEFIELD Field1 } <> { MERGEFIELD Field2 } "Some formatted text { MERGEFIELD Field1 } more text { MERGEFIELD Field2 }" "{ MERGEFIELD Field3 } or { MERGEFIELD Field4 }" }

    If I use the data source with dummy data and set the values as below:
    Field1 =1
    Field2 =2
    Field3="______"
    Field4="______"

    Then The result will be:
    Some Text: 1 more text 2,________
    Some formatted text 1 more text 2

    But my goal is to get the result :
    Some Text: ______ more text ______ ,________
    Some formatted text ______ more text ______

    So my plan is :
    1-To have a table in the database that contains all documents names and there IF statements

    Doc Name Condition DefaultValue
    Sample1.dot IF { MERGEFIELD Field1 } <> { MERGEFIELD Field2 } True


    2- Loop through all the if statement in the document  and compare them with the values in the database.
    if the Default Value of the condition is true then IF { MERGEFIELD Field1 } <> { MERGEFIELD Field2 } will become
    IF "True" = "True"

    3- Now all the merge fields within the IF statement conditions are set to be as in the database table and the Individual merge fields (Out of the IF condition) have no changes "still as they are".

    4- Loop through all merge fields as set value to be  "_______".

    That's why I am trying to control the result of the condition first.

    Thanks,

    Tuesday, March 15, 2016 5:18 AM
  • Your approach simply won't work. Taking the second example from my previous post, if you replace the mergefields for fields 3 & 4 with '-----', all you'd get is syntax errors!

    Mailmerge field coding can be vastly more complex than you seem to envisage. See for example, the field constructions in the Mailmerge Tips and Tricks thread at:
    http://windowssecrets.com/forums/showthread.php/163017-Word-Mailmerge-Tips-amp-Tricks - and those fields are not especially complex. If you want to appreciate the complexity you might encounter, consider:

    {QUOTE
    {SET Delay 14}
    {SET a{=INT((14-{MERGEFIELD MergeDate \@ M})/12)}}
    {SET b{={MERGEFIELD MergeDate \@ yyyy}+4800-a}}
    {SET c{={MERGEFIELD MergeDate \@ M}+12*a-3}}
    {SET d{MERGEFIELD MergeDate \@ d}}
    {SET jd{=d+INT((153*c+2)/5)+365*b+INT(b/4)-INT(b/100)+INT(b/400)-32045+Delay}}
    {SET e{=INT((4*(jd+32044)+3)/146097)}}
    {SET f{=jd+32044-INT(146097*e/4)}}
    {SET g{=INT((4*f+3)/1461)}}
    {SET h{=f-INT(1461*g/4)}}
    {SET i{=INT((5*h+2)/153)}}
    {SET dd{=h-INT((153*i+2)/5)+1}}
    {SET mm{=i+3-12*INT(i/10)}}
    {SET yy{=100*e+g-4800+INT(i/10)}}
    "{dd}-{mm}-{yy}" \@ "dddd, d MMMM yyyy"}

    and:

    {QUOTE{IF{MERGESEQ}= 1 "{SET Key1 ""}{SET Key2 ""}{SET LastKey {REF Key1}}" {SET LastKey {REF Key1}}}{IF{MERGEFIELD State}<> {REF Key1} "{IF{MERGESEQ}> 1 "
    If you require more details about the above sales figures, please contact your {REF LastKey} Sales Manager.
    Sincerely,
    Customer Service Manager (National)
    {DATE \@ "dddd, d MMMM yyyy"}
    {IF{MERGEFIELD State}<> 0 {QUOTE 12}}"}{IF{={IF{MERGESEQ}= 1 1 0}+{IF{MERGEFIELD State}<> 0 1 0}}>= 1 "Director,
    Retail Sales {MERGEFIELD State}{SET Key1 {MERGEFIELD State}}
    These are the sales totals for {MERGEFIELD State \* Charformat}
    City Representative Sales
    "}"}"{IF{MERGEFIELD State}<> 0 "{IF{MERGEFIELD City}<> {REF Key2} "{MERGEFIELD City}{SET Key2 {MERGEFIELD City}}" "    '' ''"} {MERGEFIELD Representative} {MERGEFIELD Sales \# $,0.00}
    "}"}

    These examples are taken from two of my tutorials: the first adds 14 day to a date returned by a mergefield; the second manages a directory merge that groups records by two categories. Simply replacing a mergefield's output with '-----' would give a meaningless output in either case.

    If you want a record of how the various fields are coded, I suggest you use code like the following, which replaces all fields in a document with formatted text representations of their original structure & content:

    Sub FieldCodesToFormattedText()
    Application.ScreenUpdating = False
    ActiveWindow.View.ShowFieldCodes = True
    Dim RngCode As Range
    With ActiveDocument
      While .Fields.Count > 0
        With .Fields(1)
          Set RngCode = .Code
          With RngCode
            .MoveEndUntil Chr(21), wdForward
            .MoveStartUntil Chr(19), wdBackward
            .Cut
          End With
          .Delete
        End With
        With RngCode
          .Text = "{}"
          .Start = .Start + 1
          .Collapse wdCollapseStart
          .Paste
          If InStr(.Text, Chr(20)) > 0 Then
            .MoveStartUntil Chr(20), wdForward
            .Delete
          End If
        End With
      Wend
    End With
    ActiveWindow.View.ShowFieldCodes = False
    Application.ScreenUpdating = True
    End Sub 

    Having extracted the structure, you can then other tools to edit the text representations of the fields, if that's what you really want to do.


    Cheers
    Paul Edstein
    [MS MVP - Word]


    • Edited by macropodMVP Tuesday, March 15, 2016 10:22 AM Code enhancement
    • Marked as answer by MAsseedeh Monday, March 21, 2016 7:36 AM
    Tuesday, March 15, 2016 9:21 AM
  • Thank you Paul , The code was very helpful.

    Monday, March 21, 2016 7:36 AM