Get a CheckBox in Word using OpenXML
Asked Answered
F

1

9

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.

Fortuneteller answered 1/12, 2011 at 3:55 Comment(1)
Are you using a Check Box Content Control?Epitaph
D
12

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.

Dally answered 4/12, 2011 at 13:47 Comment(11)
That's what I would have expected to work, except the three checkboxes I have put in my code are still not being picked up. I can't for the life of me figure out what I've done. Unless there are different types of checkboxes. I've created a sample document and inserted the checkboxes from the Controls group in the Developer tab.Fortuneteller
@Phil.Wheeler: Do you use the ActiveX Checkbox or the legacy checkbox control? Note, the code above only works with the legacy checkbox.Dally
I'd say it was the ActiveX control. It's a brand new document created for purpose and the checkbox was added through the Developer tab in Word 2010. I don't see how the legacy control would have even appeared in the equation.Fortuneteller
@Phil.Wheeler: I've updated my answer. In fact, there are two kinds of checkboxes - legacy checkboxes and ActiveX control checkboxes. Please see my answer above on how to enumerate ActiveX checkboxes.Dally
Thanks. Having thought to actually open my eyes and look at the tab group, I found the "Legacy Tools" control group under a smart button (of sorts) at the lower right of the standard group of controls.Fortuneteller
Word 2010 adds a brand new type of Check Box -- the Check Box Content Control. I didn't think content controls were ActiveX and it's definitely not legacy.Epitaph
@DennisPalmer: Thank you! I didn't realize that there is a new checkbox control in Word2010. I've updated my answer to reflect this.Dally
@Phil.Wheeler: I've updated my answer to show how to enumerate the new checkbox controls in Word2010. So, there are three kinds of checkboxes: Legacy, ActiveX and Content Checkboxes.Dally
What namespace do you find the StdContentCheckBox control in?Fortuneteller
@Phil.Wheeler: There was a typo in my answer. The name of the class is SdtContentCheckBox. The namespace is DocumentFormat.OpenXml.Office2010.Word.Dally
Gah! Of course it is. Never even thought about that despite mis-typing it numerous times already.Fortuneteller

© 2022 - 2024 — McMap. All rights reserved.