Search code examples
wpfdata-binding

RelativeSource binding doesn't work when ListBox source items are embedded in xaml


Is there a specific way of defining ItemsSource when items are provided in the control? In this code, the first TextBlock of the data template shows a value, the second not.

<ListBox x:Name="myList">
    <ListBoxItem>Three</ListBoxItem>
    <ListBoxItem>Can</ListBoxItem>
    <ListBoxItem>Keep</ListBoxItem>
    <ListBoxItem>A</ListBoxItem>
    <ListBoxItem>Secret</ListBoxItem>

    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding}"/>
                <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=PreviousData},
                                          StringFormat=' (previous: {0})'}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

If I set the items list in a resource and set the ItemsSource property to refer to the list resource, both bindings work:

<Window.Resources>
    <local:MyStringList x:Key="lst">
        <sys:String>Three</sys:String>
        <sys:String>Can</sys:String>
        <sys:String>Keep</sys:String>
        <sys:String>A</sys:String>
        <sys:String>Secret</sys:String>
    </local:MyStringList>
</Window.Resources>

<ListBox x:Name="myList" ItemsSource="{StaticResource ResourceKey=lst}">

Solution

  • Your ItemTemplate isn't used at all, since you are directly adding ListBoxItems to the Items collection (btw. not ItemsSource).

    The ItemTemplate is only applied for items that are no UI elements, or more precisely for items for which the IsItemItsOwnContainer method returns false.

    In this case, a ListBoxItem container is generated, and the value of the ListBox's ItemTemplate property is applied to its ContentTemplate property.

    So this would work:

    <ListBox x:Name="myList">
        <sys:String>Three</sys:String>
        <sys:String>Can</sys:String>
        <sys:String>Keep</sys:String>
        <sys:String>A</sys:String>
        <sys:String>Secret</sys:String>
    
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding}"/>
                    <TextBlock Text="{Binding RelativeSource={RelativeSource Mode=PreviousData},
                                              StringFormat=' (previous: {0})'}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>