Working with Paragraphs

A paragraph is a set of characters combined into a logical block and ending with a special character – a paragraph break. In Aspose.Words, a paragraph is represented by the Paragraph class.

Insert a Paragraph

To insert a new paragraph into the document, in fact, you need to insert a paragraph break character into it. DocumentBuilder.Writeln inserts not only a string of text into the document, but also adds a paragraph break.

The current font formatting is also specified by the Font property, and the current paragraph formatting is determined by the ParagraphFormat property. In the next section, we will go into more detail about paragraph formatting.

The following code example shows how to insert a paragraph into a document:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
Font font = builder.Font;
font.Size = 16;
font.Bold = true;
font.Color = Color.Blue;
font.Name = "Arial";
font.Underline = Underline.Dash;
ParagraphFormat paragraphFormat = builder.ParagraphFormat;
paragraphFormat.FirstLineIndent = 8;
paragraphFormat.Alignment = ParagraphAlignment.Justify;
paragraphFormat.KeepTogether = true;
builder.Writeln("A whole paragraph.");
doc.Save(ArtifactsDir + "AddContentUsingDocumentBuilder.InsertParagraph.docx");

Format Paragraph

Current paragraph formatting is represented by the ParagraphFormat object that is returned by the ParagraphFormat property. This object encapsulates various paragraph formatting properties available in Microsoft Word. You can easily reset a paragraph’s formatting to its default – Normal style, left-aligned, no indentation, no spacing, no borders, no shading – by calling ClearFormatting.

The following code example shows how to set paragraph formatting:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
ParagraphFormat paragraphFormat = builder.ParagraphFormat;
paragraphFormat.Alignment = ParagraphAlignment.Center;
paragraphFormat.LeftIndent = 50;
paragraphFormat.RightIndent = 50;
paragraphFormat.SpaceAfter = 25;
builder.Writeln(
"I'm a very nice formatted paragraph. I'm intended to demonstrate how the left and right indents affect word wrapping.");
builder.Writeln(
"I'm another nice formatted paragraph. I'm intended to demonstrate how the space after paragraph looks like.");
doc.Save(ArtifactsDir + "DocumentFormatting.ParagraphFormatting.docx");

Apply Paragraph Style

Some formatting objects, such as Font or ParagraphFormat, support styles. One built-in or user-defined style is represented by a Style object, which contains the appropriate style properties like name, base style, font, style paragraph formatting, and so on.

In addition, the Style object exposes the StyleIdentifier property, which returns the locale-independent style identifier represented by the StyleIdentifier enumeration value. The fact is that the names of the built-in styles in Microsoft Word are localized for different languages. Using the style identifier, you can find the correct style regardless of the document language. The enumeration values correspond to the built-in Microsoft Word styles such as Normal, Heading 1, Heading 2 and so on. All user-defined styles are set to the StyleIdentifier.User enumeration value.

The following code example shows how to apply a paragraph style:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Title;
builder.Write("Hello");
doc.Save(ArtifactsDir + "DocumentFormatting.ApplyParagraphStyle.docx");

Insert Style Separator to Put Different Paragraph Styles

A style separator can be added to the end of a paragraph using the keyboard shortcut Ctrl+Alt+Enter in Microsoft Word. This feature allows you to use two different paragraph styles in the same logical printed paragraph. If you want some text from the beginning of a particular heading to appear in the table of contents, but do not want the entire heading to show in the table of contents, you can use this function.

The following code example shows how to insert a style separator to accommodate different paragraph styles:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
Style paraStyle = builder.Document.Styles.Add(StyleType.Paragraph, "MyParaStyle");
paraStyle.Font.Bold = false;
paraStyle.Font.Size = 8;
paraStyle.Font.Name = "Arial";
// Append text with "Heading 1" style.
builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1;
builder.Write("Heading 1");
builder.InsertStyleSeparator();
// Append text with another style.
builder.ParagraphFormat.StyleName = paraStyle.Name;
builder.Write("This is text with some other formatting ");
doc.Save(ArtifactsDir + "WorkingWithStylesAndThemes.InsertStyleSeparator.docx");

Identify Paragraph Style Separator

Aspose.Words exposes the BreakIsStyleSeparator public property on the Paragraph class to identify a paragraph with a style separator, as shown in the example below:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document(MyDir + "Document.docx");
foreach (Paragraph paragraph in doc.GetChildNodes(NodeType.Paragraph, true))
{
if (paragraph.BreakIsStyleSeparator)
{
Console.WriteLine("Separator Found!");
}
}

