Example T266080
Visible to All Users

Rich Text Editor for WinForms: Document Layout API - Practical Usage

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:

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

C# Visual Basic
CustomDocumentLayoutVisitor.cs CustomDocumentLayoutVisitor.vb
DocumentElementLayoutHelper.cs DocumentElementLayoutHelper.vb
PageLayoutHelper.cs PageLayoutHelper.vb
RichEditDocumentLayoutAnalyzer.cs RichEditDocumentLayoutAnalyzer.vb
TextBoxLayoutHelper.cs TextBoxLayoutHelper.vb
Form1.cs Form1.vb

Documentation

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

WindowsFormsApplication1/DocumentLayoutHelper/CustomDocumentLayoutVisitor.cs(vb)
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); } } }
WindowsFormsApplication1/DocumentLayoutHelper/DocumentElementLayoutHelper.cs(vb)
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; } } }
WindowsFormsApplication1/DocumentLayoutHelper/PageLayoutHelper.cs(vb)
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; } }
WindowsFormsApplication1/DocumentLayoutHelper/RichEditDocumentLayoutAnalyzer.cs(vb)
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 ""; } } }
WindowsFormsApplication1/DocumentLayoutHelper/TextBoxLayoutHelper.cs(vb)
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; } } }
WindowsFormsApplication1/Form1.cs(vb)
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); } } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.