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;