Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Custom Text Wrapping in WPF TextBlocks

0.00/5 (No votes)
13 Jul 2012 1  
This tip demonstrates how to wrap text in WPF - similar to using &shy or <wbr. in html

Introduction

I was intrigued by this question on Stack Overflow. The OP wanted to be able to wrap text based on a custom tag just like how it is done in HTML using &shy or <wbr>. While it is possible to imitate a feature close to this by setting TextBlock.IsHyphenated to true, I just decided to write a simple method that could emulate this feature in WPF.

Background

My idea was simply to write a code that would simply strip and store the position of tags in a supplied text and insert newlines by making a choice of where to insert based on the number of characters that can be displayed in a single line of the control. The method also had to be able to make a choice between the break tag and whitespace characters.

Using the Code

The code is quite simple to use. It accepts three parameters, and can be called as follows:

textBlock1.Text = WordWrap("Code<br>project <br>Today", textBlock1, "<br>");  

In the above example, it's assumed that the break tag is <br>, so it's obvious that the method can be made to use a default tag to make using it simpler.

Here's a listing of the full code:

    /// <summary>
    /// Adds break to a TextBlock according to a specified tag
    /// </summary>
    /// <param name="text">The text containing the tags to break up</param>
    /// <param name="tb">The TextBlock we are assigning this text to</param>
    /// <param name="tag">The tag, eg <br> to use in adding breaks</param>
    /// <returns></returns>
    public string WordWrap(string text, TextBlock tb, string tag)
    {
        //get the amount of text that can fit into the textblock
        int len = (int)Math.Round((2 * tb.ActualWidth / tb.FontSize));
        string original = text.Replace(tag, "");
        string ret = "";
        while (original.Length > len)
        {
            //get index where tag occurred
            int i = text.IndexOf(tag);
            //get index where whitespace occurred
            int j = original.IndexOf(" ");
            //does tag occur earlier than whitespace, then let's use that index instead!
            if (j > i && j < len)
                i = j;
            //if we usde index of whitespace, there is no need to hyphenate
            ret += (i == j) ? original.Substring(0, i) + "\n" : original.Substring(0, i) + "-\n";
            //if we used index of whitespace, then let's remove the whitespace
            original = (i == j) ? original.Substring(i + 1) : original.Substring(i);
            text = text.Substring(i + tag.Length);
        }
        return ret + original;
    }   

Points of Interest

The major interesting thing I encountered was calculating the amount of text that could fit into a single line of a WPF TextBlock control. I knew about Graphics.MeasureString method for WinForms and TextFormatter for WPF, but I wanted to avoid the latter. A random guess made me try TextBlock.Width / TextBlock.FontSize, but this of course did not work since the TextBlock width was set to auto. However with little experimentation, I discovered that...

(int)Math.Round((2 * TextBlock.ActualWidth / TextBlock.FontSize));   

...works well.

I also believe this method should be able to work for other text supporting WPF controls.

History

This if the first version of the code. There could be possible improvements in the future based on suggestions, bugs or performance.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here