Apply Borders and Shading to a Paragraph

Borders in Aspose.Words are represented by the BorderCollection class – this is a collection of Border objects that are accessed by index or by border type. The border type is in turn represented by the BorderType enumeration. Some enumeration values apply to multiple or only one document element. For example, BorderType.Bottom applies to a paragraph or table cell, while BorderType.DiagonalDown specifies a diagonal border in a table cell only.

Both the border collection and each separate border have similar attributes such as color, line style, line width, distance from text, and optional shadow. They are represented by properties of the same name. You can get different border types by combining property values. In addition, the BorderCollection and Border objects allow you to reset these values to their default values by calling the ClearFormatting method.

Aspose.Words also has the Shading class that contains shading attributes for document elements. You can set the desired shading texture and colors that are applied to the background and foreground of an element using the TextureIndex enumeration value. TextureIndex also allows you to apply different patterns to the Shading object. For example, to set the background color for a document element, use the TextureIndex.TextureSolid value and set the foreground shading color as appropriate.

The following code example shows how to apply borders and shading to a paragraph:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
BorderCollection borders = builder.ParagraphFormat.Borders;
borders.DistanceFromText = 20;
borders[BorderType.Left].LineStyle = LineStyle.Double;
borders[BorderType.Right].LineStyle = LineStyle.Double;
borders[BorderType.Top].LineStyle = LineStyle.Double;
borders[BorderType.Bottom].LineStyle = LineStyle.Double;
Shading shading = builder.ParagraphFormat.Shading;
shading.Texture = TextureIndex.TextureDiagonalCross;
shading.BackgroundPatternColor = System.Drawing.Color.LightCoral;
shading.ForegroundPatternColor = System.Drawing.Color.LightSalmon;
builder.Write("I'm a formatted paragraph with double border and nice shading.");
doc.Save(ArtifactsDir + "DocumentFormatting.ApplyBordersAndShadingToParagraph.doc");

Count Paragraph Lines

If you want to count the number of lines in a paragraph for any Word document, the following code sample can be used:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-.NET.git.
public void GetParagraphLines()
{
Document doc = new Document(MyDir + "Properties.docx");
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
foreach (Paragraph paragraph in doc.GetChildNodes(NodeType.Paragraph, true))
{
ProcessParagraph(paragraph, collector, enumerator);
}
}
private static void ProcessParagraph(Paragraph paragraph, LayoutCollector collector, LayoutEnumerator enumerator)
{
object paragraphBreak = collector.GetEntity(paragraph);
if (paragraphBreak == null)
return;
object stopEntity = GetStopEntity(paragraph, collector, enumerator);
enumerator.Current = paragraphBreak;
enumerator.MoveParent();
int lineCount = CountLines(enumerator, stopEntity);
string paragraphText = GetTruncatedText(paragraph.GetText());
Console.WriteLine($"Paragraph '{paragraphText}' has {lineCount} line(-s).");
}
private static object GetStopEntity(Paragraph paragraph, LayoutCollector collector, LayoutEnumerator enumerator)
{
Node previousNode = paragraph.PreviousSibling;
if (previousNode == null)
return null;
if (previousNode is Paragraph prevParagraph)
{
enumerator.Current = collector.GetEntity(prevParagraph); // Para break.
enumerator.MoveParent(); // Last line.
return enumerator.Current;
}
else if (previousNode is Table table)
{
enumerator.Current = collector.GetEntity(table.LastRow.LastCell.LastParagraph); // Cell break.
enumerator.MoveParent(); // Cell.
enumerator.MoveParent(); // Row.
return enumerator.Current;
}
else
{
throw new InvalidOperationException("Unsupported node type encountered.");
}
}
/// <summary>
/// We move from line to line in a paragraph.
/// When paragraph spans multiple pages the we will follow across them.
/// </summary>
private static int CountLines(LayoutEnumerator enumerator, object stopEntity)
{
int count = 1;
while (enumerator.Current != stopEntity)
{
if (!enumerator.MovePreviousLogical())
break;
count++;
}
return count;
}
private static string GetTruncatedText(string text)
{
int MaxChars = 16;
return text.Length > MaxChars ? $"{text.Substring(0, MaxChars)}..." : text;
}