add character spacing for range of character in open xml c# - c#

how to add character spacing for range of characters
like i want to give character spacing In word toggling for 2 characters
gg of spacing="Expanded" with By value of 4pt

Open XML has not only SDK, but also a tool for converting any document to C# code.
Best way to find out how to use some word feature is to make 2 short documnets - one with this feature used and the other - without. Then convert both documnets into C# code and compare generated code (you can use WinMerge, for example).

As you wish to apply a style to the middle of a paragraph you will need to have (at least) 3 separate Run elements; the first for the start of the unstyled text, the second for the text that has the spacing and the third for the rest of the unstyled text.
To add the character spacing you need to add a Spacing element to the Run. The Spacing element has a Value property that sets the spacing you want in twentieths of a point (so to get 4pt you need to set the Value to 80).
The following code will create a document with spacing on the gg in the word toggling
public static void CreateDoc(string fileName)
{
// Create a Wordprocessing document.
using (WordprocessingDocument package =
WordprocessingDocument.Create(fileName, WordprocessingDocumentType.Document))
{
// Add a new main document part.
package.AddMainDocumentPart();
//create a body and a paragraph
Body body = new Body();
Paragraph paragraph = new Paragraph();
//add the first part of the text to the paragraph in a Run
paragraph.AppendChild(new Run(new Text("This sentence has spacing between the gg in to")));
//create another run to hold the text with spacing
Run secondRun = new Run();
//create a RunProperties with a Spacing child.
RunProperties runProps = new RunProperties();
runProps.AppendChild(new Spacing() { Val = 80 });
//append the run properties to the Run we wish to assign spacing to
secondRun.AppendChild(runProps);
//add the text to the Run
secondRun.AppendChild(new Text("gg"));
//add the spaced Run to the paragraph
paragraph.AppendChild(secondRun);
//add the final text as a third Run
paragraph.AppendChild(new Run(new Text("ling")));
//add the paragraph to the body
body.AppendChild(paragraph);
package.MainDocumentPart.Document = new Document(body);
// Save changes to the main document part.
package.MainDocumentPart.Document.Save();
}
}
The above produces the following:
Note that you can set the Value of the Spacing to a negative number and the text will be condensed rather than expanded.

Related

Finding list of objects that contain full or just part of searched string

I've a list of paragraphs. Each paragagraph can contain Text. I'm trying to search for a string that may be as whole within a single paragraph, or spread across multiple paragraphs with as bad case where each letter is different paragraph.
public List<WordParagraph> FindText(string text) {
List<WordParagraph> list = new List<WordParagraph>();
var found = false;
Paragraph currentParagraph = null;
foreach (var paragraph in this.Paragraphs) {
//if (currentParagraph == null) {
// currentParagraph = paragraph._paragraph;
//} else {
// if (currentParagraph != paragraph._paragraph) {
// found = false;
// }
//}
// paragraph.Text
// logic missing to find text that can start within some paragraph.Text, but
// can span across multiple paragraphs
// for example searching for text "This Is MyTest" within 4 paragraphs that
// may be written like
// paragraph.Text = "Thi"
// paragraph.Text = "s Is"
// paragraph.Text = " MyTes"
// paragraph.Text = "t"
}
return list;
}
I've tried some logic around foreach char in text, and nested loop over text from the paragraph.text but the logic was failing me.
To give you a bit of background. Consider a Word Document that has a single sentence - one long sentence but each word, or even letter is formatted differently - different font size, bold, underline or whatever. It looks like this:
Now what Word actually saved in the file is a single paragraph, but each paragraph has multiple "runs". The run contains a Text element. Each text element contains the text that you see in Word, but due to formatting of possibly even each word it can be split into many many small Text properties.
Now in my example, I've simplified the logic and for me, each "run" is a paragraph with a text. So List of WordParagraphs is a list of runs within Screenshot you see.
Now I need to find a string "I have that" from the whole sentence you see in word. That means I need to go thru all paragraphs, find the first letter that matches and then check if next letter matches as well, if not I need to start again.
My brain is having hard time to grasp this logic in code.

Apply bold formatting to specific text on Powerpoint textbox programmatically

