ceilidhboy

I'm seeing some strange & inexplicable behaviour with databinding on an ItemsControl nested inside another one. It seems like a bug to me, but maybe there's some subtlety I'm missing

The idea is to display a list of countries horizontally, with the name of each country at the top of a column, and cities in each country listed underneath.

I've done this using an outer ItemsControl has a horizontal StackPanel as it's ItemsPanel. It's item template has a data template containing another ItemsControl, this time vertical, to list the cities underneath the country name.

There's a simple style in the outer resources for text blocks - it just gives a little margin and sets the foreground to blue - mainly so you can see that it's applied.

Now what's happening is this: if the style doesn't get used for the city heading, the text block style is only applied to the cities in the first column! How weird is that It's clear from running the sample below. The 2nd and 3rd columns clearly aren't styled, yet each column is created from a data template so they should all be the same.

Even more weird, if the style is applied to a column heading (the country name) then only one country is displayed - the 2nd and 3rd simply don't appear!

Why on earth should setting a style on a text block cause only one the first item from the bound array to be created !

Am I missing something here

I've boiled down a sample. It needs both XAML and a small bit of C# to create a suitably nested data structure to which to bind:

Window1.xaml.cs:

using System.Windows;

namespace BindingSpike
{   
    public class Country
    {
        private readonly string name;
        private readonly string[] cities;

        public Country( string name, params string[] cities )
        {
            this.name = name;
            this.cities = cities;
        }

        public string Name
        {
            get { return name; }
        }

        public string[] Cities
        {
            get { return cities; }
        }
    }

    public partial class Window1 : Window
    {

        public Window1()
        {
            Country[] countries = new Country[]
                {
                    new Country("Britain", "London", "Edinburgh", "Cardiff"),
                    new Country("USA", "Washington", "New York", "Los Angeles", "Chicago"),
                    new Country("Slovakia", "Bratislava", "Kosice")
                };
            Resources.Add("countries", countries);
            InitializeComponent();
        }
    }
}

<Window x:Class="BindingSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="clr-namespace:BindingSpike"
    Title="BindingSpike" Height="300" Width="300"
    >
    <DockPanel>
        <ItemsControl ItemsSource="{StaticResource countries}">
            <ItemsControl.Resources>
                <Style x:Key="myStyle">
                    <Setter Property="Control.Margin" Value="4,2"/>
                    <Setter Property="TextBlock.Foreground" Value="Blue"/>
                </Style>
            </ItemsControl.Resources>

            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
           
            <!-- data template for countries -->

            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <ItemsControl ItemsSource="{Binding Path=Cities}">
                        <ItemsControl.Template>
                            <ControlTemplate>
                                <DockPanel>
                                    <!-- TextBlock to display the country name at the top of each column -->
                                    <!-- If the text block has a style reference, only the first country is displayed! -->
                                    <!-- Without the style, all countries are displayed but with the style only applied to the cities in the first country! -->
                                   
                                    <!-- Uncomment one line and comment out the next to see the effect -->
                                    <!-- <TextBlock Style="{StaticResource myStyle}" DockPanel.Dock="Top" Text="{Binding Path=Name}" FontWeight="Bold"/> -->
                                    <TextBlock DockPanel.Dock="Top" Text="{Binding Path=Name}" FontWeight="Bold"/>
                                    <ItemsPresenter/>
                                </DockPanel>
                            </ControlTemplate>
                        </ItemsControl.Template>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Style="{StaticResource myStyle}" Text="{Binding}"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </DataTemplate>
            </ItemsControl.ItemTemplate>

        </ItemsControl>
    </DockPanel>
</Window>





Re: Windows Presentation Foundation (WPF) Strange data binding behaviour with nested ItemsControls

lee d

obviously there is some issue, here is something that does work

<DockPanel>
<DockPanel.Resources>
<Style x:Key="myStyle" TargetType="{x:Type TextBlock}" >
<Setter Property="TextBlock.Foreground" Value="Blue"/>
</Style>
<DataTemplate x:Key="dt2">
<TextBlock Style="{StaticResource myStyle}" Text="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="dt1">
<ItemsControl ItemsSource="{Binding Path=Cities}" ItemTemplate="{StaticResource dt2}">
<ItemsControl.Template>
<ControlTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Top" Text="{Binding Path=Name}" FontWeight="Bold"/>
<ItemsPresenter/>
</DockPanel>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</DataTemplate>

</DockPanel.Resources>
<ItemsControl ItemsSource="{StaticResource countries}" ItemTemplate="{StaticResource dt1}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>