Почему этот простой сценарий привязки данных не работает?(связанный со списком)
-
19-08-2019 - |
Вопрос
Я уже некоторое время ломаю голову над этим вопросом и на данный момент нахожусь в тупике.
Сценарий проблемы проще объяснить в виде кода, так что, надеюсь, он говорит сам за себя.Прежде всего, у меня есть приложение silverlight со следующим в XAML...
<UserControl x:Class="SilverlightApplication2.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<UserControl.Resources>
<DataTemplate x:Key="icTemplate">
<ComboBox ItemsSource="{Binding StringsChild}" SelectedItem="{Binding SelectedItem}"/>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ItemsControl x:Name="ic" ItemTemplate="{StaticResource icTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<Button Click="Save" Grid.Row="1" Content="GO"/>
</Grid>
Мой исходный код выглядит следующим образом...(все написано в одном файле класса, чтобы вам было легко скопировать его в свой собственный проект и скомпилировать)
namespace SilverlightApplication2
{
public partial class Page : UserControl
{
public ObservableCollection<SomeClass> StringsParent { get; set; }
public Page()
{
InitializeComponent();
StringsParent = new ObservableCollection<SomeClass>();
ic.ItemsSource = StringsParent;
}
private void Save(object sender, RoutedEventArgs e)
{
SomeClass c = new SomeClass();
c.StringsChild.Add("First");
c.StringsChild.Add("Second");
c.StringsChild.SetSelectedItem("Second");
StringsParent.Add(c);
}
}
public class SomeClass
{
public SelectableObservablecollection<string> StringsChild { get; set; }
public SomeClass()
{
StringsChild = new SelectableObservablecollection<string>();
}
}
public class SelectableObservablecollection<T> : ObservableCollection<T>
{
public SelectableObservablecollection()
: base()
{
}
public void SetSelectedItem<Q>(Q selectedItem)
{
foreach (T item in this)
{
if (item.Equals(selectedItem))
{
SelectedItem = item;
return;
}
}
}
private T _selectedItem;
public T SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged(new PropertyChangedEventArgs("SelectedItem"));
}
}
}
}
Итак, позвольте мне объяснить...Я намеревался написать общий способ создания ObservableCollection, который имеет Выбранный элемент свойство на нем, так что, например, когда я привязываю коллекцию к выпадающему списку, я могу привязать выпадающий список Выбранный элемент собственность к нему.
Однако по какой-то причине это, похоже, не работает, когда поле со списком эффективно вложено через ItemTemplate .Фактически у меня есть список списков, сценарий, который достаточно прост, чтобы я терялся в том, что не так.
Когда вы запустите код, вы увидите, что шаблонное поле со списком действительно выбирает правильные элементы, но оно никогда не устанавливается в SelectedItem, несмотря на привязку.
Я знаю, что это довольно многословно, но...есть идеи?
Большое спасибо
Решение
Выходные данные отладчика на самом деле дают вам подсказку к проблеме:
Система.Windows.Ошибка данных:Ошибка пути к BindingExpression: Свойство 'SelectedItem' не найдено в 'ExpressionElements.SomeClass' 'ExpressionElements.SomeClass' (хэш-код=49044892).Связывающее выражение:Path='SelectedItem' DataItem='ExpressionElements.SomeClass' (Хэш-код=49044892);целевой элемент - 'System.Windows.Элементы управления.Поле со списком' (Name=");целевым свойством является 'SelectedItem' (тип 'System.Объект')..
Поскольку контекст данных для шаблона является экземпляром класса SomeClass, все, что вам нужно сделать, это изменить привязку SelectedItem с SelectedItem на StringsChild.Выбранный элемент:
<DataTemplate x:Key="icTemplate">
<ComboBox ItemsSource="{Binding StringsChild}"
SelectedItem="{Binding StringsChild.SelectedItem}"/>
</DataTemplate>