9

I have the following code:

<Window x:Class="UnderstandSizing.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" x:Name="Column1" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBox Grid.Column="0" Text="{Binding ActualWidth,ElementName=Column1,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</Window>

I expected to see at the textbox the value of the width of the column Column1 but all I can see is 0.

I've seen this and this but everywhere says that is related only to Silverlight, not WPF.

Edit Fixed a typo. Also to note that the Output window do not show any binding issue . What is strange to me is that it is working in the designer. It stops working only on runtime.

Community
  • 1
  • 1
Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207

3 Answers3

9

Interesting...

As DanM found, ColumnDefinition.ActualWidth is not a dependency property so you wont get binding updates when it changes.

A workaround is to put a hidden control in the column and bind to it's ActualWidth like this:

    <ContentControl Visibility="Hidden" Grid.Column="0" HorizontalAlignment="Stretch" x:Name="hidden"/>
    <TextBox Grid.Column="0" Text="{Binding ActualWidth,ElementName=hidden,Mode=OneWay}" />
Robert Levy
  • 28,747
  • 6
  • 62
  • 94
5

Wouldn't this be a circular reference? The width of "Column1" is dependent on the Text of your TextBox, and the Text of your TextBox is dependent on the width of "Column1". I don't see how WPF could ever possibly resolve a value for this unless you explicitly set the width of either "Column1" or your TextBox.

Edit

Oh, I see the problem. ActualWidth is a double not a dependency property, so you will never receive an update when the value gets calculated.

You need to use @Robert Levy's suggestion of putting a dummy control in the space occupied by your TextBox and bind to the ActualWidth of that instead.

devuxer
  • 41,681
  • 47
  • 180
  • 292
  • If that was the case I would expect a never ending loop not a 0. Anyway the text 100 needs the same space as 110. – Ignacio Soler Garcia Jan 25 '12 at 19:27
  • 1
    The zero may be WPF's way of dealing with the infinite loop. – devuxer Jan 25 '12 at 19:28
  • I've tried changing to the rowheight and the same happens, so looks like this is not what is happening because the row has the same height with or without text. – Ignacio Soler Garcia Jan 25 '12 at 19:30
  • Try this: change the width of your two column definitions to `*` instead of `Auto`. If the binding is working, your `TextBlock` should show "150". – devuxer Jan 25 '12 at 19:32
  • None. No errors, no warnings. The binding working in designtime and not in runtime. – Ignacio Soler Garcia Jan 25 '12 at 19:37
  • 1
    Sorry but the MSDN says that is a DP. http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.actualwidth.aspx – Ignacio Soler Garcia Jan 25 '12 at 21:34
  • @Robert, good question. I have asked myself the same thing with several properties throughout WPF. AFAIK, just about every property of every control should be a DP, but I guess the WPF team felt differently when it designed the classes. – devuxer Jan 25 '12 at 21:34
  • 2
    @SoMoS, `ColumnnDefinition` is not a `FrameworkElement`: http://msdn.microsoft.com/en-us/library/system.windows.controls.columndefinition.aspx. It's actually a `FrameworkContentElement`, which is not the same thing. Here is the page for the actual property -- it clearly says `double` for `ActualWidth`: http://msdn.microsoft.com/en-us/library/system.windows.controls.columndefinition.actualwidth.aspx – devuxer Jan 25 '12 at 21:35
3

You have a typo in this line of XAML:

<TextBox Grid.Column="0" Text="{Binding ActualWidth,ElementName=Colum1,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}" />

ElementName should be Column1 instead of Colum1.

One of the nice things about XAML is that it will still run if you have done an improper binding, and one of the frustrating things about XAML is that it will still run if you have done an improper binding.

EDIT

If you bind to the ActualWidth of the textbox itself, that is within the column, it will work just fine.

<TextBox Name="tbk1" Grid.Column="0" Text="{Binding ElementName=tbk1, Path=ActualWidth, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />

or, more simply (no requirement to name the textbox):

<TextBox Grid.Column="0" Text="{Binding Path=ActualWidth, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource Self}}" />
Stewbob
  • 16,759
  • 9
  • 63
  • 107