I want to programmatically lock all content controls so that the user cannot delete them.
I am using the following code, but my problem is that in a few cases I am getting null when calling elem.SdtProperties.ChildElements.First<WP.Lock>().
Can someone help me complete the below mentioned code?
static void MakeContentControlsNonDeletable()
{
using (P.WordprocessingDocument wordDoc =
P.WordprocessingDocument.Open(@"c:\XYZ.docx", true))
{
IEnumerable<WP.SdtElement> elements =
wordDoc.MainDocumentPart.Document.Descendants<WP.SdtElement>();
foreach (WP.SdtElement elem in elements)
{
if (elem.SdtProperties != null)
{
WP.Lock l = elem.SdtProperties.ChildElements.First<WP.Lock>();
if (l == null)
{
//Please help here
//Please help here
//Please help here
//Please help here
}
if (l.Val != WP.LockingValues.SdtContentLocked && l.Val != WP.LockingValues.SdtLocked)
{
Console.WriteLine("Unlock content element...");
l.Val = WP.LockingValues.SdtLocked;
}
}
}
}
It seems your code is fine. I've had the same problems before in another scenario where there is a certain object and it returns null. I don't know what's wrong with openxml sdk at that point but I can tell you how I did solve mine.
The problem basically is that at certain points deep in the structure you know there is a element that should be interpreted as a Lock object but the sdk can see it only as OpenXmlElement (not its subclass Lock object), so thats why when you do First<WP.Lock>() you expect a Lock object and you know its there but you just get null. What I do is treat everything as OpenXmlElement and forget about the strong typing.
static void MakeContentControlsNonDeletable()
{
using (P.WordprocessingDocument wordDoc =
P.WordprocessingDocument.Open(@"c:\XYZ.docx", true))
{
IEnumerable<OpenXmlElement> elements =
wordDoc.MainDocumentPart.Document.Descendants<>(child => child.LocalName == "sdt");
foreach (OpenXmlElement elem in elements)
{
if (elem.ChildElements.Any(child => child.LocalName == "sdtPr"))
{
OpenXmlElement sdtPr = elem.ChildElements.FirstOrDefault(child => child.LocalName == "sdtPr");
OpenXmlElement l = sdtPr.ChildElements.FirstOrDefault(child => child.LocalName == "lock");
if (l == null) //At this point if you have your lock object this isn't null
{
//Please help here
//Please help here
//Please help here
}
OpenXmlAttribute valAttribute = l.GetAttribute("val", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
if (valAttribute != null) {
valAttribute = new OpenXmlAttribute();
}
if (valAttribute.Value != "sdtContentLocked" && valAttribute.Value != "sdtLocked")
{
Console.WriteLine("Unlock content element...");
valAttribute.Value = "sdtLocked";
}
}
}
}
I know this isn't the way it's supposed to be and I know that all objects should be strongly typed to its respective openxml sdk class but that's something that happens a lot and that's why I do it this way.
Hope it 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