none
Is there a way to directly access and modify Content Controls? RRS feed

  • Question

  • hi

    I want to access and modify just the parts of the docx document that i setup in developer mode, the goal is to find a statement similar to using select controls by tag?

    this is an example of a visual basic or VBA code snippet, Im using c# in asp.net/mvc web app; but the goal is to have a mechanism to accurately and reliably modify the fields of "text content" that i have assigned properties to, the code example is from:

    Content Control Grouping & Navigation

    the goal is to have a method that i can pass the field name and its new string value to and save the document.  there is a reference document that never changes, its always used as a base document.   

    my hopeful method is UpdateField, the unknown Microsoft or openXml method that would define a new control of type text is 

    DocumentControlItem(Text)

    WordDocumentType mydocument;

    public void UpdateField(document, string fieldname, string value){
    
    myTxtcontrol DocumentControlitem  = new DocumentControlItem(Text);
    myTxtcontrol = document.SelectContentControlsByTag(fieldname)
    }

    so is there a way to open the word document and be able to access the fields this way, such as the text controls that were pre defined and saved?

    Private Sub Document_ContentControlOnExit(ByVal ContentControl As ContentControl, Cancel As Boolean)
      Select Case ContentControl.Tag
        '"Last" = tag property applied to the last control.
        Case "Last"
           '"First" = tag property applied to the first control.
           ActiveDocument.SelectContentControlsByTag("First").Item(1).Range.Select
      End Select
    lbl_Exit:
      Exit Sub
    Friday, June 26, 2015 3:22 PM

