views:

365

answers:

1

I have a main window with a single user control in it, called SuperMode. SuperMode consists of a collection of people and each person in this collection has their own collection of tasks. Sounds simple, right?

From file SuperMode.xaml:

<UserControl 
    x:Class="Prototype.SuperMode"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Prototype"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"> <!-- NOTE! -->
    <!-- Look at how I'm setting the DataContext, as I think it's
         important to solve the problem! -->

    <ScrollViewer CanContentScroll="True">
        <ItemsControl ItemsSource="{Binding People}" Margin="1">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Rows="1"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </ScrollViewer>

</UserControl>

This works fine and I can see four people as I expect! Now all I have to do is get the XAML right for the Person user control so that all of their tasks are displayed as well.

As you can see, I'm using the People property to populate the control with items. The People property has type ObservableCollection<Person>, where Person is another user control as such...

From Person.xaml:

<UserControl 
    x:Class="Prototype.Person"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Prototype">

    <Border Background="Black" CornerRadius="4" Margin="1">
        <ItemsControl ItemsSource="{Binding Tasks}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Border>

</UserControl>

Tasks here is a property of Person with type ObservableCollection<Task>. This is where it gets stuck! Apparently WPF cannot find any Tasks property and looking at the output window from VS2008, I find the following:

System.Windows.Data Error: 39 : BindingExpression path error: 'Tasks' property not found on 'object' ''SuperMode' (Name='SuperMode')'. BindingExpression:Path=Tasks; DataItem='SuperMode' (Name='SuperMode'); target element is 'ItemsControl' (Name=''); target property is 'ItemsSource' (type 'IEnumerable')

Now I'm lost. It seems that I have to set the DataContext attribute on each Person, otherwise it will still think that the data context is SuperMode, but how do I do that?

+1  A: 

Ignoring the rather unpleasant design you have (you should look into MVVM), you should be able to set the DataContext for the child UserControls as follows:

<ItemsControl ItemsSource="{Binding People}" Margin="1">
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Setter Property="FrameworkElement.DataContext" Value="{Binding RelativeSource={RelativeSource Self}}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid Rows="1"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

HTH,
Kent

Kent Boogaart
Thank you, I'll try that and get back to you. Do you happen to have a link to a good place where I can see a real-world example of MVVM in action complete with source code and explanation?
Deniz Dogan
Try this: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Kent Boogaart