views:

27

answers:

1

I wrote a simple UpDown UserControl for my application. I am rendering it in a ListBox so that as UpDown controls get added, they stack up horizontally.

My UserControl has one DependencyProperty that corresponds to the number inside of the UpDown control, called NumberProperty.

I add multiple UpDown controls to the ListBox via databinding, where the ItemsSource for the ListBox is merely an ObservableCollection<NumberGroup> called NumberGroups. Each NumberGroup just has a member called Number, and I want this number to appear in its respective UpDown control when the ListBox is rendered.

My ListBox is defined in XAML like this:

    <ListBox Grid.Row="1" ItemsSource="{Binding NumberGroups}" ItemTemplate="{StaticResource NumberGroupTemplate}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" Width="Auto" Height="Auto" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>

and the DataTemplate for the ListBox is:

    <DataTemplate x:Key="RackTemplate">
        <StackPanel Orientation="Vertical">
            <TextBlock>Group</TextBlock>
            <updown:UpDown Number="{Binding Number}" />
        </StackPanel>
    </DataTemplate>

It's a little confusing because I named the DependencyProperty Number in the UpDown UserControl the same as the property in the NumberGroup class. NumberGroup is merely:

public class NumberGroup
{
    public int Number { get; set; }
}

When I run the application, I already know it's not going to work because the Output window tells me:

System.Windows.Data Error: 39 : BindingExpression path error: 'Number' property not found on 'object' ''UpDown' (Name='')'. BindingExpression:Path=Number; DataItem='UpDown' (Name=''); target element is 'UpDown' (Name=''); target property is 'Number' (type 'Int32')

OK, so it's binding to the UserControl instead of the ListItem... that can't be write. So as a test, I removed the DataTemplate from the Resources and ListBox definition and re-ran it. In the ListBox, I got a bunch of NumberGroups, which is exactly what I would expect!

So how come when I do this, it seems to bind against the ListItem, but when I define the ItemTemplate it wants to bind to the UpDown control? Any explanation would be really appreciated. I've gone over the Dr. WPF articles and don't see why this would happen.

UPDATE

Ok, I figured out something related to my problem. Within the UserControl, I am setting the DataContext to itself, so that I can process the ICommands that deal with the Up and Down buttons. But for some reason I don't yet understand, it messes with the databinding for the ListItem! Why would this happen if the UserControl is contained inside of the ListItem?

+1  A: 

When you set the UserControl's DataContext internally to itself you're getting exactly the same effect as if you did this:

<updown:UpDown DataContext="{Binding RelativeSource={RelativeSource Self}}" />

Obviously now any Bindings that you set which have no explicit Source defined will use the UpDown control as their context. So when you're trying to bind to the Number property it's looking for a Number property on UpDown instead of your ListBoxItem's data. This is exactly what your error is telling you.

To avoid this change your DataContext setting in your UserControl to apply to an element inside the control, like a root layout Grid with an x:Name.

<Grid x:Name="LayoutRoot">
...
</Grid>

And set DataContext either in code or XAML.

LayoutRoot.DataContext = this;
John Bowen
@John thanks for the tip! Like you said, that does get rid of the error message that indicates that the binding was to the UpDown UserControl instead of the CLR data. Now my problem is that I can't set the text in my UpDown control. I have a `DependencyProperty` for Number, because I'd like to do something like `<updown:UpDown Number="{Binding ClientNumber}">`, but it doesn't seem to work. Even hardcoding `Number` doesn't work, so I assume my DependencyProperty isn't working (but it works internally, because my up and down button commands can change the Number value!)
Dave
@John interesting, I put my control into a test app, and setting the number via the Window worked fine... but setting it from within my UserControl (I have a UserControl within a UserControl) doesn't.
Dave
@John stupid coder mistake, everything works great, thanks again for your useful tip!
Dave