Search code examples
.netwpfxamldatatemplateitemscontrol

ItemsControl within ItemsControl


(After pulling hair for 8 consecutive hours, I've given up. Will be very thankful if someone could come to rescue):

Here's what I have:

AlbumItem: This is an ItemsControl that uses a Canvas as its ItemsPanel and binds to a colletion property of the underlying VM. A handful of DataTemplates defined in Resources section of this control perform conversion of ViewModel objects into UI objects. This control works really nicely and as expected.

Album: This again is an ItemsControl that uses a UniformGrid as its ItemsPanel and binds to a colletion property of the underlying VM. This control shows a grid of AlbumItems. I have set the ItemTemplate of this control to AlbumItem.

No matter what I do, this second control doesn't use its ItemTemplate to display its items. UniformGrid works nicely and I get a 3 x 3 grid of items, but each of those items is a simple TextBlock showing the class name of the underlying VM object.

I have tried to use a DataTemplate too, instead of using ItemTemplate, to no avail.

Can anyone see where is it going wrong?

Edit

Posting a working sample would be a huge undertaking (this is a complex project), but I can post relevant XAML here:

AlbumItem

<ItemsControl x:Class="AlbumItem" 
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:bd="clr-namespace:ViewProject" 
         xmlns:vm="clr-namespace:ViewModelProject" 
         mc:Ignorable="d" 
         ItemsSource="{Binding Path=Children}"
         ClipToBounds="True" Background="LightYellow">
<ItemsControl.Resources>
  <BooleanToVisibilityConverter x:Key="B2VConverter" />
  <DataTemplate DataType="{x:Type vm:Ellipse}">
    <Ellipse IsHitTestVisible="False" StrokeThickness="{Binding BorderThickness}" Fill="{Binding Fill, Mode=OneWay}" Stroke="{Binding Stroke, Mode=OneWay}" />
  </DataTemplate>  
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
   <ItemsPanelTemplate>
     <Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Focusable="true" Width="{Binding Size.Width}" Height="{Binding Size.Height}" FocusVisualStyle="{x:Null}">
     </Canvas>
   </ItemsPanelTemplate>
 </ItemsControl.ItemsPanel>
 <ItemsControl.ItemContainerStyle>
    <Style>
      <Setter Property="Canvas.Left" Value="{Binding Path=Location.X}" />
      <Setter Property="Canvas.Top" Value="{Binding Path=Location.Y}" />
      <Setter Property="Panel.ZIndex" Value="{Binding Path=GlobalZOrder}" />
    </Style>
  </ItemsControl.ItemContainerStyle>
</ItemsControl>

Album

<ItemsControl x:Class="Album"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         xmlns:bd="clr-namespace:ViewProject" 
         xmlns:vm="clr-namespace:ViewModelProject" 
         d:DesignHeight="500" d:DesignWidth="800"
         ItemsSource="{Binding Drawing.Baked}" 
         ClipToBounds="True">

  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <UniformGrid Rows="3" Columns="3" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate DataType="vm:ReadonlyDrawingVM">
      <bd:AlbumItem />
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

I have used Snoop to confirm the following:

  • Album's DataContext is correct. So is its ItemsSource. I can actually see all the VM objects in Snoop when I delve ItemsSource.
  • By default Album doesn't show anything at all. If I use Snoop to reset ItemTemplate and/or ItemsPanel properties of Album, I see all the items (i.e. a TextBlock with their class name) in the form of a grid or list depending upon the property that I reset.
  • AlbumItem works fine with design-time XML data. Album doesn't.

Solution

  • This turned out to be due to the underlying data source. I was binding Album with a List<T>, which didn't update the UI with the changes in its items due to the following line of the underlying property Baked:

    If _Baked Is value Then Return
    

    This is the first line in Baked property setter (I'm using the default property template provided by MVVM Light). Since I never assigned a new List<T> to _Baked; only changed items within it, the above line would stop property change notification from being raised. Once I fixed this, my Album started getting populated.