This example demonstrates how to use RichEditControl's layout API to collect information about a currently clicked document element (and its parent elements).
Implementation Details
This example shows the following approaches to get layout information about a current element:
- Use the DocumentLayout.GetElement method overloads;
- Use the
LayoutIterator
class; - Use a custom LayoutVisitor descendant.
To get layout information about the current element, set the caret inside a text block or table cell (or select an image) and click the Analyze current document layout button.
Depending on the type (text block, image, table cell, textbox, etc.) of a clicked element, you can retrieve the following information:
- Content
- Content bounds
- Position on a page
- Page bounds
- Current page index
- Number of images/text boxes on a page
- Common text blocks count, etc.
Files to Review
Documentation
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraRichEdit.API.Layout;
namespace WindowsFormsApplication1.DocumentLayoutHelper {
public class CustomDocumentLayoutVisitor : DevExpress.XtraRichEdit.API.Layout.LayoutVisitor {
public int ParagraphsCount = 0;
public int TextLinesCount = 0;
public int WordsCount = 0;
public int TablesCount = 0;
public int TextBoxesCount = 0;
public int ImagesCount = 0;
protected override void VisitTable(LayoutTable table) {
TablesCount++;
base.VisitTable(table);
}
protected override void VisitTextBox(LayoutTextBox textBox) {
TextBoxesCount++;
base.VisitTextBox(textBox);
}
protected override void VisitFloatingObjectAnchorBox(FloatingObjectAnchorBox floatingObjectAnchorBox) {
LayoutType objectType = floatingObjectAnchorBox.FloatingObjectBox.Type;
if(objectType == LayoutType.FloatingPicture) ImagesCount++;
base.VisitFloatingObjectAnchorBox(floatingObjectAnchorBox);
}
protected override void VisitInlinePictureBox(InlinePictureBox inlinePictureBox) {
ImagesCount++;
base.VisitInlinePictureBox(inlinePictureBox);
}
protected override void VisitPlainTextBox(PlainTextBox plainTextBox) {
WordsCount++;
base.VisitPlainTextBox(plainTextBox);
}
protected override void VisitParagraphMarkBox(PlainTextBox paragraphMarkBox) {
ParagraphsCount++;
base.VisitParagraphMarkBox(paragraphMarkBox);
}
protected override void VisitRow(LayoutRow row) {
TextLinesCount++;
base.VisitRow(row);
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.Office.Utils;
using DevExpress.XtraRichEdit.API.Layout;
using DevExpress.XtraRichEdit.API.Native;
namespace WindowsFormsApplication1.DocumentLayoutHelper {
public static class DocumentElementLayoutHelper {
// get information about a current regular text block
public static string GetInformationAboutRegularTextBlock(PlainTextBox currentTextBlock, Document currentDocument) {
string returnedInformation = "!A REGULAR TEXT BLOCK IS SELECTED!\r\n";
returnedInformation += String.Format("Content: {0}\r\n", currentTextBlock.Text);
LayoutRow currentRow = currentTextBlock.Parent as LayoutRow;
LayoutColumn currentColumn = currentRow.Parent as LayoutColumn;
int currentLineIndex = currentColumn.Rows.ToList().IndexOf(currentRow);
returnedInformation += String.Format("Line index: {0}\r\n", currentLineIndex + 1);
returnedInformation += String.Format("Start position: {0}\r\n", currentTextBlock.Range.Start);
returnedInformation += String.Format("End position: {0}\r\n", currentTextBlock.Range.Start + currentTextBlock.Range.Length);
int currentParagraphIndex = currentDocument.Paragraphs.ToList().IndexOf(currentDocument.Paragraphs.Get(currentDocument.CreatePosition(currentTextBlock.Range.Start)));
returnedInformation += String.Format("Paragrpah index: {0}\r\n", currentParagraphIndex + 1);
returnedInformation += String.Format("Text block bounds: {0}\r\n", currentTextBlock.Bounds);
return returnedInformation;
}
// get information about a current floating object
public static string GetInformationAboutCurrentFloatingObject(FloatingObjectAnchorBox currentObjectAnchor, DocumentLayout currentLayout) {
LayoutFloatingObject currentFloatingObject = currentObjectAnchor.FloatingObjectBox;
string returnedInformation = "";
if(currentFloatingObject.Type == LayoutType.FloatingPicture)
returnedInformation = "!A FLOATING PICTURE IS SELECTED!\r\n";
else if(currentFloatingObject.Type == LayoutType.TextBox)
returnedInformation = "!A TEXT BOX IS SELECTED!\r\n";
returnedInformation += String.Format("Anchor location: {0}\r\n", currentObjectAnchor.Bounds.Location);
returnedInformation += String.Format("Object bounds: {0}\r\n", currentFloatingObject.Bounds);
returnedInformation += String.Format("Rotation: {0}\r\n", currentFloatingObject.RotationAngle);
if(currentFloatingObject.Type == LayoutType.TextBox) {
LayoutTextBox currentTextBox = currentFloatingObject as LayoutTextBox;
returnedInformation += String.Format("\r\n!!Content information:\r\n");
returnedInformation += TextBoxLayoutHelper.GetInformationAboutCurrentTextBoxContent(currentTextBox, currentLayout);
}
else if(currentFloatingObject.Type == LayoutType.FloatingPicture) {
LayoutFloatingPicture currentFloatingPicture = currentFloatingObject as LayoutFloatingPicture;
returnedInformation += String.Format("\r\n!!Image properties:\r\n");
returnedInformation += GetInformationAboutOfficeImage(currentFloatingPicture.Image);
}
return returnedInformation;
}
// get information about a current inline picture
public static string GetInformationAboutCurrentInlinePicture(InlinePictureBox inlinePicture) {
string returnedInformation = "!AN INLINE IMAGE IS SELECTED!\r\n";
returnedInformation += String.Format("Start position: {0}\r\n", inlinePicture.Range.Start);
returnedInformation += GetInformationAboutOfficeImage(inlinePicture.Image);
return returnedInformation;
}
// get information about a current table cell
public static string GetInformationAboutCurrentTableCell(Document currentDocument, LayoutTableCell tableCell) {
string returnedInformation = "!A TABLE CELL IS SELECTED!\r\n";
string cellText = currentDocument.GetText(currentDocument.CreateRange(tableCell.Range.Start, tableCell.Range.Length - 1));
returnedInformation += String.Format("Cell's content: {0}\r\n", cellText);
LayoutTableRow currentRow = tableCell.Parent as LayoutTableRow;
if(currentRow == null) return returnedInformation;
LayoutTable currentTable = currentRow.Parent as LayoutTable;
if(currentTable == null) return returnedInformation;
returnedInformation += String.Format("Row index: {0}\r\n", currentTable.TableRows.ToList().IndexOf(currentRow) + 1);
for(int i = 0; i < currentRow.TableCells.Count; i++) {
if(currentRow.TableCells[i] == tableCell) {
returnedInformation += String.Format("Column index: {0}\r\n", i + 1);
break;
}
}
returnedInformation += String.Format("\r\n!Table information:\r\n");
returnedInformation += String.Format("Row count: {0}\r\n", currentTable.TableRows.Count);
int maxCellsCount = 0;
for(int i = 0; i < currentTable.TableRows.Count; i++) {
if(currentTable.TableRows[i].TableCells.Count > maxCellsCount) maxCellsCount = currentTable.TableRows[i].TableCells.Count;
}
returnedInformation += String.Format("Column count: {0}\r\n", maxCellsCount);
return returnedInformation;
}
// get information about a current inline picture
public static string GetInformationAboutOfficeImage(OfficeImage officeImage) {
string returnedInformation = "";
returnedInformation += String.Format("Format: {0}\r\n", officeImage.RawFormat);
returnedInformation += String.Format("Original size: {0}\r\n", officeImage.SizeInPixels);
return returnedInformation;
}
}
}
C#using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using DevExpress.XtraRichEdit.API.Layout;
using DevExpress.XtraRichEdit.API.Native;
namespace WindowsFormsApplication1.DocumentLayoutHelper {
public static class PageLayoutHelper {
public static string GetInformationAboutCurrentPage(DocumentLayout currentDocumentLayout, LayoutPage currentPage, DocumentPosition currentPosition) {
string returnedInformation = "";
int currentPageIndex = currentDocumentLayout.GetPageIndex(currentPage);
int totalPageCount = currentDocumentLayout.GetFormattedPageCount();
// get information about page content using a LayoutVisitor descendant
CustomDocumentLayoutVisitor visitor = new CustomDocumentLayoutVisitor();
visitor.Visit(currentPage);
// get information about page bounds using PageArea properties
PageAreaProperties pageAreaProperties = CaculatePageAreaProperties(currentPage.PageAreas[0], currentPosition);
returnedInformation += String.Format("\r\nPage: {0} of {1}\r\n", currentPageIndex + 1, totalPageCount);
returnedInformation += String.Format("Current page range: {0} - {1}\r\n", currentPage.MainContentRange.Start, currentPage.MainContentRange.Start + currentPage.MainContentRange.Length - 1);
returnedInformation += String.Format("Images count: {0}\r\n", visitor.ImagesCount);
returnedInformation += String.Format("Tables count: {0}\r\n", visitor.TablesCount);
returnedInformation += String.Format("Text Boxes count: {0}\r\n", visitor.TextBoxesCount);
returnedInformation += String.Format("Paragraphs count: {0}\r\n", visitor.ParagraphsCount);
returnedInformation += String.Format("Text lines count: {0}\r\n", visitor.TextLinesCount);
returnedInformation += String.Format("Words (text blocks) count: {0}\r\n", visitor.WordsCount);
returnedInformation += String.Format("\r\nColumn: {0} of {1}\r\n", pageAreaProperties.currentColumnIndex, pageAreaProperties.columnCount);
returnedInformation += String.Format("Current COLUMN content bounds: {0}\r\n", pageAreaProperties.currentColumnBounds);
returnedInformation += String.Format("Current PAGE content bounds: {0}\r\n", pageAreaProperties.currentPageBounds);
return returnedInformation;
}
public static PageAreaProperties CaculatePageAreaProperties(LayoutPageArea pageArea, DocumentPosition pos) {
PageAreaProperties pageAreaProperties = new PageAreaProperties();
pageAreaProperties.columnCount = pageArea.Columns.Count;
pageAreaProperties.currentPageBounds.Location = pageArea.Columns[0].Bounds.Location;
for(int i = 0; i < pageArea.Columns.Count; i++) {
int currentColumnContentHeight = pageArea.Columns[i].Rows.Last.Bounds.Bottom - pageArea.Columns[i].Rows.First.Bounds.Top;
if(pageArea.Columns[i].Range.Contains(pos.ToInt())) {
pageAreaProperties.currentColumnIndex = i;
pageAreaProperties.currentColumnBounds.Location = pageArea.Columns[i].Bounds.Location;
pageAreaProperties.currentColumnBounds.Width = pageArea.Columns[i].Bounds.Width;
pageAreaProperties.currentColumnBounds.Height = currentColumnContentHeight;
}
pageAreaProperties.currentPageBounds.Width += pageArea.Columns[i].Bounds.Width;
pageAreaProperties.currentPageBounds.Height = Math.Max(pageAreaProperties.currentPageBounds.Height, currentColumnContentHeight);
}
return pageAreaProperties;
}
}
public class PageAreaProperties {
public int currentColumnIndex = 0;
public int columnCount = 0;
public Rectangle currentColumnBounds = Rectangle.Empty;
public Rectangle currentPageBounds = Rectangle.Empty;
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraRichEdit.API.Layout;
using DevExpress.XtraRichEdit.API.Native;
namespace WindowsFormsApplication1.DocumentLayoutHelper {
public static class RichEditDocumentLayoutAnalyzer {
public static string GetInformationAboutRichEditDocumentLayout(Document currentDocument, DocumentLayout currentDocumentLayout) {
SubDocument subDocument = currentDocument.CaretPosition.BeginUpdateDocument();
DocumentPosition docPosition = subDocument.CreatePosition(currentDocument.CaretPosition.ToInt() == 0 ? 0 : currentDocument.CaretPosition.ToInt() - 1);
ReadOnlyShapeCollection shapes = subDocument.Shapes.Get(subDocument.CreateRange(docPosition, 1));
ReadOnlyDocumentImageCollection images = subDocument.Images.Get(subDocument.CreateRange(docPosition, 1));
if(shapes.Count == 0 && images.Count == 0) docPosition = subDocument.CreatePosition(currentDocument.CaretPosition.ToInt());
string returnedInformation = "";
// get infromation about a current document element
returnedInformation += GetInformationAboutCurrentDocumentElement(currentDocument, currentDocumentLayout, subDocument, docPosition);
// collect information about CURRENT PAGE
RangedLayoutElement layoutPosition = currentDocumentLayout.GetElement<RangedLayoutElement>(docPosition);
if(layoutPosition != null) {
int currentPageIndex = currentDocumentLayout.GetPageIndex(layoutPosition);
returnedInformation += PageLayoutHelper.GetInformationAboutCurrentPage(currentDocumentLayout, currentDocumentLayout.GetPage(currentPageIndex), docPosition);
}
currentDocument.CaretPosition.EndUpdateDocument(subDocument);
return returnedInformation;
}
public static string GetInformationAboutCurrentDocumentElement(Document currentDocument, DocumentLayout currentDocumentLayout, SubDocument currentSubDocument, DocumentPosition docPosition) {
if(currentSubDocument.GetSubDocumentType() == SubDocumentType.TextBox) {
return TextBoxLayoutHelper.GetInformationAboutCurrentTextBox(currentSubDocument, currentDocumentLayout, docPosition);
}
if(currentSubDocument.GetSubDocumentType() == SubDocumentType.Main) {
RangedLayoutElement tableCell = currentDocumentLayout.GetElement(docPosition, LayoutType.TableCell);
if(tableCell != null)
// collect information about TABLE CELL
return DocumentElementLayoutHelper.GetInformationAboutCurrentTableCell(currentDocument, tableCell as LayoutTableCell);
RangedLayoutElement imageinline = currentDocumentLayout.GetElement(docPosition, LayoutType.InlinePictureBox);
if(imageinline != null)
// collect information about INLINE PICTURE
return DocumentElementLayoutHelper.GetInformationAboutCurrentInlinePicture(imageinline as InlinePictureBox);
RangedLayoutElement floatingObjectAnchor = currentDocumentLayout.GetElement(docPosition, LayoutType.FloatingObjectAnchorBox);
if(floatingObjectAnchor != null)
// collect information about FLOATING OBJECT
return DocumentElementLayoutHelper.GetInformationAboutCurrentFloatingObject(floatingObjectAnchor as FloatingObjectAnchorBox, currentDocumentLayout);
RangedLayoutElement regularTextBlock = currentDocumentLayout.GetElement(docPosition, LayoutType.PlainTextBox);
if(regularTextBlock != null)
// collect information about REGULAR TEXT BLOCK
return DocumentElementLayoutHelper.GetInformationAboutRegularTextBlock(regularTextBlock as PlainTextBox, currentDocument);
}
return "";
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraRichEdit.API.Layout;
using DevExpress.XtraRichEdit.API.Native;
namespace WindowsFormsApplication1.DocumentLayoutHelper {
public static class TextBoxLayoutHelper {
// get information about a current text box layout
public static string GetInformationAboutCurrentTextBox(SubDocument subDocument, DocumentLayout currentLayout, DocumentPosition docPosition) {
string returnedInformation = "!A TEXTBOX CONTENT IS SELECTED!\r\n";
LayoutIterator layoutIterator = new LayoutIterator(currentLayout, subDocument.Range);
LayoutPage currentTextBoxPage = null;
LayoutTextBox currentTextBox = null;
while(layoutIterator.MoveNext()) {
LayoutElement element = layoutIterator.Current;
if(element is LayoutTextBox) {
currentTextBox = (element as LayoutTextBox);
if (currentTextBox.Parent is LayoutPage) currentTextBoxPage = currentTextBox.Parent as LayoutPage;
}
if(element is PlainTextBox) {
PlainTextBox currentPlaintTextBox = element as PlainTextBox;
if(currentPlaintTextBox.Range.Contains(docPosition.ToInt())) {
returnedInformation += String.Format("Selected content: {0}\r\n", currentPlaintTextBox.Text);
LayoutRow currentRow = currentPlaintTextBox.Parent as LayoutRow;
int currentLineIndex = currentTextBox.Rows.ToList().IndexOf(currentRow);
returnedInformation += String.Format("Line index: {0}\r\n", currentLineIndex + 1);
returnedInformation += String.Format("Selected block bounds: {0}\r\n", currentPlaintTextBox.Bounds);
break;
}
}
}
returnedInformation += String.Format("TEXTBOX bounds: {0}\r\n", currentTextBox.Bounds);
returnedInformation += String.Format("\r\n!!Content information:\r\n");
returnedInformation += GetInformationAboutCurrentTextBoxContent(currentTextBox, currentLayout);
if(currentTextBoxPage != null) {
returnedInformation += PageLayoutHelper.GetInformationAboutCurrentPage(currentLayout, currentTextBoxPage, docPosition);
}
return returnedInformation;
}
public static string GetInformationAboutCurrentTextBoxContent(LayoutTextBox currentTextBox, DocumentLayout currentLayout) {
string returnedInformation = "";
CustomDocumentLayoutVisitor visitor = new CustomDocumentLayoutVisitor();
visitor.Visit(currentTextBox);
SubDocument doc = currentLayout.BeginUpdateDocument(currentTextBox);
string plainTextContent = doc.GetText(doc.Range);
currentLayout.EndUpdateDocument(doc);
returnedInformation += String.Format("Lines count: {0}\r\n", visitor.TextLinesCount);
returnedInformation += String.Format("Words count: {0}\r\n", visitor.WordsCount);
returnedInformation += String.Format("Plain text: {0}\r\n", plainTextContent);
return returnedInformation;
}
}
}
C#using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraBars.Ribbon;
using DevExpress.XtraRichEdit.API.Layout;
using DevExpress.XtraRichEdit.API.Native;
using WindowsFormsApplication1.DocumentLayoutHelper;
namespace WindowsFormsApplication1 {
public partial class Form1 : RibbonForm {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
richEditControl1.LoadDocument("testDocument.docx");
}
private void barButtonItem1_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) {
memoEdit1.Text = RichEditDocumentLayoutAnalyzer.GetInformationAboutRichEditDocumentLayout(richEditControl1.Document, richEditControl1.DocumentLayout);
}
}
}