C# : Remove a Picture Content Control fro .docx - c#

I use the following code to find a Picture Content Control using the tagname of this one and after I use the function Remove to remove it in the Word document :
System.IO.File.Copy(templatePath, outputPath, true);
using (WordprocessingDocument doc = WordprocessingDocument.Open(outputPath, true))
{
tagName = "portrait";
controlBlock = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>().Where(r => r.SdtProperties.GetFirstChild<Tag>().Val == tagName).SingleOrDefault();
if (controlBlock != null)
{
controlBlock.Remove();
}
doc.Close();
}
But when I open the created file in Word, the document need to be repaired by Word if not I can't open it. Word also give me this message in the detail of error :
<p> elements are required before every </tc>
When I inspect the word document with Open Xml before and after it been repaired, I don't see any difference
So what is the best way to remove a Picture Content Control in a Word document?

I resolved my problem easily, in fact the error message provided by Word is clear. So I get the parent element of my Picture Control Content and add a new empty paragraph and after I tried to delete the Picture Control Content and it was enough to resolved my problem.
Here is the code :
controlBlock.Parent.AppendChild(new DocumentFormat.OpenXml.Wordprocessing.Paragraph());
controlBlock.Remove();

Related

How to expand Word header and footer via C# word interop

When bulk editing images in the header and footer of word documents via word interop it works perfectly well for most documents. If however the header and footer of a document are collapsed, word crashes.
Now to my question: Can you expand the header/footer section automatically via word interop or do you know of another way to work around this problem?
Additional info:
When expanding the header/footer section manually and saving the document it works again, but that's no reasonable option because there are many documents to edit.
Collapsed header (doesn't work):
Expanded header (works):
The Word error information:
The code I'm using for editing header images:
foreach (Section section in currentDocument.Sections)
{
HeadersFooters headerFooters = section.Headers;
foreach (HeaderFooter headerFooter in headerFooters)
{
InlineShapes inlineShapes = headerFooter.Range.InlineShapes;
foreach (InlineShape shape in inlineShapes)
{
if (shape.Type != WdInlineShapeType.wdInlineShapePicture)
continue;
//[...]
}
}
}
It is possible to turn the full page display on/off:
Word.View vw = currentDocument.ActiveWindow.View;
if (vw.DisplayPageBoundaries == false)
{
vw.DisplayPageBoundaries = true;
}

Retrieve hidden text blocks and replace all content between two of them

I want to use OpenXML to automate Word document creation by taking a given document as a template. This template contains text blocks with a special syntax (namely e.g. «tagname[»...«]tagname») in the form of hidden text (in the font dialog box, the 'Hidden' checkbox in the effects section is activated) so that they don't show up when the document is printed.
Depending on the tagname I want to replace any content which might be already there in the template file between the opening and closing tag with some other content (e.g. in «today[»01/01/2000«]today» the content 01/01/2000 would be substituted with 07/06/2018) preferably preserving the format (e.g. bold, italic or text color).
How can I retrieve the hidden text parts and is there an easy way to replace anything between corresponding tags using C#?
I am not sure what exactly are the text blocks in your template. Instead you can use Content Control from Developer options at the required place, then you can name them from the properties of content control.
today will be name of the Content Control
Once you have all the content control at your template, you can look for specific content control with name and add the new value you want to.
Here is the Snippet to give you an idea.
// Title is name of content control(today), value is what you want to add(1/01/2000)
private static void UpdateControl(WordprocessingDocument document, string title, string value)
{
MainDocumentPart mainPart = document.MainDocumentPart;
var sdtRuns = mainPart.Document.Descendants<SdtRun>()
.Where(run => run.SdtProperties.GetFirstChild<Tag>().Val.Value == title);
foreach (SdtRun sdtRun in sdtRuns)
{
sdtRun.Descendants<Text>().First().Text = value;
}
document.MainDocumentPart.Document.Save();
}

VSTO Word Add-in - insert Content Control around selected text

I'm trying to add a rich text content control around the user's selected text in a Word document.
I'm new to VSTO and Content Controls so i'm using the MSDN examples as a baseline. The example shows this, which adds the Content Control at the chosen position:
private void AddRichTextControlAtSelection()
{
word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;
currentDocument.Paragraphs[1].Range.InsertParagraphBefore();
currentDocument.Paragraphs[1].Range.Select();
Document extendedDocument = Globals.Factory.GetVstoObject(currentDocument);
richTextControl1 = extendedDocument.Controls.AddRichTextContentControl("richTextControl1");
richTextControl1.PlaceholderText = "Enter your first name";
}
However i want the Content Control to wrap around the user's selected text. Any help, please?
What you found is one possibility. More efficient and "cleaner" (IMO) would be to use the constructor that accepts a RANGE object and pass the Range. If you want the user's selection then
richTextControl1 = extendedDocument.Controls.AddRichTextContentControl(extendedDocument.Parent.Selection.Range, "richTextControl1");
//the Parent of a Document is the Word.Application
//Selection is a dependent of the Word.Application
Otherwise, building on your code sample:
richTextControl1 = extendedDocument.Controls.AddRichTextContentControl(currentDocument.Paragraphs[1].Range, "richTextControl1");
Note that if you don't need to work with VSTO's extensions of the Content Controls you don't need to go through the GlobalFactory steps, you can simply insert the "interop" versions of the Content Controls.
Simple fix in the end: currentDocument.ActiveWindow.Selection.Range.Select();

C# DocumentFormat OpenXML Word 2013 Repeating Content Control

I have created a Word 2013 document with a series of content controls. I have a bunch of text controls in the header and then a table that has a repeating content control with more text controls
What I am trying to achieve is via my C# program build some XML that I can use to map to my content controls.
My XML looks like this
<Job>
<JobNo>123</JobNo>
<Staff>Chris Smith</Staff>
<Client>Client 2</Client>
<DateReceived>2015-05-08</DateReceived>
<SampleNo>3</SampleNo>
<Department>Product</Department>
<Status>Open</Status>
<JobSamples>
<Sample>
<SampleNo>1</SampleNo>
<SampleIdentification>Identifier</SampleIdentification>
<AnalyticalTest>AnalyticalTest</AnalyticalTest>
<SampleMatrix>SampleMatrix</SampleMatrix>
<TypeOfTest>TypeOfTest</TypeOfTest>
<SampleStaff>SampleStaff</SampleStaff>
<SampleDueDate>SampleDueDate</SampleDueDate>
</Sample>
<Sample>
<SampleNo>2</SampleNo>
<SampleIdentification>Identifier</SampleIdentification>
<AnalyticalTest>AnalyticalTest</AnalyticalTest>
<SampleMatrix>SampleMatrix</SampleMatrix>
<TypeOfTest>TypeOfTest</TypeOfTest>
<SampleStaff>SampleStaff</SampleStaff>
<SampleDueDate>SampleDueDate</SampleDueDate>
</Sample>
</JobSamples>
</Job>
I have created a word template that has a Custom XML part and have mapped the fields appropriately. My RepeatingContentControl has been mapped to the node and correctly displays two rows of Samples data
However at run time my XML may contain 1....N Samples and so I want the Repeating Content Control to correctly refresh
When I run my code all the other control outside of the repeating content control get refreshed, but the repeating control doesn't.
Do I need to get a handle on the repeating content control in code and add or remove rows accordingly?
If so, how can I do that?
If not, how can I get my repeating control to refresh?
Here is my code:-
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Job Sheet.docx");
using (WordprocessingDocument myDoc = WordprocessingDocument.Open(path, true))
{
// Creates and saves JobXML file
CreateCustomXML(job);
XmlDocument doc = new XmlDocument();
doc.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JobXML.xml"));
MainDocumentPart mainPart = myDoc.MainDocumentPart;
//delete old xml part
mainPart.DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts);
//add new xml part
CustomXmlPart customXml = mainPart.AddCustomXmlPart(CustomXmlPartType.CustomXml);
using (StreamWriter ts = new StreamWriter(customXml.GetStream()))
{
ts.Write(doc.OuterXml);
}
}

Find Content Control by TagName in Word document in OpenXml

I am attempting to insert text in to a content control in my word document template using OpenXml. First I search the content control by its tag name and then adding paragraph element in the SdtBlock like below,
SdtBlock contentBlock = wordDoc.MainDocumentPart.Document.Body.Descendants<SdtBlock>()
.Where(r => r.SdtProperties.GetFirstChild<Tag>().Val == "AssessmentSection")
.Single();
But when I execute this statement, I am getting "Object reference not set to an instance of an object." error message. The template document already has another content control and I was able to find that control using the same above statement with only tagname as different. But after adding "AssessmentSection" content control in template and while running the program, I get "Object Reference..." error for "AssessmentSection" control and the program fails. I am sure the new content control tag name and title are unique with other content control.
Can someone please help me why this strange behaviour is occurring and how to fix it???
you also could loop the documents ContentControls items and check their tags, like:
foreach (Word.ContentControl contentcontrol in wordDoc.ContentControls)
{
if (contentcontrol.Tag != null)
{
...
}
}

Categories

Resources