views:

533

answers:

3

How do you determine the width of the text in a WPF TreeViewItem at run time?

I need to calculate an offset so I can draw a line from one leaf to the leaf of a different TreeView. All the 'width' properties return a size that is way bigger than the space taken up by the actual text of the node. It must be possible because the Select feature doesn't highlight the entire row. I'm writing the client in WPF and Silverlight.

A: 

You weren't very specific on the text or the tags, so I'm assuming you're taking about the .Net Framework's TreeViewItem.

There might be easier ways, but one possibility is to use the Graphics.MeasureString method. It gives you the size in pixels of a text when drawn using a specific font.

Badaro
Yes, I meant .Net. I should have been more specific. I'm writing the client in WPF and Silverlight. FIXED.
MrPhil
The System.Drawing namespace is not available in Silverlight and from what I can tell there isn't an equivalent method laying around
MrPhil
A: 

I have two solutions:

A) Uses the visual tree

    TreeViewItem selected = (TreeViewItem)dataSourceTreeView.SelectedItem;
    double textWidth = 0;
    double expanderWidth = 0;
    Grid grid = (Grid)VisualTreeHelper.GetChild(selected, 0);

    ToggleButton toggleButton = (ToggleButton)VisualTreeHelper.GetChild(grid, 0);
    expanderWidth = toggleButton.ActualWidth;

    Border bd = (Border)VisualTreeHelper.GetChild(grid, 1);
    textWidth = bd.ActualWidth;

B) If you don't want to use the visual tree

    TreeViewItem selected = (TreeViewItem)dataSourceTreeView.SelectedItem;
    double textWidth = 0;
    Typeface typeface = new Typeface(selected.FontFamily,
        selected.FontStyle, selected.FontWeight, selected.FontStretch);

    GlyphTypeface glyphTypeface;
    if (!typeface.TryGetGlyphTypeface(out glyphTypeface))
            throw new InvalidOperationException("No glyphtypeface found");

    string headerText = (string)selected.Header;
    double size = selected.FontSize;

    ushort[] glyphIndexes = new ushort[headerText.Length];
    double[] advanceWidths = new double[headerText.Length];

    for (int n = 0; n < headerText.Length; n++)
    {
            ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[headerText[n]];
            glyphIndexes[n] = glyphIndex;

            double width = glyphTypeface.AdvanceWidths[glyphIndex] * size;
            advanceWidths[n] = width;

            textWidth += width;
    }
MrPhil
A: 

@mrphil: Sweet Zombie Jesus, that's scary

myTreeViewItem.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
Size s = myTreeViewItem.DesiredSize;
return s.Width;
Paul Betts
Thanks for trying, but you answer doesn't work for me because: 1. you have a typo. DesireSize is a property not a method so 86 the (). 2. you'll find that this actually gives you the width of the entire tree not that particular item. 3. the size it reports seems to involve some sort of padding and is still larger than the answer my code reports.
MrPhil
Ok - in this case, use Snoop (http://blois.us/Snoop/) to find an appropriate thing to measure
Paul Betts
Cool tool! Thanks!
MrPhil