Search code examples
wpfdata-binding

Binding by ElementName/RelativeSource fails on ListBox but works on items inside it


I have a simple WPF test app. It is a Window with a Grid, holding a ListBox showing Image elements. When I first ran it, the images expanded past the boundaries of the Window, so I bound their MaxWidth property to the Window's ActualWidth. This worked whether I bound by ElementName or RelativeSource

But when I take that exact same binding and move it up from each individual Image element to the containing ListBox (or to the Grid), it has no effect. The images (or ListBox) expand past the limits of the Window again.

There is no binding warning in the output window. It just does nothing.

However if I place a hard-coded width value (e.g. "400") in any of these 3 places it works just fine. It's just the binding that stops working at a higher level.

Can anyone tell me why? Understanding why would help me in a lot of other binding situations

Here is the XAML with the working binding on the Image elements

<Window x:Class="MVVM_RenderPhotos.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MVVM_RenderPhotos"
        xmlns:vm="clr-namespace:MVVM_RenderPhotos.ViewModels"
        xmlns:models="clr-namespace:MVVM_RenderPhotos.Models"
        d:DataContext="{d:DesignInstance {x:Type vm:MainWindowVm}}"
        mc:Ignorable="d"
        x:Name="Root"
        Title="MainWindow" Height="800" Width="400">

    <Grid x:Name="MainGrid">
        <ListBox ItemsSource="{Binding Scans}">
            <ListBox.ItemTemplate>
                <DataTemplate DataType="{x:Type models:Scan}">
                    <Grid >
                        <Image MaxWidth="{Binding ElementName=Root, Path=ActualWidth}" 
                               Source="{Binding Thumbnail}" />
                    </Grid>
                </DataTemplate>

            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Solution

  • The Binding works, it just has no a noticable effect, since the Grid and the ListBox are already as wide as the Window's client area and hence less wide than the MaxWidth value from the Binding.

    Besides that, there is no need at all to bind MaxWidth or Width.

    Just disable horizontal scrolling of the ListBox. With horizontal scrolling enabled, the item containers in the ListBox grow as wide as they want, i.e as wide as the desired width of the contained Image elements.

    <ListBox ItemsSource="{Binding Scans}"
             ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Thumbnail}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>