Working with RichTextBox for WPF and Silverlight > Accessing Layout Information |
When C1RichTextBox creates the C1Document layout, it creates a parallel tree composed of C1TextElementView objects. For each C1TextElement in the C1Document tree, there is at least one C1TextElementView that is tasked with its layout and drawing.
Take this C1Document tree as an example:
Its corresponding view tree will look like the following:
Each C1TextElementView provides some basic layout information for its corresponding C1TextElement:
Multiple C1TextElementViews can be composed to handle layout and drawing for out C1TextElement. When this is done, the C1TextElementView.Content property contains the inner most C1TextElementView in the composition. The content view’s children correspond to the C1TextElementView.Children collection of the associated C1TextElement.
View composition is used in C1BoxView to handle margin, padding and border for its C1TextElementView.Content view. This means that the origin of each C1BoxView is outside the margin, padding and border box, while the origin of its C1TextElementView.Content is inside.
C1FlowView takes care of flowing boxes and text into lines. Each line is represented by a C1Line object. Note that C1Lines not only contains single lines of text, but may also contain an entire paragraph. Each C1FlowView contains a list of C1Line, which are always vertically stacked. In turn, each C1Line is composed of C1LineFragments, which are horizontally stacked. C1LineFragments have a reference to the child element whose origin matches the position of the fragment.
For example, the following code counts the lines in a C1RichTextBox:
Visual Basic |
Copy Code
|
---|---|
Private Function CountLines(rtb As C1RichTextBox) As Integer Dim root = rtb.ViewManager.GetView(rtb.Document) Return CountLines(root) End Function Private Function CountLines(view As C1TextElementView) As Integer Dim count As Integer = 0 Dim flow = TryCast(view, C1FlowView) If flow IsNot Nothing Then For Each line As var In flow.Lines If TypeOf line.Fragments.First().Element Is C1Inline Then count += 1 End If Next End If For Each child As var In view.Children count += CountLines(child) Next Return count End Function |
C# |
Copy Code
|
---|---|
int CountLines(C1RichTextBox rtb) { var root = rtb.ViewManager.GetView(rtb.Document); return CountLines(root); } int CountLines(C1TextElementView view) { int count = 0; var flow = view as C1FlowView; if (flow != null) { foreach (var line in flow.Lines) { if (line.Fragments.First().Element is C1Inline) { ++count; } } } foreach (var child in view.Children) { count += CountLines(child); } return count; } |
At first, the root view is obtained. That's the same as the view associated to root element, so C1RichTextViewManager.GetView is used to get the view of rtb.Document. After that, the view tree is traversed counting the lines in each C1FlowView found. Note that you only count the lines with C1Inline elements; otherwise you would also count paragraphs and other container blocks.