Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Basic HTML Markup in WPF TextBlock

4.73/5 (6 votes)
22 Oct 2012LGPL34 min read 47K   2  
Provides basic HTML markup support for WPF TextBlock areas

Introduction

Well, let's see. I have recently started a huge slew of new languages to see how quickly I can learn them, and given the immense amount of free time I have due to my studies it is going quite well. Anyway, I decided about 2 weeks ago to start learning WPF since Microsoft seems to be moving more and more away from Window Forms, my previous favourite UI design framework.

I was busy working on some code which is supposed to present the status of a plugin to the user in a popup and found that for some obscure reason, WPF's TextBlock control doesn't support inline markup of ANY kind without jumping through a large number of loops. Not willing to make the life of anyone looking to develop a plugin for my application difficult I decided I would write up a quick parser which would convert basic HTML markup into a form WPF could work with. A few minutes later and this is what I have, it works quite well and fulfils all my requirements so I figured it may be of use to someone else down the line.

Background

The general idea behind how WPF formats its documents is based around an object approach. While this may seem a bit strange at first, the reasoning is quite simple, if you design your entire document system around objects it is very, very easy to add inline controls. Something which RichTextBox on Window Forms just couldn't do without many, many hours of painful work.

The obvious downside to this approach is the same as its advantage though. That being that all the text is in the form of objects as well. While the TextBlock control does provide a Text property that can be used to set the text in the control to the contents of a string this doesn't allow you to specify some of the lovely markup that you are capable of specifying through XAML. This proves to be a particular issue when assigning text dynamically.

The solution is to declare objects to present markup and add them to the Inlines collection provided on the TextBlock. This is usually done in the following manner:

textBlock.Inlines.Add(new Bold(new Run("Show me some text!")));

However, should you want to add some bold text using the Text property, like so:

C#
textBlock.Text = "<Bold>Show me some text!</Bold>"; 

You will quickly realise that it doesn't work. And before you look at me and go "But of course not, <Bold> is not the HTML code for the bold style" remember that WPF uses their own parser, and in XAML <Bold> is the correct one to use.

The solution for me was to write up some code which would parse the markup tags and then automatically generate the new Inline object which could be added. Sounds a lot simpler than it is since in order to do so you need to dynamically generate objects with different types. Thankfully, C# has a feature called Reflection which allows you to create objects from assemblies, types and many other sources without having the code for them and without necessarily knowing their type at design time.

Enough with the introduction though, onto a basic overview of the code and how to use it.

Using the code

The code is really easy to use, simply add it to your existing project and do the following:

C#
textBlock.Inlines.AddRange(SierraLib.UI.WPF.Text.MarkupProcessor.HTMLtoWPF("<b><u><i>Show me some text!</i></u></b>"));  

As for how it does what it does, that is a bit more complicated. The source is all very well documented so you can read through that to get a better idea of what is going on behind the scenes but the basic idea is this:

The Regex object is used to find and return a list of matches. These matches can either be markup tags or text. If it is a markup tag and it isn't a closing tag then we add the respective type for that markup element to a stack which is then used to apply the style later on. As soon as the parser finds a text element we go to work applying the styles. This is done by first checking whether or not there are any styles to apply, if there aren't we just add the text, but if there are styles we start creating the item that will be added by creating its deepest child element first and working our way back up, replacing the last child each time with a new element who's child is that last child. This results in us having an equivalent to the standard markup declaration in WPF.

Finally, when all the elements have been created we return a list containing all the markup elements which should be added to create the effect that the user was looking for.

Points of Interest

For anyone not familiar with Regular Expressions or Reflection I would recommend reading up on them. They are extremely useful things to know and you will find yourself using them very often as you start writing more complex programs. Besides, nothing says cool like (?<this>[cC][oO]{2}[lL]!?). Well, except Regular Expressions that is Wink | ;)

Known Problems

  • Markup doesn't extend past the first close tag or line break (<br/>)

History

Version 1.0

Initial Release

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)