Benziner
Benziner

Reputation: 43

get button width at auto size width in Wpf

Hi I want my button in my C# WPF program to autosize depending on content. This is what I already mentioned. But now I want to know what width the button actually got. I tried button.ActualWidth and button.width. The first returned "0" and the second returned "NaN".

My XAML for the button

<Button x:Name="button1" Content="Button" HorizontalAlignment="Left" Margin="61,41,433,0" VerticalAlignment="Top" IsEnabled="False" Click="button1_Click"/>

New content of my button:

button1.Content = "new content xayxax ";

nWidth = button.ActualWidth;
MessageBox.Show(nWidth.ToString());

This Messagebox displays "0"

Upvotes: 0

Views: 2701

Answers (2)

mm8
mm8

Reputation: 169280

As suggested by @Sinatr (+1) you need to measure the Button after you have set its Content property - or wait until WPF measures it for you - but make sure that you use an large enough available space when you measure it:

button1.Content = "new content xayxax ";
var size = new Size(double.PositiveInfinity, double.PositiveInfinity);
button1.Measure(size);
button1.Arrange(new Rect(button1.DesiredSize));
MessageBox.Show(button1.ActualWidth.ToString());

This should display "110,703" which is the actual size of the Button after its Content has been updated.

Upvotes: 2

Sinatr
Sinatr

Reputation: 21999

ActualWidth should never be NaN (it starts from 0 before measure and arrange) , but Width can. Width == NaN means control width wasn't locally set and the control actual size will depends on layout.

Use ActualWidth to get width of control after measure and arrange:

var button = new Button();
button.Content = "123";
button.HorizontalAlignment = HorizontalAlignment.Left;
button.Measure(new Size(100, 100));
button.Arrange(new Rect(0, 0, 100, 100));
MessageBox.Show(button.ActualWidth.ToString()); // Output: 23,41

You don't event need a window (the way how WPF engine works), but you must to call Measure and Arrange.

Changing Content will not refresh the control, that would occurs some time later, you can invoke the call like this to get it:

void button_Click(object sender, RoutedEventArgs e)
{
    button.Content = "123";
    //MessageBox.Show(button.ActualWidth.ToString()); // output: 0
    Dispatcher.Invoke(() => MessageBox.Show(button.ActualWidth.ToString()), DispatcherPriority.Render); // correct output
}

First message box will still display old size, new size become available only measure/arrange. Invoke with DispatcherPriority.Render will ensure what render occurs (it will do measure/arrange), returning correct new size.

If you can't wait with invoke, then just call Measure and Arrange yourself (passing parent container available size, or just invoking it on the root element of visual tree).

Upvotes: 2

Related Questions