Positions and Ranges
- 7 minutes to read
Position and range are key entities in the RichEditControl. They define the location of every object in a document model.
Position
Position (the DocumentPosition object) is a zero-based index of every symbol in a document. Each position identifies a possible placement for a text cursor. Position 0 is the beginning of a document and precedes the first character. When the caret moves to the next character, it moves to position 1 and so on.
Obtain a Position
The following code sample calls the SubDocument.CreatePosition method to obtain the document position at the given index and inserts a text in it:
Document document = richEditControl.Document;
DocumentPosition pos1 = document.CreatePosition(2);
document.InsertText(pos1,"The Word Processing Document API is a non-visual .NET library.\r
It allows you to automate frequent word processing tasks.\n");
You can use DocumentPosition objects to insert other elements into a document. The table below lists APIs that use a position as a parameter or returns a DocumentPosition object.
API | Description |
---|---|
SubDocument.InsertText | Inserts a given text string at the specified position. |
SubDocument.InsertDocumentContent | Inserts content from a range, stream or text string at the specified position. |
ParagraphCollection.Insert | Insert a new paragraph at the specified position. |
Document.InsertSection | Inserts a section break at the given position. |
FieldCollection.Create | Creates a new field at the specified position. |
BookmarkCollection.Create | Creates a new bookmark at the given position. |
FormFieldCollection.InsertCheckBox | Creates a new checkbox at the given position. |
ShapeCollection.InsertPicture | Inserts a new image at the given position. |
ShapeCollection.InsertTextBox | Inserts a new text box at the given position. |
CommentCollection.Create | Creates a comment anchored to the specified position |
TableCollection.Create | Inserts a new table with the given number of rows and columns in the specified position. |
The code sample below appends an image at the end of the document:
document.Images.Insert(document.Range.End,
DocumentImageSource.FromFile("Documents//DevExpress.png"));
Obtain the Position’s Location
Use the following methods to obtain an approximate location of the required position.
- RichEditControl.GetBoundsFromPosition - obtains coordinates of the rectangle surrounding the specified document position.
- RichEditControl.GetPositionFromPoint - locates the position close to the specified point.
- RichEditView.GetCursorBounds - retrieves coordinates of a rectangle encompassing the cursor.
Note
If you operate with a selection range, any of the above-listed methods should be enclosed within DocumentRange.BeginUpdateDocument - DocumentRange.EndUpdateDocument methods pair. Otherwise, an incorrect document model might be selected, resulting in an exception “Error: specified document position or range belongs to other document or subdocument” being thrown.
Range
The range (the DocumentRange object) is an interval between two positions (DocumentRange.Start and DocumentRange.End). The difference between them is equal to DocumentRange.Length.
Obtain a Range
Use the SubDocument.CreateRange method to create a new DocumentRange object with the specified start and end positions.
The following API allows you to obtain a range associated with document elements or obtain elements from a specified range:
Object | Obtain a Range Related to an Element | Retrieve an Element from a Range |
---|---|---|
Text | ||
Paragraph | ||
Section | ||
Image | ||
Shape | ||
Table | ||
Hyperlink | ||
Bookmark | ||
Comment | ||
Field |
The code sample below retrieves all images from the document and moves the first image to the header:
Document document = richEditControl.Document;
if (document.Images.Count != 0)
{
//Obtain all images
ReadOnlyDocumentImageCollection images = document.Images.Get(document.Range);
//Start the header update
SubDocument header = document.Sections[0].BeginUpdateHeader();
//Insert the retrieved image in the header
header.Images.Insert(header.Range.Start, images[0].Image.NativeImage);
header.EndUpdate();
//Remove the image from its initial place
document.Delete(images[0].Range);
}
How Content Modifications Affect Ranges
When you modify content within a range, the range can expand or shrink automatically.
If you append a single line to a document and change its format options, the format is applied to the new content only.
Tip
Refer to the Text Formatting article for more information on how to format text.
Document document = richEditControl.Document;
//Append the line
DocumentRange newRange = document.AppendText("Word Processing Document API\r\n");
//Change the range's format options
CharacterProperties characterProperties = document.BeginUpdateCharacters(newRange);
characterProperties.ForeColor = Color.DarkGray;
characterProperties.FontSize = 16;
characterProperties.FontName = "Georgia";
characterProperties.Italic = true;
document.EndUpdateCharacters(characterProperties);
richEditControl.SaveDocument("result.docx", DocumentFormat.OpenXml);
If you sequentially append multiple fragments to a document, the DocumentRange object may expand with each new added fragment. The examples below demonstrate the possible results and two ways to resolve these issues.
Append two lines of text and then change the range’s formatting, as shown below:
Document document = richEditControl.Document;
//Append the first line
DocumentRange newRange = document.AppendText("Word Processing Document API\r\n");
//Append the second line
document.AppendText("The Word Processing Document API is a non-visual .NET library.\r " +
"It allows you to automate frequent word processing tasks.\n");
//Change the range's format options
CharacterProperties characterProperties = document.BeginUpdateCharacters(newRange);
characterProperties.ForeColor = Color.DarkGray;
characterProperties.FontSize = 16;
characterProperties.FontName = "Georgia";
characterProperties.Italic = true;
document.EndUpdateCharacters(characterProperties);
richEditControl.SaveDocument("result.docx", DocumentFormat.OpenXml);
When you execute this code, it changes the format of all the text.
Solution #1
Change the format options before inserting new content to avoid this behavior. In this case, the new content remains unformatted.
Document document = richEditControl.Document;
//Append the first line
DocumentRange newRange = document.AppendText("Word Processing Document API\r\n");
//Apply formatting for the first line
CharacterProperties characterProperties = document.BeginUpdateCharacters(newRange);
characterProperties.ForeColor = Color.DarkGray;
characterProperties.FontSize = 16;
characterProperties.FontName = "Georgia";
characterProperties.Italic = true;
document.EndUpdateCharacters(characterProperties);
//Append the second line
document.AppendText("The Word Processing Document API is a non-visual .NET library.\r " +
"It allows you to automate frequent word processing tasks.\n");
richEditControl.SaveDocument("result.docx", DocumentFormat.OpenXml);
Solution #2
Another way to format the initial content is to store the target range’s position and length and create a new DocumentRange object.
The code sample below appends two lines to the document, but changes the format options only for the first line.
Document document = server.Document;
//Append the first line
DocumentRange newRange = document.AppendText("Word Processing Document API.\r\n");
//Preserve the range's start position and length
int rangeStart = newRange.Start.ToInt();
int rangeLength = newRange.Length;
//Append the second line
document.AppendText("The Word Processing Document API is a non-visual .NET library.\r " +
"It allows you to automate frequent word processing tasks.\n");
//Recreate the initial range
DocumentRange formattedRange = document.CreateRange(rangeStart, rangeLength);
//Format the target range
CharacterProperties characterProperties = document.BeginUpdateCharacters(formattedRange);
characterProperties.ForeColor = Color.DarkGray;
characterProperties.FontSize = 16;
characterProperties.FontName = "Georgia";
characterProperties.Italic = true;
document.EndUpdateCharacters(characterProperties);
richEditControl.SaveDocument("result.docx", DocumentFormat.OpenXml);