Lock or Protect Regions or Specific Parts in Word Document using C# .NET | Create Editable Range without using Document Builder

Hi,

We were also looking for this feature - i.e the ability to lock specific parts of a Word document.

As this wasn’t supported in our current version of Aspose, we have achieved this ourselves using OpenXml, but ideally would like to move to use the Aspose API when we upgrade to the latest version.

I’m just testing with Aspose 16.1 and attempting to implement the same functionality using Aspose.

In our existing implementation, we mark the entire document as ReadOnly with certain ranges in the document editable via PermStart and related elements (https://docs.microsoft.com/en-us/previous-versions/office/developer/office-2010/cc847826(v=office.14)).

The Aspose documentation is a bit patchy but it appears the only way to achieve similar behaviour is to use Sections and set the editable Sections through ProtectedForForms property (https://reference.aspose.com/words/net/aspose.words/section/properties/protectedforforms).

However this requires us to use Sections and more importantly appears to only work if you protect the document with ProtectionType.AllowOnlyFormFields rather than ReadOnly. This would mean we still cannot reproduce our current behaviour.

Is this correct?

Thanks

Alastair

Hi Alastair,

Thanks for your inquiry. You can mark whole document as read-only and specify editable regions in Word document. I believe, you can meet this requirement after running the following code:

Document doc = new Document();
doc.RemoveAllChildren();
Section section = new Section(doc);
doc.AppendChild(section);
Body body = new Body(doc);
section.AppendChild(body);
Paragraph para = new Paragraph(doc);
body.AppendChild(para);
Run run = new Run(doc);
run.Text = "Hello ";
run.Font.Color = System.Drawing.Color.Red;
para.AppendChild(run);
Run run2 = new Run(doc);
run2.Text = "World!";
para.AppendChild(run2);
doc.Protect(ProtectionType.ReadOnly);
DocumentBuilder builder = new DocumentBuilder(doc);
EditableRangeStart start = builder.StartEditableRange();
EditableRangeEnd end = builder.EndEditableRange();
run2.ParentNode.InsertBefore(start, run2);
run2.ParentNode.InsertAfter(end, run2);
doc.Save(MyDir + @"16.1.0.docx");

Hope, this helps.

Best regards,

Hi,

Thanks, but is this possible using the low-level API rather than having to use the DocumentBuilder?

My understanding is that all functions of DocumentBuilder should be possible using the underlying API, but not sure here since EditableRangeStart is internal.

If not, is this due to change in future?

Thanks

Hi Alastair,

Thanks for your inquiry. Currently there are no public constructors for EditableRange, EditableRangeStart and EditableRangeEnd classes that is why you cannot use DOM classes to create new editable range in document. We have logged your requirement in our issue tracking system as WORDSNET-13251. Our product team will further look into the details of this problem and we will keep you updated on the status of this issue. We apologize for any inconvenience.

Best regards,

Hi Alastair,

Regarding WORDSNET-13251, can you please elaborate your usecase in more details? What is the goal that you want to achieve? The DocumentBuilder class was intended to simplify things, i.e. achieve more result while writing less code. So when we see a compelling usecase where writing more code can help the customers achieve more result, we may start thinking about providing that capability to the public. So if you please provide a deeper reasoning behind this request, there is more probability that this issue will be addressed. Thanks for your cooperation.

Best regards,

Hi,

I’ve got an existing document that contains content controls. Some of these controls indicate that the contained content should be locked for editing.

I’m trying to replace the content control with its child nodes wrapped with an End and Start Editable range tag.

For other content controls that we deal with, the following code has worked fine to move the content controls child node outside of the control itself.

var childNodes = contentControl.ChildNodes.ToArray();
foreach (var childNode in childNodes)
{
    contentControl.ParentNode.InsertBefore(childNode, contentControl);
}
contentControl.Remove();

But I’ve not been able to do the same using the DocumentBuilder. I just get

Cannot insert a node of this type at this location.

I’ve also had problems using MoveTo, since it only allows me to move to Paragraphs or inline nodes.

Hi Alastair,

Thanks for your inquiry. Could you please attach your input Word document and expected document here for our reference? We will investigate the structure of your expected document as to how you want your final output be generated like. You can create expected document using Microsoft Word. We will then provide you code to achieve the same using Aspose.Words.

Regarding DocumentBuilder.MoveTo method, It moves the cursor to an inline node or to the end of a paragraph. The node must be a paragraph or a direct child of a paragraph.

When node is an inline-level node, the cursor is moved to this node and further content will be inserted before that node.

When node is a Paragraph, the cursor is moved to the end of the paragraph and further content will be inserted just before the paragraph break.

When node is a block-level node but not a Paragraph, the cursor is moved to the end of the first paragraph into block-level node and further content will be inserted just before the paragraph break.

Best regards,

I’ve attached an archive with the files used for unit testing

LockedArea.docx is the source document.

It contains some text with part of it wrapped by a content control indicating that the contained content should be locked in the output document.

LockedArea-Expected.docx is the desired output document.

Thanks

PS Please bear in mind that the service we are using to do the transformation is generic so any solution needs to be able to handle any content in the content control.

So it is not sufficient just to be able to hand code the generation of that output document.

Hope this makes sense.

Thanks

Alastair

Hi Alastair,

Thanks for your inquiry. Please use the following code to meet this requirement:

Document doc = new Document(filePath);

doc.Protect(ProtectionType.ReadOnly);

DocumentBuilder builder = new DocumentBuilder(doc);

EditableRangeStart start = builder.StartEditableRange();

EditableRangeEnd end = builder.EndEditableRange();

doc.FirstSection.Body.FirstParagraph.InsertBefore(start, doc.FirstSection.Body.FirstParagraph.Runs[0]);

doc.FirstSection.Body.FirstParagraph.InsertAfter(end, doc.FirstSection.Body.FirstParagraph.Runs[0]);

EditableRangeStart start1 = builder.StartEditableRange();

EditableRangeEnd end1 = builder.EndEditableRange();

doc.FirstSection.Body.LastParagraph.InsertBefore(start1, doc.FirstSection.Body.LastParagraph.FirstChild);

doc.FirstSection.Body.LastParagraph.InsertAfter(end1, doc.FirstSection.Body.LastParagraph.LastChild);

doc.Save(MyDir + @"16.4.0.docx");

Hope, this helps.

PS: I am afraid this is not a generic solution but it will help you understand how to place EditableRangeStart and EditableRangeEnd nodes at the correct place in DOM.

Best regards,

@alastair.hails,

Regarding WORDSNET-13251, we have completed the work on your issue and concluded that we would not be able to implement any fix of this issue in Aspose.Words API. Your issue (WORDSNET-13251) has now been closed with ‘Won’t Fix’ resolution. DocumentBuilder was intended to simplify things, i.e. achieve more result while writing less code. So when we see a compelling usecase where writing more code can help achieve more result, we may then provide such capability via public classes. But, in this case you can easily meet this requirement by using DocumentBuilder class.