How to create Recursive Content Control

Feb 12, 2012 at 1:30 AM

Hi, in your example Word Template, "Test_Template - 2.docx" you have a "VendorDetailRow" content control that spans all the columns.  How did you do that?  I need to be able to do that in many templates.  I'll be building lots of tables.

Thanks.  BTW, great tool!

Coordinator
Feb 12, 2012 at 6:47 PM

Thanks Kahanu. I was finding very hard to have a rich text control that spans all the columns with out this tool. I used "Open Xml Package editor power tool for Visual Studio 2010". The download location is http://visualstudiogallery.msdn.microsoft.com/450a00e3-5a7d-4776-be2c-8aa8cec2a75b.  After this tool is installed drag a Word document on Visual Studio and it will open the package. 

Open document.xml node. Do a [Ctrl + K + D] so that Xml gets formatted. Wrap the table row inside the content control as displayed below

	<w:sdt>
            <w:sdtPr>
              <w:alias w:val="Vendor Detail"/>
              <w:tag w:val="VendorDetailRow"/>
              <w:id w:val="-1995484328"/>
              <w:placeholder>
                <w:docPart w:val="84B549EBC817423DB384C8816A38D0E0"/>
              </w:placeholder>
            </w:sdtPr>
            <w:sdtEndPr/>
            <w:sdtContent>
              <w:tr w:rsidR="004C78EB" w:rsidTr="008F578D">
                <w:tc>
                  <w:tcPr>
                    <w:tcW w:w="4788" w:type="dxa"/>
                  </w:tcPr>
                  <w:p w:rsidR="004C78EB" w:rsidRPr="0079049E" w:rsidRDefault="00AB6969" w:rsidP="008F578D">
                    <w:sdt>
                      <w:sdtPr>
                        <w:alias w:val="Vendor ID"/>
                        <w:tag w:val="VendorId"/>
                        <w:id w:val="-1348856374"/>
                        <w:placeholder>
                          <w:docPart w:val="4561E24F1E34488FAA44A2E6AB6DF29D"/>
                        </w:placeholder>
                        <w:showingPlcHdr/>
                        <w:text/>
                      </w:sdtPr>
                      <w:sdtEndPr/>
                      <w:sdtContent>
                        <w:r w:rsidR="00AA2CB2" w:rsidRPr="004E36F4">
                          <w:t>Click here to enter text.</w:t>
                        </w:r>
                      </w:sdtContent>
                    </w:sdt>
                  </w:p>
                </w:tc>
                <w:tc>
                  <w:tcPr>
                    <w:tcW w:w="4788" w:type="dxa"/>
                  </w:tcPr>
                  <w:p w:rsidR="004C78EB" w:rsidRPr="0079049E" w:rsidRDefault="00AB6969" w:rsidP="008F578D">
                    <w:sdt>
                      <w:sdtPr>
                        <w:alias w:val="Vendor Name"/>
                        <w:tag w:val="VendorName"/>
                        <w:id w:val="-216660976"/>
                        <w:placeholder>
                          <w:docPart w:val="E4BC115C38114FACBB074DD303396937"/>
                        </w:placeholder>
                        <w:showingPlcHdr/>
                        <w:text/>
                      </w:sdtPr>
                      <w:sdtEndPr/>
                      <w:sdtContent>
                        <w:r w:rsidR="00324673" w:rsidRPr="004E36F4">
                          <w:t>Click here to enter text.</w:t>
                        </w:r>
                      </w:sdtContent>
                    </w:sdt>
                  </w:p>
                </w:tc>
              </w:tr>
            </w:sdtContent>
          </w:sdt>

In order to cross validate open the document inside "Open Xml 2.0 Productivity tool". Inside the table this content control will be of type "SdtRow" now. The same thing can be done for a cell and in that case the type will be "SdtCell". 

Let me know if further information is required. Thanks.

Regards,

Atul

 

Feb 13, 2012 at 6:25 PM

