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

3

1

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.

Plantagenet answered 26/5, 2009 at 22:19 Comment(0)
P
0

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;
    }
Plantagenet answered 27/5, 2009 at 19:33 Comment(0)
K
1

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.

Karakoram answered 26/5, 2009 at 22:26 Comment(2)
Yes, I meant .Net. I should have been more specific. I'm writing the client in WPF and Silverlight. FIXED.Plantagenet
The System.Drawing namespace is not available in Silverlight and from what I can tell there isn't an equivalent method laying aroundPlantagenet
S
1

@mrphil: Sweet aborted fetus, that's scary

myTreeViewItem.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
Size s = myTreeViewItem.DesiredSize;
return s.Width;
Spud answered 28/5, 2009 at 6:20 Comment(2)
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.Plantagenet
Ok - in this case, use Snoop (blois.us/Snoop) to find an appropriate thing to measureSpud
P
0

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;
    }
Plantagenet answered 27/5, 2009 at 19:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.