Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping text in TextBlock

Tags:

c#

wpf

textblock

Are there any possibilities to provide a wordwrap suggestion to a Textblock as you can do in HTML with <SHY> (soft hyphen) or <WBR> (word break) or the even more complicated and less maintainable zero-width-space &#8203;

At the moment the Textblock breaks words just as it sees necessity, ending up with word wraps like

Stackoverflo
w

what I want is:

Stackover-
flow

or at least:

Stackover
flow

If there are recommend ways to achieve the needed, please let me know.

like image 962
Mare Infinitus Avatar asked Jul 12 '12 11:07

Mare Infinitus


Video Answer


2 Answers

Setting TextBlock.IsHypenationEnabled to true would actually do something similar to that, but if you want to use tags, you can use a method like this:

    /// <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;
    }

This way you can now say:

textBlock1.Text = WordWrap("StackOver<br>Flow For<br>Ever", textBlock1, "<br>");

This will output:

Just tested

However, using only IsHyphenated without tags, it will be:

IsHypehnated Scenario1

While:

textBlock1.Text = WordWrap("StackOver<br>Flow In<br> U", textBlock1, "<br>");

will output:

Doesn't add <brs> here

And IsHyphenated without tags:

IsHyphenated Scenario 2

EDIT: On reducing font size, I discovered that first code I posted does not prefer adding breaks where whitespaces occur to user specified breaks.

like image 181
Chibueze Opata Avatar answered Sep 23 '22 00:09

Chibueze Opata


Use the TextFormatter in conjunction with a custom TextSource to control how the text is broken up and wrapped.

  • http://msdn.microsoft.com/en-us/library/ms754036

You need to derive a class from TextSource and in your implementation analyse your content/string and provide your wrapping rules, e.g. looking for your <wbr> tag...when you see a tag you return a TextEndOfLine else you return a TextCharacters.

An example which could help in implementing a TextSource is here:

  • http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=wpfsamples&DownloadId=10113

For a very advanced example look at "AvalonEdit" which also uses it:

  • http://community.sharpdevelop.net/forums/p/10187/28231.aspx

You could also investigate GlyphRun if you don't need rich formatting.

  • http://msdn.microsoft.com/en-us/library/bb613560.aspx
like image 26
CSmith Avatar answered Sep 21 '22 00:09

CSmith