Answers

  • Hi Bradley

    It actually pays to do some research in the documentation, you know. We can only point you in the right direction, based on the information you give us. Content controls are "typed" by where they're located. They're listed in the DocumentFormat.OpenXML.WordProcessing section, under sdt. If you have to be able to pick up any kind, then you need to test for all these different kinds!

    You have three different types in the document you show me: BlockContent, RunContent and Cell.

                    IEnumerable<SdtBlock> ccBlocks = bodyDoc.Descendants<SdtBlock>();
                    int i = 1;
                    foreach (SdtBlock ccb in ccBlocks)
                    {
                        textContent = ccb.Descendants<Text>().FirstOrDefault();
                        if (textContent != null)
                        {
                            textContent.Text = "block" + i;
                            i++;
                        }
                    }
    
                    IEnumerable<SdtCell> ccCellContents = bodyDoc.Descendants<SdtCell>();
                    i = 1;
                    foreach (SdtCell ccc in ccCellContents)
                    {
                        textContent = ccc.Descendants<Text>().FirstOrDefault();
                        if (textContent != null)
                        {
                            textContent.Text = "ccCell" + i;
                            i++;
                        }
                    }
    
                    IEnumerable<SdtContentBlock> ccBlockContents = bodyDoc.Descendants<SdtContentBlock>();
                    i = 1;
                    foreach (SdtContentBlock ccbc in ccBlockContents)
                    {
                        textContent = ccbc.Descendants<Text>().FirstOrDefault();
                        if (textContent != null)
                        {
                            textContent.Text = "blockC" + i;
                            i++;
                        }
                    }
    
                    IEnumerable<SdtRun> ccRuns = bodyDoc.Descendants<SdtRun>();
                    i = 1;
                    foreach(SdtRun ccr in ccRuns)
                    {
                    textContent = ccr.Descendants<Text>().FirstOrDefault();
                    if (textContent != null)
                    {
                        textContent.Text = "test" + i;
                        i++;
                    }
    


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, July 20, 2015 3:44 PM
    Moderator

All replies

  • Hi Bradley

    I've been guiding you through your project in the Word forum and *I* can't follow what you're asking for, here :-) Your brain is really deep into the project, where we can't follow...

    The absolute simplest way for you to access the what the content controls display is to link them to a Custom XML Part. Then all you need to do is access that part and read/write its XML (standard XML, the way you want to set it up - as long as it's valid it can be anything).

    Here are some links that may help your mind get into the different set for working with Open XML

    http://ericwhite.com/blog/content-controls-expanded/
    http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2010/10/27/59361.aspx
    http://www.codeproject.com/Articles/96408/Content-Controls-and-Open-XML-SDK


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, June 26, 2015 4:38 PM
    Moderator
  • thanks Cindy,

    i tried to post in a way that i thought was direct/to the point without anything extra, so as to make a helpful question but your feedback helps me to try to change and write better.  i will look at these links and apply and update you, thanks for your patience and help in this.

    I have done this kind of thing in the past, putting live data variables into xml fields and making reports and cannot believe its such a challenge now

    Friday, June 26, 2015 5:24 PM
  • Hi Bradley

    <<I have done this kind of thing in the past, putting live data variables into xml fields and making reports and cannot believe its such a challenge now>>

    I imagine, once your thinking gets out of Word's convoluted object model <g>, you'll find the Open XML SDK closer to what you're used to in this regard. Especially if you link the content controls to a Custom XML Part so that you end up working directly with an XML file.

    It's just getting the document set up that can be such a pain. Note, however, that you don't need to use the OpenXML SDK to get the document set up with the content controls, links and CustomXMLPart. You can do that using Greg's approach or automation code (even VBA). That's a one-off - once it's done you don't need to worry about it anymore.


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, June 26, 2015 7:27 PM
    Moderator
  • Well its not solved, I cannot write to content controls.  trying examples from every site i can find.  i cannot make your example work.

    have a Word doc, newest office i signed up for today.  new visual studio 2015 new project.  now every bookmark code example i tried did work.  the content controls examples do not.

    if anyone has ever made openXML write to the text or rich text contents of a contentcontrol used in making/modifying a word document? any code examples of any kind please post them? any link to any code that runs to change a contentcontrol contents.

    here is code from one of the links, it fails at runtime. just one of the snippets that dont work from online searching

     public void myapp() {
    
             string fileName = "C:\\Users\\test\\Desktop\\1112.docx";
             string savePath = "C:\\Users\\test\\Desktop\\1234567.docx";
             byte[] templateBytes = System.IO.File.ReadAllBytes(fileName);
            using (MemoryStream templateStream = new MemoryStream())
            {
                templateStream.Write(templateBytes, 0, (int)templateBytes.Length);
    
                using (WordprocessingDocument outDoc = WordprocessingDocument.Open(templateStream, true))
                {
                    MainDocumentPart mainPart = outDoc.MainDocumentPart;
    
                    //foreach (SdtElement sdt in mainPart.Document.Descendants<SdtElement>().ToList())
                    //{
                    //    SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();
    
                    //    if (alias != null)
                    //    {
                    //        string sdtTitle = alias.Val.Value;
    
                    //        switch (sdtTitle)
                    //        {
                    //            case "Name":
                    //                // ¿Qué?
                    //                break;
                    //            case "Age":
                    //                // ¿Qué?
                    //                break;
                    //        }
                    //    }
                    //}
    
    
    
                    foreach (SdtElement sdt in mainPart.Document.Descendants<SdtElement>().ToList())
                    {
                        SdtAlias alias = sdt.Descendants<SdtAlias>().FirstOrDefault();
    
                        if (alias != null)
                        {
                            SdtRun xRun = new SdtRun();
                            Run xRun2 = new Run(sdt);
                            SdtContentRun xContentRun = xRun.Descendants<SdtContentRun>().FirstOrDefault();
                             xRun2 = xContentRun.Descendants<Run>().FirstOrDefault();
                            Text xText = xRun.Descendants<Text>().FirstOrDefault();
     
                            string sdtTitle = alias.Val.Value;
    
                            switch (sdtTitle)
                            {
                                case "Test":
                                    xText.Text = "Whatever";
                                    break;
                                case "test":
                                    xText.Text = "69";
                                    break;
                            }
                        }
                    }
    
           outDoc.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
                }
    
                using (FileStream fileStream = new FileStream(savePath, System.IO.FileMode.CreateNew))
                {
                    templateStream.WriteTo(fileStream);
                }
            }
    
    
            } //myapp()


    • Edited by Bradley Rogers Wednesday, July 8, 2015 5:06 PM put actual openxml code into the response
    Wednesday, July 8, 2015 12:51 AM
  • Well here is the current one, openXml. using some of the documentation and then a code sample from an online source,

    the code should work but there is no method called ContentControls. just

    trying to iterate thru the controls to start with

    public void myapp2() { //*********************************************** /* myapp() OpenXML doc processing app c2015 BR /* //***********************************************/ // Understanding Process Mode //The process mode specifies which document parts should be preprocessed.You set this property to a member of the MarkupCompatibilityProcessMode enumeration. The default value, NoProcess, indicates that no preprocessing is performed.Your application must be able to understand and handle any elements and attributes present in the document markup, including any of the elements and attributes in the Markup Compatibility namespace. //You might want to work on specific document parts while leaving the rest untouched.For example, you might want to ensure minimal modification to the file. In that case, specify ProcessLoadedPartsOnly for the process mode.With this setting, preprocessing and the associated filtering is only applied to the loaded document parts, not the entire document. //Finally, there is ProcessAllParts, which specifies what the name implies. When you choose this value, the entire document is preprocessed. //The default value, Office2010, means the SDK will assume that namespaces defined in Office 2010 are understood, but not namespaces defined in Office 2013.Thus, during preprocessing, the SDK will ignore the namespaces defined in Office 2013 and choose the Office 2010 compatible alternate-content. //When you set the target file format versions property to Office2013, the Open XML SDK 2.5 assumes that all of the namespaces defined in Office 2010 and Office 2013 are understood, does not ignore any content defined under Office 2013, and will choose the Office 2013 compatible alternate-content. string filename = "C:\\Users\\Test\\Desktop\\1112.docx"; // Create instance of OpenSettings OpenSettings openSettings = new OpenSettings(); // Add the MarkupCompatibilityProcessSettings 2013! openSettings.MarkupCompatibilityProcessSettings = new MarkupCompatibilityProcessSettings( MarkupCompatibilityProcessMode.ProcessAllParts, FileFormatVersions.Office2013); // Open the document with OpenSettings using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filename, true, openSettings)) { { DocumentFormat.OpenXml.Wordprocessing.Control x = new DocumentFormat.OpenXml.Wordprocessing.Control(); Paragraph p = wordDoc.MainDocumentPart.Document.Body.Elements<Paragraph>().First(); SdtContentRichText srt = new SdtContentRichText(); Body body = wordDoc.MainDocumentPart.Document.Body; foreach (Object cc in wordDoc.ContentControls))

    //foreach fails because there is no content controls, cant compile { SdtProperties props = cc.Elements<SdtProperties>().FirstOrDefault(); Tag tag = props.Elements<Tag>().FirstOrDefault(); Console.WriteLine(tag.Val); } } } } //myapp2


    Thursday, July 9, 2015 3:07 AM
  • Hi Bradley

    OK, I think we're at least now on the same page, in the appropriate forum :-)

    Below is a very simple example that loops all inline content controls and sets a incremented text content value. (inline vs. controls that contain more than one paragraph (which would be a block) or a table or whatever - just keeping it simple, to start).

                using (WordprocessingDocument pkgDoc = WordprocessingDocument.Open(docPath, true))
                {
                    MainDocumentPart mainDoc = pkgDoc.MainDocumentPart;
                    Body bodyDoc = mainDoc.Document.Body;
                    //SdtContentBlock cc = bodyDoc.Descendants<SdtContentBlock>().FirstOrDefault();
                    IEnumerable<SdtRun> ccRuns = bodyDoc.Descendants<SdtRun>();
                    int i = 1;
                    foreach(SdtRun ccr in ccRuns)
                    {
                    DocumentFormat.OpenXml.Wordprocessing.Text textContent = ccr.Descendants<Text>().FirstOrDefault();
                    if (textContent != null)
                    {
                        textContent.Text = "test" + i;
                        i++;
                    }
                    }
                }
    


    Cindy Meister, VSTO/Word MVP, my blog

    Thursday, July 9, 2015 3:30 PM
    Moderator
  • Cindy 

    ok this runs and counts the content controls at least returns the number of cc's that i have there, and when i added more it found more

    Thursday, July 9, 2015 4:51 PM
  • it should also be writing to the content controls...?

    Cindy Meister, VSTO/Word MVP, my blog

    Thursday, July 9, 2015 8:29 PM
    Moderator
  • ok i see it does.  great!

    didnt catch that before.  have been doing another openxml project from Eric Whites blog there to generate .docx files.  really great projects he has made.  also get runtime faults and cant make it run with my data in there on the project from their website;

    But let me check and try some things with this code you shared and see if i can make this work, thanks


    Friday, July 10, 2015 1:45 PM
  • well good gravy... I cannot figure out how to modify this to check for the label name of the content control.  it can iterate thru what it finds and it sees every content control and can write to (them); 

    but would like to put a switch case, based on the contentcontrol label... and then put the value in based only on the specific label.

    ok think i figured it out...

     

     


    Friday, July 10, 2015 2:47 PM
  • if (textContent != null)
                        {
                            if (ccr.OuterXml.Contains("abcd")) //content control name
                            {
                                textContent.Text = "1234"; 
                            }
                            i++;
                        }

    this is the code needed to write based on label


    Friday, July 10, 2015 4:46 PM
  • Hi Bradley

    Yes, I knew you'd need to "pick and choose" when writing data into the document. But I first wanted to make sure that the basics were working :-)

    See this article for a more "palatable" (yes, I saw the original of your most recent post :-)) way to go about it. Really, both work and the OuterXml variation might even be faster. But see:

    http://forums.asp.net/t/1941290.aspx?Populate+a+Content+Control+in+Word+with+SQL+data+using+Ling+to+SQL+and+OpenXML


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, July 10, 2015 7:34 PM
    Moderator
  • Cindy

    Im back on this.  I had it working, i thought then had to make the file save dialog work;  thought this part was ok.  its not.

    it was filling in the fields, each contentcontrol got updated.  now? only the first 2 or 3 out of 60 get modified.  

    deleted and re created contentcontrols.  doesnt matter.  like building blocks made of jello, try and then try again, try faster and it blobs down like jello

    not doing this for a while, i forgot the constructs of sdts and then sdtrun and the other fields.  

    Wednesday, July 15, 2015 7:50 PM
  • Hi Bradley

    I'm afraid you simply don't provide enough information for us to even begin to guess what's gone wrong...

    However, I don't understand at all what a File/Save dialog has to do with using the Open XML SDK to work with content controls...?


    Cindy Meister, VSTO/Word MVP, my blog

    Wednesday, July 15, 2015 8:30 PM
    Moderator
  • Hi Cindy

    well the project will let the user save the .docx file to their pc after its modified.  it opens a template .docx, puts into a byte array r/w then runs this content control modify routine then saves back to .docx then sends it to the user.  the file saveAs ? wow.  the browser does this by listening to a hint you give it in one of the response headers.  nothing about the word 'save' or ? but a certain content type? that makes the save file dialog or if the browser is set to save in the /downloads folder it just happens by itself.

    but here, i thought the logic was ok;  there is a foreach SdtRun ccr, and then a  textContent variable of type ccr.Descendants<Text>().FirstOrDefault();   so for each ccr, if ccr.OuterXml.Contains("contentcontrollabel") then the textContent.Text = "new text value of contentcontrol"

    which is what you sent me, right?  it only gets to the 2nd contentcontrol change, even if it iterates thru the whole thing.

            DocumentFormat.OpenXml.Wordprocessing.Text textContent;
            public void mymethod()
            {
                byte[] byteArray = System.IO.File.ReadAllBytes(fileName);
                using (MemoryStream mem = new MemoryStream())
                {
                    mem.Write(byteArray, 0, (int)byteArray.Length);
                    using (WordprocessingDocument wordDoc =
                        WordprocessingDocument.Open(mem, true))
                    {
                        MainDocumentPart mainDoc = wordDoc.MainDocumentPart;
                        Body bodyDoc = mainDoc.Document.Body;
                        //SdtContentBlock cc = bodyDoc.Descendants<SdtContentBlock>().FirstOrDefault();
                        IEnumerable<SdtRun> ccRuns = bodyDoc.Descendants<SdtRun>();
                        int i = 1;
                        foreach (SdtRun ccr in ccRuns)
                        {
                            textContent = ccr.Descendants<Text>().FirstOrDefault();
                            richTextBox1.Text += "  value:  " + i.ToString() + " is " + textContent.ToString() + "ccr oxml is: " + ccr.InnerText.ToString() + "\n";
                            i++;
                            if (textContent != null)
                            {
                                if (ccr.OuterXml.Contains("Address"))
                                {
                                    richTextBox1.Text += textContent.Text.ToString() + "  1 ";
                                    textContent.Text = "this test data";
                                    break;
    
    
                                }
                            }
                        }
                    }
                }
            }
            
    

    Thursday, July 16, 2015 12:27 PM
  • if I modify this and use a different approach with List<SdtBlock> then it only finds 3 content controls but duplicates the list, so its 123, 123 and the listcount is 6 where it should be (about 20)

     MainDocumentPart mainDoc = wordDoc.MainDocumentPart;
                        //MainDocumentPart mainDocumentPart = WordDoc.MainDocumentPart;
                    List<SdtBlock> sdtList = mainDoc.Document.Descendants<SdtBlock>().ToList();
                    SdtBlock sdtA = null;
                    richTextBox1.Text += "sdtList count= " + sdtList.Count.ToString() + "\n"; //.ToString();
                    foreach (SdtBlock sdt in sdtList)
                    {
                        //if (sdt.SdtProperties.GetFirstChild<Tag>().Val.Value == sdtBlockTag)
                        //{
                        //    sdtA = sdt;
                        //    break;
                        //}
                        richTextBox1.Text += " value is: " + sdt.SdtProperties.GetFirstChild<Tag>().Val.Value + "\n";
    
                    }
    

    Thursday, July 16, 2015 12:50 PM
  • and if I try this way, it also shows up only 6 and the list duplicates the 4, 5, 6th content control names so as the names in my doc go, its printing

    4

    5

    6

    4

    5

    6

    foreach (var element in mainDoc.Document.Body.Descendants())
                    {
                        if (element.GetType() == typeof(SdtBlock))
                        {
                            SdtBlock block = (SdtBlock)element;
                            SdtProperties prop = block.SdtProperties;
                            richTextBox1.Text += "sdt properties: " + prop.GetFirstChild<Tag>().Val + "\n";
                            //if (prop.GetFirstChild<Tag>().Val == "paymentTerms")
                            //{
                            //    //Text t = block.Descendants<Text>().Single();
                            //    //t.Text = customerName;
                            //    //mainPart.Document.Save();
                            //    //break;
                            //}
                        }
                    }

    Thursday, July 16, 2015 1:06 PM
  • Hi Bradley

    Difficult to follow everything, but...

    You can't use sdtRun and sdtBlock interchangeably - they're two different things. If you have content controls that are in-line as well as content controls that contain entire paragraphs (or other things) then you need both kinds of loops.

    <<it opens a template .docx, puts into a byte array r/w then runs this content control modify routine then saves back to .docx >>

    If what you're seeing here is different from your test scenario that we worked out together, then something is either happening when the user does editing, or when the document is being sent back-and-forth. The Open XML SDK toolkit should let you compare documents (they're Open XML) so that you can see what's changing. Also, Word as a Compare Documents functionality in the UI.


    Cindy Meister, VSTO/Word MVP, my blog

    Thursday, July 16, 2015 3:48 PM
    Moderator
  • sdtRun is the part that contains the contentcontrol text, right? w:t ?

    how much does it matter rich text content control vs. plain?  these are all rich text cc's

    they do not change.  the template is loaded from the file, values are forced into the cc's now by a string literal on each line, then its output.

    ...ok am back again, it looks like using the if OuterXml.Contains("name") ? this will not work, this is the random part that sends back whatever text it may send.

    in your example you just iterated thru cc's and wrote to them, i then tried to add a labelling mechanism, if content control name is "this" then the text =  "that"

    so the stuck part here is identifying the content control, can you help with this? if we can JUST find a way to iterate thru known content controls and say if value is this then write that?  or switch case cc name (within a foreach) it will be done.  it has to be done and working within a few hours from now

    Thursday, July 16, 2015 5:34 PM
  • Cindy

    think i figured it out this finds it and seems to put it in the right place.

    foreach (SdtRun ccr in ccRuns)
                        {
                          textContent = ccr.Descendants<Text>().FirstOrDefault();
                            if (textContent != null)
                            {
                                if (ccr.SdtProperties.GetFirstChild<Tag>().Val.Value =="ModelNum")
                                {
                                   
                                   ccr.Descendants<Text>().First().Text = mydb.modelnumber;
                                   continue;
    
    
                                }

    Thursday, July 16, 2015 7:53 PM
  • NO.  today it does not work.  figures.  

    the word document, i took the working one, added all of the fields at another pc running the newest office;  all perfect.  loaded it back on this pc today? crashes.  says object reference not set to an instance of an object

    use the old word.docx and it runs, picks up the 6 content controls.  my doc crashes it.  using that tool to check, neither validate fully only some small differences, any advice what can i do?  i put in hours late last nite to finish the word doc that now will not let the sw run

    richTextBox1.Text += "value: " +ccr.SdtProperties.GetFirstChild<Tag>().Val.Value + " \n";  is the line it crashes on
    Friday, July 17, 2015 12:50 PM
  • Cindy

    the code fails now, it will read content controls just in a plain area, then within a table inside cells, and then it does not see anything past the table and may be where its crashing.

    is there any reason you can imagine why content controls that come after a table would not be seen by the code?  seems to get the null reference there but not sure yet

    Friday, July 17, 2015 3:05 PM
  • Hi Bradley

    No idea. You really don't provide enough technical detail to explore what may be going on... Sample files with full repro steps including code and sample document, plus information on the version of Word involved would be a start.


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, July 17, 2015 4:20 PM
    Moderator
  • using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Wordprocessing;
    using OpenXmlPowerTools.Commands;
    using OpenXmlPowerTools;
    //using DocumentFormat.OpenXml.Office2013.Word;
    using DocumentFormat.OpenXml.ExtendedProperties;
    using DocumentFormat.OpenXml.Office;
    using System.Xml.Linq;
    using System.Xml;
    using System.IO;
    
    
    
    namespace WindowsFormsApplication3
    {
        public  partial class Form1 : Form
        {
            public string outputfileName;
            public byte[] memStream;
            public string fileName = "C:\\Users\\test\\Desktop\\test1.docx";
            
            public Form1()
            {
                InitializeComponent();
                label2.Text = fileName.ToString();
            }
            DocumentFormat.OpenXml.Wordprocessing.Text textContent;
            public void mymethod()
            {
                byte[] byteArray = System.IO.File.ReadAllBytes(fileName);
                using (MemoryStream mem = new MemoryStream())
                {
                    mem.Write(byteArray, 0, (int)byteArray.Length);
                    using (WordprocessingDocument wordDoc =
                        WordprocessingDocument.Open(mem, true))
                    {
                        MainDocumentPart mainDoc = wordDoc.MainDocumentPart;
                        Body bodyDoc = mainDoc.Document.Body;
                        IEnumerable<SdtRun> ccRuns = bodyDoc.Descendants<SdtRun>();
                        int i = 1;
                        foreach (SdtRun ccr in ccRuns)
                        {
                            textContent = ccr.Descendants<Text>().FirstOrDefault();
                            try
                            {
                                richTextBox1.Text += "value: " + ccr.SdtProperties.GetFirstChild<DocumentFormat.OpenXml.Wordprocessing.Tag>().Val.Value + " \n";
                                richTextBox1.Text += "inner text: " + ccr.SdtProperties.GetFirstChild<Tag>().Val.InnerText.ToString() +" \n";
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("exception is: " + ex.ToString());
                                continue;
                            }
                            i++;
                        }
                    }
                }
            }
            private void button1_Click(object sender, EventArgs e)
            {
                mymethod();
            }
    
            private void button2_Click(object sender, EventArgs e)
            {    
            }
        }
    }

    needs:  richtextbox1, button1, button1, label1, label2

    otherwise is there a place i can upload the project to for reference?  here is the entire word doc i just made as a reference.  this is done using the open xml sdk2.5 productivity tool for microsoft office

    the code does not find all of the content controls, this may be a bug.  with the recent document it only sees the last 2 content controls, the others are not found;  with my project it finds the first ones then never sees the later ones after the table.

    ok i cannot post the word document, says 6000 chars max.  how can i post the docx?

    
    


    Friday, July 17, 2015 5:46 PM
  • https://www.dropbox.com/s/kotfsft76hh4og3/TEST1.docx?dl=0

    this is the document .docx file   on my system when the test program is run it only sees 2 content controls.  there are more than 2

    put the docx file on your desktop using explorer, click on the address bar of explorer to change the text to blue, then copy it and paste it into the code's file location.  change the single slash '/' to double slash '//' to make the path work.  docx file must not be open in any other program or it wont load.
    Friday, July 17, 2015 5:51 PM
  • Hi Bradley

    It actually pays to do some research in the documentation, you know. We can only point you in the right direction, based on the information you give us. Content controls are "typed" by where they're located. They're listed in the DocumentFormat.OpenXML.WordProcessing section, under sdt. If you have to be able to pick up any kind, then you need to test for all these different kinds!

    You have three different types in the document you show me: BlockContent, RunContent and Cell.

                    IEnumerable<SdtBlock> ccBlocks = bodyDoc.Descendants<SdtBlock>();
                    int i = 1;
                    foreach (SdtBlock ccb in ccBlocks)
                    {
                        textContent = ccb.Descendants<Text>().FirstOrDefault();
                        if (textContent != null)
                        {
                            textContent.Text = "block" + i;
                            i++;
                        }
                    }
    
                    IEnumerable<SdtCell> ccCellContents = bodyDoc.Descendants<SdtCell>();
                    i = 1;
                    foreach (SdtCell ccc in ccCellContents)
                    {
                        textContent = ccc.Descendants<Text>().FirstOrDefault();
                        if (textContent != null)
                        {
                            textContent.Text = "ccCell" + i;
                            i++;
                        }
                    }
    
                    IEnumerable<SdtContentBlock> ccBlockContents = bodyDoc.Descendants<SdtContentBlock>();
                    i = 1;
                    foreach (SdtContentBlock ccbc in ccBlockContents)
                    {
                        textContent = ccbc.Descendants<Text>().FirstOrDefault();
                        if (textContent != null)
                        {
                            textContent.Text = "blockC" + i;
                            i++;
                        }
                    }
    
                    IEnumerable<SdtRun> ccRuns = bodyDoc.Descendants<SdtRun>();
                    i = 1;
                    foreach(SdtRun ccr in ccRuns)
                    {
                    textContent = ccr.Descendants<Text>().FirstOrDefault();
                    if (textContent != null)
                    {
                        textContent.Text = "test" + i;
                        i++;
                    }
    


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, July 20, 2015 3:44 PM
    Moderator
  • Cindy

    this does work, the concept of having 3 kinds was not clear or was not presented in the documentation i looked at.  nonetheless, it does find the cc's.  it works.



    Monday, July 20, 2015 8:07 PM
  • Hi Bradley

    There are more than three kinds - just so you know. As I said, take a look in the object model...


    Cindy Meister, VSTO/Word MVP, my blog

    Wednesday, July 22, 2015 3:30 PM
    Moderator