views:

81

answers:

2
+1  Q: 

WPF Text overflow

I'm currently trying to make it so that when I take a string, it fills up the first textblock until it overflows and then it should start in textblock 2. Currently, I have it to where the string is cut into two pieces at the last end of the last word before it hits what I guess to be the max characters that can fit into textblock one, and the second half is in 2, but the problem I'm encountering is that it's never really possible to figure out where to cut off text, since when it wraps, the spaces left over take up different sizes. So I'm left with textblock 1 having some cut off text at the end, making it look like some words are missing between the two. Is there any way to programmatically find the overflow on a textblock?

ps- the Textblocks are created at runtime in the C# instead of the wpf markup.

This is what I do. I take myDescription and try to fit it into myDesc[0] and then [2] based on the sizes I approximate. The problem is that if I guess the size threshold to be too big, it leaves myDesc[0] with a ... or cut off word, and if I approximate it to be too little, it has huge awkward gaps. There's no number that I cut off that doesn't have either.

TextBlock[] myDesc = new TextBlock[2];
string myDescription = infoLoader.games[gameID].description[currentLanguage];
        string[] myWords = myDescription.Split(' ');

        string firstPart = "";
        string secondPart = "";


        int currentWord = 0;


        // New and improved way
        int currentLine = 0;
        int charsInLine = 0;
        while (currentWord < myWords.Length)
        {
            // Determine the size of the word based on the number of characters and size of certain characters in it.
            int myWLength = myWords[currentWord].Length;
            int iCount = 0;
            for (int i = 0; i < myWords[currentWord].Length; i++)
            {
                if (myWords[currentWord][i] == 'm' || myWords[currentWord][i] == 'M')
                {
                    Console.Write("M or m. ");
                    myWLength++;
                }
                else if (myWords[currentWord][i] == 'i' || myWords[currentWord][i] == 'l' || myWords[currentWord][i] == 'I' || myWords[currentWord][i] == 'j' || myWords[currentWord][i] == 'í' || myWords[currentWord][i] == 't')
                {
                    iCount++;
                }
            }
            iCount = (iCount / 2);
            myWLength -= iCount;
            if (myWords[currentWord] == "SKIP")
            {
                firstPart += "\n";
                currentLine++;
                currentWord++;
            }
            else if (currentLine < 4)
            {
                // firstPart.
                if (charsInLine + myWLength < 20)
                {
                    // Add It.
                    firstPart += myWords[currentWord];
                    firstPart += " ";
                    charsInLine += myWLength;
                    charsInLine += 1;
                    currentWord++;

                }
                else
                {
                    // New Line.
                    //firstPart += " " + currentLine + " ";
                    firstPart += "\n";
                    charsInLine = 0;
                    currentLine++;
                }
            } else if (currentLine < 6) 
            {
                if (charsInLine + myWLength < 21)
                {
                    // Add It.
                    firstPart += myWords[currentWord];
                    firstPart += " ";
                    charsInLine += myWLength;
                    charsInLine += 1;
                    currentWord++;

                }
                else
                {
                    // New Line.
                    //firstPart += "\n";
                    charsInLine = 0;
                    currentLine++;
                }
            }
            else
            {
                // secondPart.
                secondPart += myWords[currentWord];
                secondPart += " ";
                currentWord++;
            }
        }

myDesc[0] = new TextBlock();
        myDesc[0].Text = firstPart;
        myDesc[0].TextWrapping = TextWrapping.Wrap;
        myDesc[0].TextTrimming = TextTrimming.CharacterEllipsis;
        myDesc[0].Background = descBGBrush;
        myDesc[0].FontFamily = new FontFamily("Arial");
        myDesc[0].FontSize = 12.0;
        myDesc[0].Width = 118;
        myDesc[0].Height = 83;
        Canvas.SetLeft(myDesc[0], 132);
        Canvas.SetTop(myDesc[0], 31);

        myDesc[1] = new TextBlock();
        myDesc[1].Text = secondPart;
        myDesc[1].TextWrapping = TextWrapping.Wrap;
        myDesc[1].Background = descBGBrush;
        myDesc[1].FontSize = 12.0;
        myDesc[1].FontFamily = new FontFamily("Arial");
        myDesc[1].Width = 236;
        myDesc[1].Height = 43;
        Canvas.SetLeft(myDesc[1], 16);
        Canvas.SetTop(myDesc[1], 115);
A: 

A way is to create create a custom-control where you do the rendering over DrawingContext. With this, you can exactly calculate the size that the text will use and therefore calculate the cut-position.

With such a control, you can define an overflow-property that returns for each control the text that is not shown and set it as source of a sibling-control.

Sure, this is not a simple job, but it's a possible way. You can also derive from TextBlock and then calculate the text in the default-processing logic and add a DP to provide the overflow text.

The following links may be usefull to do the above solution:

FormattedText

FormattedText.Height

HCL
"With such a control, you can define an overflow-property that returns for each control the text that is not shown and set it as source of a sibling-control."
Andrew
Sorry, meant to be one comment, but I'm not sure exactly how to go about doing that. I'll explain what I'm doing better above
Andrew
A: 

Take a look at the TextWrapping property associated with the TextBlock to perhaps make your code simplier.

<StackPanel>
  <TextBlock Text="One line of text"/>
  <TextBlock Width="50" TextWrapping="WrapWithOverflow" Text="One line of text"/>
  <TextBlock Width="50" TextWrapping="Wrap" Text="One line of text"/>
</StackPanel>
Zamboni