Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine the height of all items contained in a DockPanel

I have a DockPanel to which I am programmatically adding TextBlock controls. The DockPanel is defined so:

    <DockPanel x:Name="staHeadlines" Margin="0,10,0,0"
     ScrollViewer.VerticalScrollBarVisibility="Disabled"/>

The TextBlocks are added to the DockPanel as follows:

    For count = headlinePosition To maxHeadlineCount
        Dim tb As New TextBlock With {.Text = headlines.Item(count), 
            .FontFamily = New FontFamily("Segoe UI Semilight"), .FontSize = "22",
            .TextWrapping = TextWrapping.Wrap, .Margin = New Thickness(0, 10, 0, 10)}
        DockPanel.SetDock(tb, Dock.Top)
        staHeadlines.Children.Add(tb)
    Next

The DockPanel is used to display news headlines, one per TextBlock. I want to add sufficient TextBlocks to fill the available space, but not let the bottom item overflow the DockPanel bounds. As the height of the TextBlock is defined by the content - which I do not know in advance - I need to be able to calculate the height of all items added to the DockPanel to determine if the last child added will overflow the bounds of the DockPanel and appear clipped.

Any ideas?

like image 681
Dan Avatar asked Oct 30 '22 11:10

Dan


1 Answers

You can try something like this...

        private void TryAddNewTextBox(TextBox textbox)
        {
            this.staHeadlines.Children.Add(textbox);
            textbox.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

            var totalChildrenHeight = textbox.DesiredSize.Height + this.staHeadlines.Children.OfType<TextBox>().Sum(childTextbox => GetElementBoundsHeight(childTextbox));

            if (totalChildrenHeight > GetElementBoundsHeight(this.staHeadlines))
                this.staHeadlines.Children.RemoveAt(this.staHeadlines.Children.Count - 1);
        }

        private double GetElementBoundsHeight(FrameworkElement element)
        {
            return element.RenderTransform.TransformBounds(new Rect(element.RenderSize)).Height;
        }

The tricky part here is getting the size of the new TextBox before it has been rendered. We do this by first adding to the DockPanel, then calling Measure on the TextBox. By passing new Size(double.PositiveInfinity, double.PositiveInfinity), we are basically saying 'Mr. TextBox, render yourself as large as you need to be to show your content'. By doing this we know what size the new control will be. Then all we have to do is add the height of the new TextBox to the sum of all the DockPanel's children's height bounds. Compare the result of that to the bounds of the DockPanel and BOOM. Could clean up this code a bit, but hopefully it helps.

like image 132
Justin Shep Avatar answered Nov 15 '22 05:11

Justin Shep