Click here to Skip to main content
15,795,402 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
See more:
I have a drawingcontrol based on a canvas.
The user is able to draw a rectangle by pressing the mouse button on the topleft position and dragging the mouse to the bottom right position. If the user lets go of the mouse button, the rectangle is drawn on the exact position that the user performed that action.
Now I need to draw text on this drawing control too, and it is the same procedure, the idea is that when the user lets go of the mouse the rectangle is filled in with the tekst "label", and that it exactly fills the surrounding rectangle. If I change the tekst to say "Lgl" the formatting should be reapplied because most likely the 'g' has a negative bottom bearing. How can I make this happen ? (Not the reformatting event, that is happening ok, but the fitting in the surrounding rectangle itself)
If I say the fontsize is 50, the resulting size is most likely bigger.
I used following code to do some investigation already based on what I found on the net :
public class HeightFontSizeConverter : IMultiValueConverter
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            string text = (string)values[0];
            double desiredHeight = (double)values[1];
            FontFamily family = (FontFamily)values[2];
            FontStyle style = (FontStyle)values[3];
            FontWeight weight = (FontWeight)values[4];
            FontStretch stretch = FontStretches.Normal;
            if (desiredHeight == 0) return (double)0;
            Typeface face = new Typeface(family,style,weight,stretch);
            GlyphTypeface gtf;
            if (face.TryGetGlyphTypeface(out gtf))
                for (int i = 0; i < text.Length; ++i)
                    ushort index = gtf.CharacterToGlyphMap[text[i]];
                    double h = gtf.AdvanceHeights[index];
                    double b = gtf.BottomSideBearings[index];
                    double t = gtf.TopSideBearings[index];
                    double baseline = gtf.Baseline;
                    double height = gtf.Height;
                    Debug.WriteLine("in HeightFontSizeConverter {0} baseline={1} height={2} advh={3} bsb={4} tsb={5}",text[i], baseline, height, h, b,t);
                return desiredHeight;
            else return (double)0;

The problem basically is that I don't seem to find the meaning of the parameters in GlyphTypeface. I am not interested in left side bearing and right side bearing, I have the feeling it has to do with top side bearing and bottom side bearing but where do they start exactly.
I don't want any space above the tekst and I do not want any space below the tekst, it should fit the rectangle exactly.
Updated 15-Sep-12 2:04am

Just a quick off-the-cuff idea, but have you tried just wrapping a TextBlock inside a ViewBox? I don't have access to VS at the moment to try, but I imagine that would scale it automatically for you with essentially no special code.

Apologies if I've missed something.
Share this answer
Philip Stuyck 15-Sep-12 7:55am    
If I try this :
<viewbox height="100">
<textblock padding="0,0,0,0" removed="Green" fontsize="1" text="HhglW"></textblock>
You'll see that with the default font even there is no space at the bottom, that is what I want , but there is space at the top that I don't want.
Nice try though because you are right, I did not think of the viewbox ;-)
If I change the font to Gautami then you have space at the top and at the bottom. This font actually has a lot of unused space.
Adam David Hill 15-Sep-12 8:51am    
Hmmm... have you tried setting Stretch="Fill"? It depends whether you don't mind distorting the aspect ratio of the text, but maybe experiment with that property?
Philip Stuyck 15-Sep-12 10:08am    
The unused space is still there, because it is actually part of the font. The viewbox is doing its thing, it just does not know about the unused space.
Adam David Hill 15-Sep-12 19:41pm    
Ah, I see. You could use a Margin with negative values to counteract the spacing in the font. The trouble/risk would be that the word google (lowercase) vs. GOOGLE (uppercase) would need different values due to differing ascenders / descenders.
Philip Stuyck 16-Sep-12 3:55am    
That is true, and that is the reason for the code that is showing above. The parameters are somehow different for each charackter, but the problem is interpreting them correctly to make the proper modifications.
I am about to give up on this and stick to your solution, essentially the user will see that the text is smaller than the rectangle he has drawn but he can still select the text and make it bigger in this drawing application. I guess I am a little too perfectionistic about it.
I cannot mark this as a solution but I'll upvote anyway for the effort you put in trying to find a solution.
Can you use this:
TextBox myText = new TextBox();
Rect textRext = myText.GetRectFromCharacterIndex(myText.Text.Length);[^]
Share this answer
Philip Stuyck 16-Sep-12 3:56am    
Did not work, the space is also counted in the measurement, because it is part of the font itself.
So I cannot mark this as a solution but I'll upvote anyway for the effort you put in trying to find a solution.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900