In this section we will look WPF text formatting in layout services. We will have a look at text rendering feature, text layout services, text object model and text editing controls.
WPF uses ContentModel to present the text so WPF is does not just present the text as a plain string but allows you to take control and present whatever you want, so all the controls that use text are free to use WPF text formatting. As we can see in the image below we have used multiple fonts and color in the TextBlock inside a button. I know it looks ugly but the point is that this is the kind of capability WPF provides us with.
As we can see in the image above we have placed a textblock inside the button. TextBlock is your control if you want to a few letters or a few paragraphs. It supports Font Styles like FontSize, FontFamily, etc. It also offers block level formatting options. But default a TextBlock only runs a single line display but if you want to display paragraphs you need to turn on text wrapping. We can specify the TextAlignment. Till now you have seen TextBlock accepting the strings as the Text to display. That is done for the convenience for DataBinding, etc. We can provide content model to the text to provide formatting to the other part of the texts. We have individual properties which will be used to provide formatting to text sections. There is also Span which can be used to apply a format to the span of a text. We also nest these formatting like a span inside a span. As use can see that we have painted the text with LinearGradientBrush. It is evidently similar to html. Though it might look like HTML these are objects and blend well with .NET.
Class Hierarchy for WPF Text Model
Inline Text Elements
In the image below we can see the class hierarchy of the WPF Text Object Model. These are the Inline elements of the text like the short runs of text that are within the paragraph like a bold or underline. As we saw in the Core Elements section that the most of the WPF Elements derive from the FramworkUIELements but Text derive from the FrameworkContentElement. As we can see TextElement derives from FrameworkContentElement and provides properties like FontSize, FontFamily,etc. The properties in other WPF Controls provides aliases to these properties. If you go to the Control.FontSize property of a control and retrieve its DependencyObject then you will see that it derives from TextElement. Controls just provide an easy way to use these properties rather than using the cumbersome attached properties syntax. Controls do this by using the static Add Owner method of the dependency property which allows an element to declare the use of attached properties as a local property.
Inline class is the base the class for elements which are designed to use within a paragraph. As we can see that these elements which are designed to use in a paragraph and the most of them then further derive from Span. Span defines a children property and Span can acts a container and that is why we are able nest these elements in XAML. LineBreak lets you add line breaks between paragraphs. WPF does not consider these as paragraphs from Content Model point of view. And since Paragraph is not an inline element and so we cannot use it as the inline element. So LineBreak comes in handy and it helps to design stuff inline that looks like a paragraph. Run is an inline element which we always use but never write it. Confused? Actually Run element is the only one capable of holding a string The Span is a content model that support only inlines. Run is automatically generated when we add text strings. Let see this in action. You will see that the run elements are automatically generated by the xaml compiler when the types request it.
Block Text Elements
Blocks are paragraph level constructs like List, Tables, etc. Since these elements do not derive from inline we cannot put them into textblock so we need to place them into a FlowDocument that supports Blocks.
Document Viewer Controls
To display a flow document we need to use one of the DocumentViewerControls.
- FLowDocumentScrollViewer – This displays content as continuous vertical scrolling. This one looks similar to a web browser page where we can place unlimited content and it will scroll vertically.
- FlowDocumentPageViewer – This provides a paginating view. You can see it in lot of online reader like msdn reader. This will size the content to page according to the reading area available and font size so that no scrolling is required and it uses pagination for the documents that not fit one page.
- FlowDocumentReader – This lets the user decide as to which FlowDocument style to use. This is similar to what we will get wahen we display a flow document inside a content control.
Paragraph is the simplest block type. It is just a collection of inlines and so we can fill it up with text or marked up formatted text. Since paragraph support inline contents it will wrap its content into run elements impliclitly.
Section is another block type. As the block has no intrinsic appearance of its own. The purpose of a block is to let us group several other blocks together and then we can set the text formatting properties on the entire block any text formatting applied to a section will imply on all the blocks of the entire section.
List block type makes it easier to display bulleted and numbered list. WPF provides just one list that does it all. The MarkerStyle property of the list will specify whether we want bullets or numbers. You can specify the numbers, letters or bullets. We can use only inbuilt bullets as there is no way to define the custom bullet types.
The table block element lets us build the table of texts. This may seem similar to Grid but the Grid derives form FramworkElemet and Table derives from FramworkContentElement as it is a text element. The table understands the text layout roots and this enables the table for doing what the grid cannot. Like a table can span multiple pages if it cannot fit one page. Also unlike the grid we do not need to tell the table upfront as to how many columns are needed. It generates them as per the content. The advantage of grid over table is that we can put multiple elements in one cell which is not possible in a table. We still can have nested elements inside a table cell though.
Figures and Floaters
Other inline types are Figures and Floaters. They cannot be used inside a TextBlock though. These can be use only in a FlowDocument. These let us place the content that is out of the main flow of the document like images, tables, etc. They support nested items of content and the main text will flow around them. These elements provide as an anchor point for content out of the flow of the document.
Floater – It is the simple of the two and we can provide the alignment of the element.
Figure – This is more flexible. It’s designed for paginated views. We can the content to appear at the top of the page, half of the width of the page or span a couple of columns.
Integrating a UIElement in a FlowDocument
We can do that by using the following:
This is like the textbox but uses the FlowDocument as its internal representation. So it uses the TextObjectModel we just explored. It can also import or export the rich text format through the clipboard.
Any questions, comments or feedback are most welcome.
The code for this post can be found here.