I have a code that iterates through all the shapes in a Powerpoint presentation (single slide), finds the one that is a textbox and checks whether it is the one I want to replace the text with (and does so if it is, obviously).
All that is working fine, but I want to set the text bold in 2 parts of the text: the name of the person and the name of the course (it's a diploma). I have tried adjusting the ideas/code from this answer, but to no success.
Could anybody help me?
Below is the code I have:
Presentation certificadoCOM = powerpointApp.Presentations.Open(#"C:\Users\oru1ca\Desktop\certCOM.pptx");
// iterates through all shapes
foreach (Shape shape in certificadoCOM.Application.ActivePresentation.Slides.Range().Shapes)
{
// gets the name of the shape and checks whether is a textbox
string shapeName = shape.Name;
if (shapeName.StartsWith("Text Box"))
{
// gets the text from the shape, and if it's the one to change, replace the text
string shapeText = shape.TextFrame.TextRange.Text;
if (shapeText.StartsWith("Concedemos"))
{
shape.TextFrame.TextRange.Text = "Concedemos à Sra. " + nomeP[i] + ",\n representando [...]";
}
}
}
TextRange has methods to select a range of text within the TextFrame.
For example, .Words(int) will select a selection of words (a set of characters separated via spaces) which you can then apply styles to (in this case .Bold.
Code example:
//Set the first 3 words as bold.
shape.TextFrame.TextRange.Words(3).Font.Bold = true;

How to align center a paragraph using open xml c#

I am trying to align to center a paragraph but is not having any affection on the paragraph.I am using OpenXml. Below is the code:
//paragraph properties
ParagraphProperties User_heading_pPr = new ParagraphProperties();
//trying to align center a paragraph
Justification justification1 = new Justification() { Val = JustificationValues.Center };
// build paragraph piece by piece
Text text = new Text(DateTime.Now.ToString() + " , ");
Text text1 = new Text(gjenerimi + " , ");
Text text2 = new Text(merreshifren());
var run = new Run();
run.Append(text,text1,text2);
Paragraph newParagraph = new Paragraph(run);
User_heading_pPr.Append(justification1);
newParagraph.Append(User_heading_pPr);
Here is how I am trying to align center the paragraph.
Reverse the order in which you assign text and paragraph properties:
User_heading_pPr.Append(justification1);
Paragraph newParagraph = new Paragraph(User_heading_pPr);
newParagraph.Append(run);
In valid and well-formed Word Open XML the paragraph properties must precede the run. So you have to build the Open XML document the same way.
This is a bit different than object models, the way we're typically used to dealing with them - the order does matter!

How to highlight text using string indexes in WPF RichTextBox?

I'm working on a custom RichTextBox which highlights certain words typed in it.
(more like highlight certain strings, because I intent to highlight strings that are not separated by spaces)
I search for strings by loading the text to memory, and looking for a list of strings one by one, then applying formatting to them.
Issue is that, index I get from the plain text representation, doesn't necessarily point to the same position in the RichTextBox's content, when formatting is applied.
(First formatting is perfect. Any subsequent formatting starts to slip to the left. I assume this is because formatting adds certain elements to the documents which makes my indexes incorrect.)
Sample pseudo code for this is as follows.
// get the current text
var text = new TextRange(Document.ContentStart, Document.ContentEnd).Text;
// loop through and highlight
foreach (string entry in WhatToHighlightCollection)
{
var currentText = text;
var nextOccurance = currentText.IndexOf(suggestion); //This index is Unreliable !!!
while (nextOccurance != -1)
{
// Get the offset from start. (There appears to be 2 characters in the
// beginning. I assume this is document and paragraph start tags ??
// So add 2 to it.)
int offsetFromStart = (text.Length) - (currentText.Length) + 2;
var startPointer = Document.ContentStart.
GetPositionAtOffset(offsetFromStart + nextOccurance, LogicalDirection.Forward);
var endPointer = startPointer.GetPositionAtOffset(suggestion.Length, LogicalDirection.Forward);
var textRange = new TextRange(startPointer, endPointer);
textRange.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
textRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold);
textRange.ApplyPropertyValue(TextElement.FontFamilyProperty, new FontFamily("Segoe UI"));
// Go to the next occurance.
currentText = currentText.Substring(nextOccurance + suggestion.Length);
nextOccurance = currentText.IndexOf(suggestion);
}
}
How do I map string indexes to rich text box content ?
NOTE: I'm not worried about the performance of this at the moment, although any suggestions are always welcome, as currently I run this on every TextChanged event to highlight 'as the user type' and it's getting a bit sluggish.

"\r\n" appears as small square boxes in word document, C#

I am appending some text containing '\r\n' into a word document at run-time.
But when I see the word document, they are replaced with small square boxes :-(
I tried replacing them with System.Environment.NewLine but still I see these small boxes.
Any idea?
the answer is to use \v - it's a paragraph break.
Have you not tried one or the other in isolation i.e.\r or \n as Word will interpret a carriage return and line feed respectively. The only time you would use the Environment.Newline is in a pure ASCII text file. Word would handle those characters differently! Or even a Ctrl+M sequence. Try that and if it does not work, please post the code.
Word uses the <w:br/> XML element for line breaks.
After much trial and error, here is a function that sets the text for a Word XML node, and takes care of multiple lines:
//Sets the text for a Word XML <w:t> node
//If the text is multi-line, it replaces the single <w:t> node for multiple nodes
//Resulting in multiple Word XML lines
private static void SetWordXmlNodeText(XmlDocument xmlDocument, XmlNode node, string newText)
{
//Is the text a single line or multiple lines?>
if (newText.Contains(System.Environment.NewLine))
{
//The new text is a multi-line string, split it to individual lines
var lines = newText.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
//And add XML nodes for each line so that Word XML will accept the new lines
var xmlBuilder = new StringBuilder();
for (int count = 0; count < lines.Length; count++)
{
//Ensure the "w" prefix is set correctly, otherwise docFrag.InnerXml will fail with exception
xmlBuilder.Append("<w:t xmlns:w=\"http://schemas.microsoft.com/office/word/2003/wordml\">");
xmlBuilder.Append(lines[count]);
xmlBuilder.Append("</w:t>");
//Not the last line? add line break
if (count != lines.Length - 1)
{
xmlBuilder.Append("<w:br xmlns:w=\"http://schemas.microsoft.com/office/word/2003/wordml\" />");
}
}
//Create the XML fragment with the new multiline structure
var docFrag = xmlDocument.CreateDocumentFragment();
docFrag.InnerXml = xmlBuilder.ToString();
node.ParentNode.AppendChild(docFrag);
//Remove the single line child node that was originally holding the single line text, only required if there was a node there to start with
node.ParentNode.RemoveChild(node);
}
else
{
//Text is not multi-line, let the existing node have the text
node.InnerText = newText;
}
}

Categories