Maybe you must write something like this:
datePicker.FullDate = new DateTimeValue(DateTime.Now)
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
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;
}
Maybe you must write something like this:
datePicker.FullDate = new DateTimeValue(DateTime.Now)
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);
}
}
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")}");
}
}
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);
}
}