ListBox ItemTemplate непостоянен с данными CLR и UserControl

Я написал простой UpDown UserControl для моего приложения. Я рендерил его в ListBox, чтобы при добавлении элементов управления UpDown они складывались горизонтально.

Мой UserControl имеет один DependencyProperty, который соответствует номеру внутри элемента управления UpDown, который называется NumberProperty.

Я добавляю несколько элементов управления UpDown в ListBox через привязку данных, где ItemsSource для ListBox является просто ObservableCollection<NumberGroup> называется NumberGroups, каждый NumberGroup просто есть член с именем Number, и я хочу, чтобы этот номер отображался в соответствующем элементе управления UpDown при визуализации ListBox.

Мой ListBox определен в XAML следующим образом:

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

и DataTemplate для ListBox:

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

Это немного сбивает с толку, потому что я назвал DependencyProperty Number в UpDown UserControl то же самое, что и свойство в классе NumberGroup. NumberGroup это просто:

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

Когда я запускаю приложение, я уже знаю, что оно не будет работать, потому что окно "Вывод" говорит мне:

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')

Итак, это привязка к UserControl вместо ListItem... который не может быть записан. В качестве теста я удалил DataTemplate из определения Resources и ListBox и перезапустил его. В ListBox я получил кучу NumberGroupс, что именно то, что я ожидал!

Так почему же, когда я делаю это, он связывается с ListItem, но когда я определяю ItemTemplate, он хочет связываться с элементом управления UpDown? Любое объяснение будет действительно оценено. Я просмотрел статьи доктора WPF и не понимаю, почему это произойдет.

ОБНОВИТЬ

Хорошо, я выяснил кое-что, связанное с моей проблемой. В UserControl я устанавливаю DataContext для себя, чтобы я мог обработать ICommandс кнопками вверх и вниз. Но по какой-то причине я еще не понимаю, это портит привязку данных для ListItem! Почему это произошло бы, если UserControl содержится внутри ListItem?

1 ответ

Решение

Когда вы сами устанавливаете DataContext UserControl внутри себя, вы получаете точно такой же эффект, как если бы вы это сделали:

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

Очевидно, что теперь любые заданные вами привязки, для которых не определен явный источник, будут использовать элемент управления UpDown в качестве контекста. Поэтому, когда вы пытаетесь связать свойство Number, оно ищет свойство Number в UpDown вместо данных вашего ListBoxItem. Это именно то, что говорит вам ваша ошибка.

Чтобы избежать этого, измените настройку DataContext в вашем UserControl, чтобы он применялся к элементу внутри элемента управления, например, к сетке корневого макета с x:Name.

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

И установите DataContext либо в коде, либо в XAML.

LayoutRoot.DataContext = this;
Другие вопросы по тегам