How does one get a handle to a CheckBox control that's embedded in a Word document using OpenXML?
You would think that either Paragraph.ControlPropertiesPart or Paragraph.Descendents() would achieve something but in every single case I get a null type returned.
I can traverse down the document tree using the actual XML structure, but this seems cumbersome.
Suggestions welcome.
The code below shows how to enumerate all checkboxes in a word document by
using the Decendants<CheckBox>()
method on the docuement's body.
using (WordprocessingDocument doc = WordprocessingDocument.Open("c:\\temp\\checkbox.docx", true))
{
foreach (CheckBox cb in doc.MainDocumentPart.Document.Body.Descendants<CheckBox>())
{
Console.Out.WriteLine(cb.LocalName);
FormFieldName cbName = cb.Parent.ChildElements.First<FormFieldName>();
Console.Out.WriteLine(cbName.Val);
DefaultCheckBoxFormFieldState defaultState = cb.GetFirstChild<DefaultCheckBoxFormFieldState>();
Checked state = cb.GetFirstChild<Checked>();
Console.Out.WriteLine(defaultState.Val.ToString());
if (state.Val == null) // In case checkbox is checked the val attribute is null
{
Console.Out.WriteLine("CHECKED");
}
else
{
Console.Out.WriteLine(state.Val.ToString());
}
}
}
To determine the name of a given checkbox input element you have to access the
Parent
property of the CheckBox
instance and then search for the FormFieldName
element (to assign a name to a checkbox use the Properties Dialog in Microsoft Word).
The DefaultCheckBoxFormFieldState
Val
property holds the default state for the checkbox.
Furthermore the Val
property of the Checked
element holds the actual checked state
of the CheckBox
instance. Note, for Microsoft Word 2007 the Val property is null
if
the checkbox is checked.
BEGIN EDIT
I'd like to extend my answer. In fact, there are two kinds of checkbox controls on the MS Word developer tab - a legacy checkbox and an ActiveX control checkbox. The code shown above can be used to enumerte legacy checkboxes in a word document (see this article on how to create a legacy checkbox).
As far as I know, you can't use the OpenXML SDK to get/set values for an ActiveX checkbox. However you can enumerate ActiveX controls using the following code:
foreach (Control ctrl in doc.MainDocumentPart.Document.Body.Descendants<Control>())
{
Console.Out.WriteLine(ctrl.Id);
Console.Out.WriteLine(ctrl.Name);
Console.Out.WriteLine(ctrl.ShapeId);
}
To determine whether or not a given Control
is a checkbox you have to ckeck the class ID of the Control
. The class ID of a checkbox is {8BD21D40-EC42-11CE-9E0D-00AA006002F3}
.
Here is a code sample to get the class ID (I don't know if there is an easier way...):
OpenXmlPart part = doc.MainDocumentPart.GetPartById(ctrl.Id);
OpenXmlReader re = OpenXmlReader.Create(part.GetStream());
re.Read();
OpenXmlElement el = re.LoadCurrentElement();
if(el.GetAttribute("classid", el.NamespaceUri).Value == "{8BD21D40-EC42-11CE-9E0D-00AA006002F3}")
{
Console.WriteLine("Checkbox found...");
}
re.Close();
END EDIT
EDIT 2
I didn't realize that there is a new checkbox control in Word 2010 (Thanks to Dennis Palmer).
To enumerate those new checkbox controls you can use the following code:
using (WordprocessingDocument doc = WordprocessingDocument.Open(filename, true))
{
MainDocumentPart mp = doc.MainDocumentPart;
foreach(SdtContentCheckBox cb in mp.Document.Body.Descendants<SdtContentCheckBox>())
{
if(cb.Checked.Val == "1");
{
Console.Out.WriteLine("CHECKED");
}
}
}
END EDIT 2
Hope, this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With