Posted By: kaul | Oct 6th, 2006 @ 2:36 AM
page 1 of 1
Comments: 23 | Views: 11655
I have a textblock (wpf) which is being declared, initialized and filled-in programmatically (code behind).Because of some constraints I can't give this control a fixed size (I have declared minheight, maxheight and minwidth, maxwidth). I want to measure the height of the control after the text has been inserted but what I am getting is NaN. How can the exact height/width can be determined? 

Alternatively can I determine height/width of the text in a line (assuming wrapping is enabled and font is same) can be determined?
footballism
footballism
Another Paradigm Shift!
    Actually you can query the TextBlock's ActualHeight and ActualWidth property to get the actual size which WPF layout engine assigns to your TextBlock, WPF has a very capable layout system, the actual size of  controls in WPF is finally determined by the layout, not by the properties set on them.

Sheva
footballism
footballism
Another Paradigm Shift!
Just test this xaml snippet, and see what prints out:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel>
    <TextBlock Text="Windows Presentation Foundation" Name="textBlock"/>
    <Label Content="{Binding Path=ActualWidth, ElementName=textBlock}"/>
    <Label Content="{Binding Path=ActualHeight, ElementName=textBlock}"/>
    <Label Content="{Binding Path=Width, ElementName=textBlock}"/>
    <Label Content="{Binding Path=Height, ElementName=textBlock}"/>
  </StackPanel>
</Page>

Sheva
TommyCarlier
TommyCarlier
I want my scalps!
What do you get if you ask the ActualHeight AFTER adding it to spnl?

May be you can use another function in which you can find out the actual height of textblock.

i trie it myself, it is still giving NaN, if give height or width as Auto and check it at runtime, may be we can count \r\n, but then again i am not sure 
footballism
footballism
Another Paradigm Shift!
    Hi, Kaul, the problem with your code is that you instantiate a textblock in the Test method, and you check its size immediately in the same method block, so there is no wonder why you ain't get the correct size value, the thing here is that when you instantiate a TextBlock, you should give the WPF layout engine an opporntunity to calculate the actual size for the newly instantiated TextBlock, but the WPF dispatcher is currently running in your method body, it cannot do the layout at the same time when it is still running inside the current method block, actually if you want to get the actual size of the newly instantiated TextBlock, you should do something like this in the Test method body:

            TextBlock tb = new TextBlock();
            tb.TextWrapping = TextWrapping.Wrap;
            tb.MaxHeight = 200;
            tb.MinHeight = 10;
            tb.MaxWidth = 100;
            tb.MinWidth = 100;
            tb.Text = "sahf ivdahy;fyia yiyficvaysdfyilaysilyfiluyhsdfylia asdafsbgtgsrgtyvteryhifl aybisyfi a";
            spnl.Children.Add(tb);
            spnl.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(Object state)
            {
                MessageBox.Show(tb.ActualHeight.ToString());
                return null;
            }), null);


   Sheva

footballism
footballism
Another Paradigm Shift!
Sorry, bad typo, it shoud be:
spnl.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(Object state)
{
	MessageBox.Show(tb.ActualHeight.ToString());
	return null;
}), null);

Sheva

footballism
footballism
Another Paradigm Shift!
    Hey, kaul, what you are trying to do is that you just want to know the actual size of the specified WPF control without adding it to the visual tree or even logical tree, right?
    Well, the problem is that WPF has a very sophisticated layout engine, to put it simple, WPF use two passes of layout operations to calculate the atual size and location of the child controls, they are Measure, and Arrange, Measure pass is responsible for figuring out how large the child control is desired to be, and the Arrange pass is finally responsible for positioning the control on the screen, and in the arrange pass, the actual size of the control is returned, and all those layout operations first happens on the root visual, typically its a Window, and immediately after the root visual, it will call the two passes of layout operations down the visual tree recursively on the child elements if they are present. so only if you add the control to the visual tree, its actual size can be calculated, and returned.

Sheva
I've just come across your post. Sheva is right about the need to perform a Measure pass on the control, but you shouldn't actually require the Layout pass (the Measure will return the control's size).

Try just calling Measure, then rather than the ActualWidth and ActualHeight properties, use the DesiredSize property instead.
Using Measure(Double.PositiveInfinity, Double.PositiveInfinity) and then using DesiredSize worked swell, thanks.  Glad I didn't have to BeginInvoke to measure text . . . .

Eric
bonk
bonk
Ich bin der Wurstfachverkäuferin !

Oops, already anwered -- ignore

I am trying to do the same thing, except I can't use the DesiredWidth value -- I need the ActualWidth (as the final width is determined by the layout and is not the same thing as the DesiredSize).

Is there a way to get the final width after layout? It would be nice if there was an OnLayoutComplete callback where I could put all of my initialization code that is dependant on post-layout values.

I'm new to C#, coming from a JScript/Actionscript background.

I think I can find a workaround -- using Dispatcher, or watching for a positive value in ActualWidth from a CompositionTarget Rendering event. But please let me know if there is a better way to do it.
footballism
footballism
Another Paradigm Shift!
   You can hook up to UIElement.LayoutUpdated event to initialize your size-aware code.

Sheva

Use myControl.UpdateLayout() to fully update the layout of the control and populate the ActualWidth and ActualHeight properties. As it has been already said, your control must be a part of the visual tree or the method won't work.

page 1 of 1
Comments: 23 | Views: 11655
Microsoft Communities