Set SdtContentDate date value using OpenXML

Niels van Strien 6 Reputation points
2022-02-15T11:11:25.29+00:00

Hi,

I am trying to set the date value of a content control in a word document using OpenXML. I am using the code at the bottom of this message to find my content control.

The contentcontrol is in a Word table (in a .docx document), so what my FindContentControlByTag finds is a SdtCell element.

I then navigate to the SdtContentDate element via:

    List<OpenXmlElement>? dateCCs = doc.FindContentControlByTag("CCDatePicker");
    OpenXmlElement cc = dateCCs.First();

    var datePickers = cc.Descendants<SdtContentDate>().ToList();

    SdtContentDate datePicker = datePickers.First();

Now that I have my datePicker selected, how can I set the date?

Using

datePicker.FullDate.Value = DateTime.Now;

does not set the date in the contentcontrol - at least it is not visible when opening the document with Word.

Kind regards,

Niels van Strien

public static IEnumerable<OpenXmlElement> ContentControls(this OpenXmlPart part)
        {
            if (part.RootElement != null)
            {
                return part.RootElement.Descendants().Where(e => e is SdtElement);
            }

            return new List<OpenXmlElement>();
            //e is SdtBlock || e is SdtRun, see https://social.msdn.microsoft.com/Forums/office/en-US/4428bfb4-03f6-47d8-8cb1-dd23ed59a4da/cant-find-contentcontrols-inside-the-words-table-openxml-sdk-20?forum=oxmlsdk
        }

        public static IEnumerable<OpenXmlElement> ContentControls(this WordprocessingDocument doc)
        {
            if (doc.MainDocumentPart != null)
            {
                foreach (var cc in doc.MainDocumentPart.ContentControls())
                {
                    yield return cc;
                }

                foreach (var header in doc.MainDocumentPart.HeaderParts)
                {
                    foreach (var cc in header.ContentControls())
                    {
                        yield return cc;
                    }
                }

                foreach (var footer in doc.MainDocumentPart.FooterParts)
                {
                    foreach (var cc in footer.ContentControls())
                    {
                        yield return cc;
                    }
                }

                if (doc.MainDocumentPart.FootnotesPart != null)
                {
                    foreach (var cc in doc.MainDocumentPart.FootnotesPart.ContentControls())
                    {
                        yield return cc;
                    }
                }

                if (doc.MainDocumentPart.EndnotesPart != null)
                {
                    foreach (var cc in doc.MainDocumentPart.EndnotesPart.ContentControls())
                    {
                        yield return cc;
                    }
                }
            }
        }

        public static List<OpenXmlElement> FindContentControlByTag(this WordprocessingDocument doc, string tag)
        {
            IEnumerable<OpenXmlElement>? ccs = doc.ContentControls();
            List<OpenXmlElement>? output = new();

            if (ccs != null)
            {
                foreach (var cc in ccs)
                {
                    SdtProperties? props = cc.Elements<SdtProperties>().FirstOrDefault();

                    if (props != null)
                    {
                        Tag? tagElement = props.Elements<Tag>().FirstOrDefault();

                        if (tagElement != null)
                        {
                            //Console.WriteLine(tagElement.Val);

                            if (tagElement.Val == tag)
                            {
                                output.Add(cc);
                            }
                        }
                    }

                }
            }

            return output;
        }
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,904 questions
Word Management
Word Management
Word: A family of Microsoft word processing software products for creating web, email, and print documents.Management: The act or process of organizing, handling, directing or controlling something.
922 questions
0 comments No comments
{count} vote

4 answers

Sort by: Most helpful
  1. Viorel 117K Reputation points
    2022-02-15T14:36:48.003+00:00

    Maybe you must write something like this:

    datePicker.FullDate = new DateTimeValue(DateTime.Now)

    0 comments No comments

  2. Niels van Strien 6 Reputation points
    2022-02-15T14:47:34.313+00:00

    Hi Viorel-1,

    I wrote an extension method, and tried both variants. However, in both cases the content control is not set when opening the Word document.

    datePicker.FullDate.Value = new DateTimeValue(date);
    
    datePicker.FullDate = new DateTimeValue(date);
    
    
            public static void SetDate(this OpenXmlElement cc, DateTime date)
            {
    
                var datePickers = cc.Descendants<SdtContentDate>().ToList();
    
                SdtContentDate datePicker = datePickers.First();
    
                if (datePicker != null && datePicker.FullDate != null)
                {
                    datePicker.FullDate.Value = new DateTimeValue(date);
                }
            }
    
    0 comments No comments

  3. Niels van Strien 6 Reputation points
    2022-02-15T15:28:13.693+00:00

    Following the example provided here (for a openxml checkbox content control): setting-the-value-in-openxml-checkbox-word2013, I changed my extension method to also change the text property (see code below). Now I do see the new date in the SdtContentDate and the calendar opens on the right date when selected. Can somebody perhaps confirm that this is the correct way to set the date programmatically for a SdtContentDate control using OpenXML?

            public static void SetDate(this OpenXmlElement cc, DateTime date)
            {
                var datePickers = cc.Descendants<SdtContentDate>().ToList();
    
                SdtContentDate datePicker = datePickers.First();
                DateTime newDate = date;
    
                if (datePicker != null && datePicker.FullDate != null)
                {
                    datePicker.FullDate.Value = new DateTimeValue(date).Value;
                }
    
                var texts = cc.Descendants<Run>().ToList();
                foreach (var item in texts)
                {
                    item.InnerXml = item.InnerXml.Replace($"{item.InnerText}", $"{date.ToString("dd-MM-yyyy")}");
                }
            }
    

  4. Jack F 0 Reputation points
    2024-08-26T23:59:01.7633333+00:00

    Similar to your answer, I created a function to set the date and the text value of the control using the format set on the date control

            static void UpdateDateContentControls(OpenXmlElement item, string tag, DateTime value)
            {
                var controls = item.Descendants<SdtElement>().Where(sdt => sdt.SdtProperties.GetFirstChild<Tag>()?.Val == tag);
                foreach (var control in controls)
                {
                    var dateElement = control.Descendants<SdtContentDate>().FirstOrDefault();
                    var format = "dd/MM/yyyy";
                    if (dateElement != null)
                    {
                        dateElement.FullDate.Value = new DateTimeValue(value.ToUniversalTime());
                        if (dateElement.DateFormat != null)
                        format = dateElement.DateFormat.Val;
                    }
                    var text = control.Descendants<Text>().FirstOrDefault();
                    if (text != null)
                        text.Text = value.ToString(format);
                }
            }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.