ListBox SelectedItem не обновляет DataTemplate
Следующая проблема: у меня есть DataModel, содержащая список объектов и ссылку на выбранный объект внутри списка (среди прочего) Все работает нормально - если я выбираю s.th. в ListBox это также доступно в SelectedItem - если я изменяю s.th. в SelectedItem он обновляется во всей DataModel.
..С одним исключением: Контент ListBox не обновляется. Я подозреваю, что это как-то связано с DataTemplate, потому что я могу наблюдать следующее:
- если я изменяю SelectedItem, список элементов в DataModel соответствующим образом обновляется (проверено на отладчике - также я всегда вижу правильные данные в окне редактирования выбранного элемента)
- ListBox обновляется, если я добавляю объект из списка внутри DataModel, НО также во время этого обновления я получаю только новый элемент в ListBox, существующие тексты не обновляются (поэтому список фактически отражает данные из DataModel)
- Если я перезагружаю DataModel, вся ListBox перестраивается, и отображаемые данные верны (поэтому в источнике Binding нет ничего плохого)
Обновление: новая информация о точной проблеме
Проблема на самом деле в некоторой комбинации расширений Xsd2Code и ComplexType (в XSD). Я не думаю, что это ошибка в Xsd2Code, сгенерированный код выглядит хорошо.
Используемый файл XSD
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="SampleRoot">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="30">
<xs:element name="SampleElement">
<xs:complexType>
<xs:complexContent>
<xs:extension base="SampleElement"/>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="SampleElement">
<xs:attribute name="Name" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
Используемая DataModel (упрощенная, PropertyChanged правильно реализована, классы SampleRootSampleElement
а также SampleRoot
генерируются Xsd2Code):
public class DataModel : INotifyPropertyChanged
{
public SampleRootSampleElement SelectedItem;
public SampleRoot Root;
}
Что касается XAML, здесь нет ничего особенного:
<ListBox Height="211" HorizontalAlignment="Left" Margin="12,12,0,0" Name="listBoxNames" VerticalAlignment="Top" Width="189" ItemsSource="{Binding Root.SampleElement}" SelectedItem="{Binding SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox HorizontalAlignment="Left" Margin="12,229,0,0" Name="textBoxName" VerticalAlignment="Top" Width="189" Text="{Binding SelectedItem.Name}" />
Эта комбинация показывает описанное поведение. Чтобы исправить это поведение, я могу удалить расширение для SampleElement
внутри XSD, который уменьшает XSD до:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="SampleRoot">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="30">
<xs:element name="SampleElement" type="SampleElement"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="SampleElement">
<xs:attribute name="Name" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
Все остальное остается прежним, за исключением того, что нет SampleRootSampleElement
сгенерированный класс (который был расширением ранее). Вместо SampleElement
непосредственно используется:
public class DataModel : INotifyPropertyChanged
{
public SampleElement SelectedItem;
public SampleRoot Root;
}
Эти несколько изменений заставляют все работать как положено - с недостатком, что расширения не могут использоваться. Так что же плохого в первом подходе, если я хочу расширять сложные типы?
1 ответ
TextBlock
значение не было обновлено из-за двух возможных, но связанных проблем:
- Ваш
Asset
(не знаю, что является базовым типом) класс не реализуетINotifyPropertyChanged
интерфейс. - Если вы реализовали
PropertyChanged
обработчик событий - используйте его вName
сеттер:
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
После применения обоих предложений ваш пример будет работать как положено.