none
How to get a value from content control within Repeating section content control RRS feed

  • Question

  • Hi,

    I have a repeating section content control which contains a set of content controls with values that i need to access when doing calculations.

    To make things a bit easier i illustrate the content with a picture:

    Calculate value for a specific row

    In the picture above i have a table where the two rows illustrate two rows within a repeating section content control. What i need todo is to add the first value with the second value and set the total value for a SINGLE row.

    The main problem that i have is how to get the current row so that i know which content controls to pull values from.

    One idea that i have is to loop through each row within the repeating section content control and simply sum up every row every time i do a calculation but that does not seem very efficient.

    Appreciate any input on this matter.

    Br,

    /Peter


    Peter

    Monday, July 7, 2014 1:55 PM

Answers

  • Peter,

    Sorry if I have misunderstood, but it should be possible to process a sequence of repeating section items along the following lines (in VBA)

    Set pCC = mWordDocument.SelectContentControlsByTitle("role")(1)
    For Each rsi In pCC.RepeatingSectionItems

      ' set default values

      costPerHour = 0
      For Each cc In rsi.Range.ContentControls
        Select Case cc.Title
        Case "costPerHour"
          Debug.Print cc.Range.Text
          ' etc.

        Case "whatever"

        '

        Case Else
          Debug.Print "unknown"
        End Select
      Next
    Next

    I agree that it's not an elegant way to do things.

    To process a single row containing the selection you would first have to pin down which row (in which control) contained the selection, but I think that is do-able (although also inelegant).


    Peter Jamieson

    Wednesday, July 9, 2014 2:24 PM