Atul, I'll give that a try.  I'll let you know if I have any problems.  So far, with my testing, I've been building test generator classes super fast (for non-recursive results) using your excellent tool.  And it just works!

Thanks a bunch.

King Wilder

Feb 13, 2012 at 11:06 PM

Atul, the format and order of elements in the table row are in a different arrangement than in the original table.  Is this something that I need to do also?  Example, the "tc" table cells are in a different place than in the original.

This looks like a job for a custom tool.  :^)

Feb 13, 2012 at 11:40 PM

Ok, I modified the source xml and it worked!  For tables that have 6 columns or more, this is a lot of work.  Any chance of a tool to be written to help automate this? I'll see if I can write one.

Otherwise, it builds the table with data perfectly!

Coordinator
Feb 14, 2012 at 8:04 AM

Yeah, I agree that in order to have a SdtRow or SdtCell content control some times it's very hard to do though Word. What I do is create a table with required columns, rows. Then add a rich text control to the document to wrap the complete row. If it doesn't work as desired, open the document in Visual Studio and manually edit as mentioned above. I'd see if there is a better way to achieve this functionality.

 

Regards,

Atul

Feb 16, 2012 at 4:18 AM

What I do:

1) Enable "developer tab" in Word:

   - Word 2010: http://www.youtube.com/watch?v=iYi9zNlzrOc

   - Word 2007: http://www.youtube.com/watch?v=QC0x61tphQM

2) Create a table.

3) First, insert non-recursive content controls: Inside the content row, for each cell, insert "Text Control" (Aa black icon in developer tab). e.g. "Vendor id" and "Vendor name". Click "Properties" icon in developer tab to edit the control properties (name and tag);

3) After, insert recursive content control: select (with the mouse) non-recursive controls and click "Rich Text Control" (Aa blue icon in developer tab). So, the non-recursive controls will be inside the recursive content control. Click properties icon to edit tag and name (e.g. VendorDetailRow). Click "Design Mode" icon in developer tab to view the relationship between content controls .

Regards,

Jorge

Feb 23, 2012 at 11:16 PM
jwcspb wrote:

What I do:

1) Enable "developer tab" in Word:

   - Word 2010: http://www.youtube.com/watch?v=iYi9zNlzrOc

   - Word 2007: http://www.youtube.com/watch?v=QC0x61tphQM

2) Create a table.

3) First, insert non-recursive content controls: Inside the content row, for each cell, insert "Text Control" (Aa black icon in developer tab). e.g. "Vendor id" and "Vendor name". Click "Properties" icon in developer tab to edit the control properties (name and tag);

3) After, insert recursive content control: select (with the mouse) non-recursive controls and click "Rich Text Control" (Aa blue icon in developer tab). So, the non-recursive controls will be inside the recursive content control. Click properties icon to edit tag and name (e.g. VendorDetailRow). Click "Design Mode" icon in developer tab to view the relationship between content controls .

Regards,

Jorge

Jorge, thanks for the suggestion, but it doesn't work for me.  I get a message saying, "Rich Text controls cannot be inserted around multiple selections".  Maybe I'm doing it wrong but there was no way of selecting more than one non-recursive content control.

For now I'll stick with Atul's method.  It's a lot of work, but it does work.

BTW, I do have the Developer Tab enabled and can use all the controls inside.

Feb 24, 2012 at 2:35 AM

Try to select the entire line and click "Rich Text Control" (Aa blue icon in developer tab)".

Jorge

Coordinator
Feb 24, 2012 at 4:32 AM

I prefer the approach mentioned by Jorge, however at times Word doesn't nest the controls as desired. Hence the second approach i.e. editing the Word Package from with in Visual Studio in conjunction with "Open Xml 2.0 Productivity too". 

 

Regards,

Atul

Feb 27, 2012 at 5:54 PM
jwcspb wrote:

Try to select the entire line and click "Rich Text Control" (Aa blue icon in developer tab)".

