Search code examples
c#wpfxamllayoutdata-binding

How to bind to ActualWidth property


I want to align view model items (from a source) in a ListView having a WrapPanel as ItemsPanel, so that the items are basically aligned in two columns, but if an item is wider than one column, it wraps and thus makes its row higher.

I want to achieve this by a Grid control having the same width as the ListView having two columns, and then get (bind) the width of one item from the ActualWidth of one of the ColumnDefinitions of the Grid.

So, I created the following XAML:

<Grid>
    <Grid.ColumnDefinitions>
        <!--The column to bind from is a bit less wide than 50% to enable some margin between items in the same row.-->
        <ColumnDefinition x:Name="clm1" Width="45*"/>
        <ColumnDefinition Width="55*"/>
    </Grid.ColumnDefinitions>

    <ListView Grid.ColumnSpan="2" Width="some width" Height="some height" ItemsSource="some source">
        <!--the wrap panel that wraps items after two is in a row-->
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel ItemWidth="{Binding ActualWidth, ElementName=clm1}" Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>

        <ListView.ItemTemplate>
            <DataTemplate>
                <!--some properties are binded to the view model object in the DataContext-->
                <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}">
                    <!--separate TextBlock is for text wrapping-->
                    <TextBlock Text="{Binding Text}" TextWrapping="Wrap"/>
                </CheckBox>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

However, this does not work, the items are aligned as in a regular WrapPanel, rather than in columns.

The reason why this does not work: I checked (in Live Property Explorer) what value the binding to ActualWidth evaluates to, and it is double.NaN, although the ActualWidth property has a normal numerical value.

So the main question is: why that binding does not work? (And the secondary question is: how to properly achieve the desired layout?)


Solution

  • Creating a view model depends on the desired architecture of your solution. For example, I use the MSDN MVVM Pattern for larger projects because it allows for better unit testing. In my humble opinion, when you need to do complex bindings and are working with a lot of data, view models are a more elegant solution.