All replies

  • Hi Peter,

    I made a table in a reperting section content control in Word 2013 as below:

    Please try:

    Sub testContentControl()
        Dim o As Table
        Dim c As Row
        Set o = ActiveDocument.ContentControls.Item(1).Range.Tables(1)
        For Each c In o.Rows
            If IsNumeric(Mid(c.Cells(2).Range.Text, 1, Len(c.Cells(2).Range.Text) - 2)) Then
                finalNumber1 = CInt(Mid(c.Cells(2).Range.Text, 1, Len(c.Cells(2).Range.Text) - 2))
            Else
                finalNumber1 = 0
            End If
            If IsNumeric(Mid(c.Cells(3).Range.Text, 1, Len(c.Cells(3).Range.Text) - 2)) Then
                finalNumber2 = CInt(Mid(c.Cells(3).Range.Text, 1, Len(c.Cells(3).Range.Text) - 2))
            Else
                finalNumber2 = 0
            End If
            c.Cells(4).Range.Text = finalNumber1 + finalNumber2
        Next c
    End Sub

    After executing the code above, the fourth column was calculated by the second column and the third column.

    Since I found that the text in any cell was like this:

    So I removed the last two characters to make sure the text is number.

    Here is the sample you can download to test:

    https://onedrive.live.com/redir?resid=AD77AE76D657E280!160&authkey=!AIs4BmVAIsbP6Dk&ithint=file%2c.docm

    Hope this helps.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, July 8, 2014 5:56 AM
    Moderator
  • Hi,

    Thanks for your reply!

    I tried a similar solution where i access content controls directly by accessing the first content control within repeating section content control in order to count the amount of rows available.
    However, i realized that accessing a content control by its name and index is not reliable.

    For example:
    Accessing the content control "costPerHour" at position 1 does not correspond to the same row when accessing the content control "budgetHoursFirstYear" at position 1.

    See my code here down below.

    public void CalculateRoleRows()
    {
                  //First column within repeating section content control
                   var roles = mWordDocument.SelectContentControlsByTitle("name");

                    for (int i = 1; i <= roles.Count; i++)
                    {
                        //Cost per hour
                        var costPerHourCC = mWordDocument.SelectContentControlsByTitle("costPerHour")[i];
                        var costPerHourText = costPerHourCC.Range.Text;
                        long costPerHour = 0;
                        long.TryParse(costPerHourText, out costPerHour);

                        //First year
                        var bhfyCC = mWordDocument.SelectContentControlsByTitle("budgetHoursFirstYear")[i];
                        var bhfyText = bhfyCC.Range.Text;
                        long firstYear = 0;
                        long.TryParse(bhfyText, out firstYear);

                        //Second year
                        var bhsyCC = mWordDocument.SelectContentControlsByTitle("budgetHoursSecondYear")[i];
                        var bhsyText = bhsyCC.Range.Text;
                        long secondYear = 0;
                        long.TryParse(bhsyText, out secondYear);
                       
                        //Total hours audit year
                        var totalHoursAuditYearCC = mWordDocument.SelectContentControlsByTitle("totalHoursAuditYear")[i];
                        totalHoursAuditYearCC.Range.Text = (firstYear + secondYear).ToString();


                        //Budget cost first year
                        var budgetCostFirstYearCC = mWordDocument.SelectContentControlsByTitle("budgetCostFirstYear")[i];
                        budgetCostFirstYearCC.Range.Text = (firstYear * costPerHour).ToString();
                        var budgetCostFirstYearText = budgetCostFirstYearCC.Range.Text;

                        //Budget cost second year
                        var budgetCostSecondYearCC = mWordDocument.SelectContentControlsByTitle("budgetCostSecondYear")[i];
                        budgetCostSecondYearCC.Range.Text = (secondYear * costPerHour).ToString();
                        var budgetCostSecondYearText = budgetCostSecondYearCC.Range.Text;

                        //Total cost budget year
                        long budgetCostFirstYear = 0;
                        long.TryParse(budgetCostFirstYearText, out budgetCostFirstYear);

                        long budgetCostSecondYear = 0;
                        long.TryParse(budgetCostSecondYearText, out budgetCostSecondYear);

                        var totalCostAuditYearCC = mWordDocument.SelectContentControlsByTitle("totalCostAuditYear")[i];
                        totalCostAuditYearCC.Range.Text = (budgetCostFirstYear + budgetCostSecondYear).ToString();
                    }
    }

    So, what i'm really after is a reliable index, a way to access every content control on the same row.
    I have looked at your solution but from my point of view you present a solution that looks like there is no support
    within the API to access information within content controls in repeating section content controls reliably.
    I'm i right or have a missed something? :-)

    Another thing is that within my table there are other things besides the repeating section content control
    so i can't just go through each row in the table. Yes, of course i can add additional checks, devide the table
    into many table etc. but is there no other way to do this?

    Br,

    /Peter


    Peter

    Tuesday, July 8, 2014 8:37 AM
  • Hi Peter,

    Sorry for the misunderstanding, I know that there are some content controls in the repeating section content control that you want to get and set the value.

    I'm not sure what your document looks like, would you mind uploading a simple document through OneDrive for us?

    In addition, you could debug the code you provided and view the properties of every object in the repeating section content control.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Tuesday, July 8, 2014 9:11 AM
    Moderator
  • Hi George,

    Of course i can upload a sample document. Just give me a link. You should know that every content control within the document is also mapped to a custom xml.

    Also, i have debugged the code and i can clearly see that when accessing information within the content controls given its title and
    an index you get information from different rows.

    Br,

    /Peter


    Peter


    Tuesday, July 8, 2014 10:28 AM
  • Hi,

    I uploaded a sample document and you can access it from here: http://1drv.ms/1k1UQLO

    Br,

    /Peter


    Peter


    Tuesday, July 8, 2014 12:20 PM
  • Hi Peter,

    If you select any cell in the table below:

    And you want to only calculate data from current selected row, please try:

    Sub test()
        Set o = Application.Selection
        Dim s1, s2 As String
        s1 = o.ParentContentControl.Parent.Tables(1).Rows(o.Rows(1).Index).Cells(3).Range.ContentControls(1).Range.Text
        s2 = o.ParentContentControl.Parent.Tables(1).Rows(o.Rows(1).Index).Cells(4).Range.ContentControls(1).Range.Text
        If IsNumeric(s1) Then
            finalNumber1 = CInt(s1)
        Else
            finalNumber1 = 0
        End If
        If IsNumeric(s2) Then
            finalNumber2 = CInt(s2)
        Else
            finalNumber2 = 0
        End If
        o.ParentContentControl.Parent.Tables(1).Rows(o.Rows(1).Index).Cells(5).Range.ContentControls(1).Range.Text = finalNumber1 + finalNumber2
    End Sub

    The result:

    This is a VBA solution, but you can convert it to C#.

    Hope this helps.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Wednesday, July 9, 2014 8:42 AM
    Moderator
  • Hi,

    Thanks for your solution. However, accessing the table this way is not an option for me. The user could very well add another table to the document. So, i need another way to access the information. From what i could see you can only extract the table by its index.

    So, what i would need to do is to first find the table and then iterate over the rows and make sure those are the correct rows within the table.

    The thing that bothers me is that we have all these really "useful" content controls which are relatively easy to extract information from, usually, and we cannot use them in this scenario, am i right?

    Found an article where they describe a similar problem http://www.msofficeforums.com/word-vba/18976-table-calculations-vba.html.
    He seems to be accessing information within the table the same way i do. Could it be that i'm missing something?

    Br,

    /Peter


    Peter



    Wednesday, July 9, 2014 9:36 AM
  • Peter,

    Sorry if I have misunderstood, but it should be possible to process a sequence of repeating section items along the following lines (in VBA)

    Set pCC = mWordDocument.SelectContentControlsByTitle("role")(1)
    For Each rsi In pCC.RepeatingSectionItems

      ' set default values

      costPerHour = 0
      For Each cc In rsi.Range.ContentControls
        Select Case cc.Title
        Case "costPerHour"
          Debug.Print cc.Range.Text
          ' etc.

        Case "whatever"

        '

        Case Else
          Debug.Print "unknown"
        End Select
      Next
    Next

    I agree that it's not an elegant way to do things.

    To process a single row containing the selection you would first have to pin down which row (in which control) contained the selection, but I think that is do-able (although also inelegant).


    Peter Jamieson

    Wednesday, July 9, 2014 2:24 PM
  • Hi Peter,

    That is awesome!! That is exactly what i wanted.
    I have implemented this with just a couple of modifications and it works like a charm :-)

    Br,

    /Peter


    Peter

    Thursday, July 10, 2014 11:01 AM
  • Hi again,

    I think i was a bit premature in my celebration. This is a bit strange, in my point of view.

    First an example:

    var roleCC = mWordDocument.SelectContentControlsByTag("role")[1];

    foreach (Word.RepeatingSectionItem rsi in roleCC.RepeatingSectionItems)
    {
     //For the first two rows, cost per hour lies at index 4. When at row three(3), cost per hour lies at index 3
     var costPerHourCC = rsi.Range.ContentControls[4];
    }

    You can read the problem in the comment.
    So, somehow, accessing cost per hour at a certain index is not valid anymore.

    Do you have any idea why this is happening?
    Could the reason for this behaviour relate to how you lay out the content controls within the template?

    Br,
    /Peter


    Peter

    Thursday, July 10, 2014 2:05 PM
  • At this point, I would have to do the same research as you to find out. 

    I would probably stick to iterating through the CCs in each RSI and comparing names (assuming that that works) via switch. Nastier, but I suspect it will be more robust.



    Peter Jamieson

    Thursday, July 10, 2014 3:21 PM
  • I agree, it is nastier and not very pretty but as long as it gets the job done...i guess :-/


    Peter

    Thursday, July 10, 2014 3:33 PM
  • Finally! Got it working! :-)

    I must say though, the api seems a bit "young"...or do you know if these "flaws", as i call them, "by design"? :-)

    Br,
    /Peter


    Peter

    Thursday, July 10, 2014 5:56 PM
  • Well, I agree that it looks like it could all be a lot simpler.

    But I don't work for Microsoft and I don't know what influenced their design decisions in this case.


    But my guess is that rather than exposing a whole bunch of different child objects of an RSI (after all, an RSI can contain stuff other than other content controls), they probably decided that it would be better to return a "familiar" Range object and let coders get everything else they needed from that.



    Peter Jamieson

    Saturday, July 12, 2014 2:54 PM
  • Yea, that's probably it but then again, why expose things like the indexer if it's not reliable.
    Anyway, thanks for all the help!

    Br,
    /Peter


    Peter

    Monday, July 14, 2014 8:06 AM
  • Have you tried mapping the controls and using the data store to perform the calculations.  I've tinkered with a basic invoice which illustrates the process.  I've put a demo file in dropbox:

    https://dl.dropboxusercontent.com/u/64545773/RS%20CC%20Demo%20Doc%20II.docm

    Just change the value in price or qty and exit the CC.


    Greg Maxey Please visit my website at: http://gregmaxey.mvps.org/word_tips.htm

    Monday, July 14, 2014 1:40 PM
  • Peter,

    How did you get it working? We recently converted a document from FormFields to ContentControls so we could utilize repeating sections for our table data. I've used variations of the code above and it works. However, I do agree that referencing the controls is flaky. For example, I have a table with three columns. Accessing these records in a foreach loop and know that column 3 is going to be THIS value. Only at row 11 it isn't. I actually get the control that should be in row 12 and from the 2nd column. Row 12 Has the first column correct, then the second column is column 3 from row 11, and the third column is column 3 from row 12 which is correct.

    ssn   address  phone

    ssn   address  phone

    ssn   address  addressX

    ssn   phoneX    phone

    I expect the controls to be returned in order, reading from the top left and down, like reading a book. The same with table data but there are times where the collection doesn't come across this way. 

    Could you post a sample of how you iterated through the controls?

    Darren

    Monday, October 22, 2018 11:45 PM