Jorge

Jorge,

Yes, I tried that, and that's when I get that error message saying that it's not allowed.

King Wilder

Feb 27, 2012 at 5:57 PM
atul_nith wrote:

I prefer the approach mentioned by Jorge, however at times Word doesn't nest the controls as desired. Hence the second approach i.e. editing the Word Package from with in Visual Studio in conjunction with "Open Xml 2.0 Productivity too". 

 

Regards,

Atul

Yes, that would be the easy way if it worked, but for me it doesn't.

I'm on a brand new Windows 7 Ultimate machine (not even 30 days old), with Microsoft Office 2010 Home and Business, so I don't know why I can't do what you suggest.

King

Feb 27, 2012 at 6:02 PM

I ended up writing a little console app that does this for me.  It kind of works, but I haven't completely tested it.  It works off of an xml file where you define the columns of the table and it creates the entire table and drops it into a single content control on your page.

It will then create the header row and the data row with the row wrapped in a content control and each cell contains a named content control.  It's intended to use with Atul's WordDocumentGenerator, so for now it's just targeted for that usage only.

I want to put it up here on CodePlex, but it's not ready for primetime and I would need some more expert eyes to look at it and collaborate before I feel it's ready for the public.

Are you guys interested in looking at this?  If so, what is the best thing for me to do with this?

King

Jul 17, 2012 at 8:54 PM

For those interested, I've created the component that will create the Word Table and I show how it works in a screencast.  You can also download all the code.

I demonstrate this in an ASP.NET MVC 3 application where I create a Word document, insert a table using my component, and populate the table with data using this OpenXml SDK.  It's pretty cool.

You can view the screencast here, http://www.mvccentral.net/s/66, and also read an article and download the complete code.

Enjoy!

King Wilder

Coordinator
Jul 18, 2012 at 5:07 AM

This is very cool. Thanks for sharing.

 

Regards,

Atul

Jul 18, 2012 at 4:43 PM

Atul,

Thank you for creating the SDK. It saved my butt. Like you I like sharing my (limited) knowledge with the community.

Thanks,

King Wilder

MVC Central

info@mvccentral.net

http://www.mvccentral.net

From: atul_nith [email removed]
Sent: Tuesday, July 17, 2012 9:07 PM
To: info@mvccentral.net
Subject: Re: How to create Recursive Content Control [WordDocGenerator:308148]

From: atul_nith

This is very cool. Thanks for sharing.

Regards,

Atul

Dec 13, 2012 at 6:03 AM

Atul, you have made an excellent job! Thank you!

But I also think that manually changing document.xml is not the best solution. Especially when you have a number of large reports. 

Jorge's (jwcspb) solution helped me much (thanks :)) But cell formatting was lost.

So I made some changes in OpenXmlHelper.cs AddRunsToSdtContentCell method:

/// <summary>
/// Adds the runs to SDT content cell.
/// </summary>
/// <param name="sdtContentCell">The SDT content cell.</param>
/// <param name="runs">The runs.</param>
private void AddRunsToSdtContentCell(SdtContentCell sdtContentCell, List<Run> runs)
{
    var para = sdtContentCell.Descendants<Paragraph>().FirstOrDefault();
    para.Descendants<Run>().ToList().ForEach(r => para.RemoveChild(r));
    foreach (Run run in runs)
    {
        para.AppendChild(run);
    }
}
That worked for me. Now it is easy to make templates with no formatting issues. :)

Feb 21, 2013 at 3:28 PM
Edited Feb 21, 2013 at 3:29 PM
Atul, you have done a great job! Thank you!

Just wonder how do I create a recursive content control on Word header?

I need to create a Word template to generate document for a list of companies name and their description. I put a recursive content control on the document's main body and include the company description content control in it, and need to repeat Company Name on the header when the company description continues to the next page. But the Word header is a different xml from the main body xml, how do I bind the header's content control with the main body's recursive content control as a group?

Thanks!