Porque é que este simples ligação de dados cenário não trabalho? (Caixa de combinação relacionadas)
-
19-08-2019 - |
Pergunta
Eu fui coçar a cabeça em um presente por um tempo agora e estou perplexo no momento.
O cenário de problema é mais fácil de explicar como código por isso espero que fala por si. Primeiro de tudo, eu tenho um aplicativo do Silverlight com o seguinte no 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>
Meu código-behind olhares como este ... (todos escritos em um único arquivo de classe de modo que é fácil para você copiá-lo em seu próprio projeto e compilação)
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"));
}
}
}
}
Então, deixe-me explicar ... Me propus a escrever uma forma genérica de se criar uma ObservableCollection que tem um SelectedItem propriedade sobre ela de modo que quando eu ligar a coleção para uma caixa de combinação, por exemplo, eu pode vincular do ComboBox SelectedItem propriedade a ele.
No entanto, por alguma razão, ele não parece trabalho quando a caixa de combinação é efetivamente aninhado através de um ItemTemplate. Eu efetivamente tem uma lista de listas, um cenário que é suficiente simples que eu estou perdido quanto ao que há de errado.
Quando você executa o código, você verá que a caixa de combinação templated faz pegar os itens corretos, mas nunca definido para um SelectedItem apesar da ligação.
Eu sei que é um pouco prolixo, mas ... alguma idéia?
Muito obrigado
Solução
A saída depurador realmente dá-lhe uma dica para o problema:
System.Windows.Data Erro: BindingExpression caminho de erro: 'SelectedItem' propriedade não foi encontrado na 'ExpressionElements.SomeClass' 'ExpressionElements.SomeClass' (HashCode = 49044892). BindingExpression: Path = 'SelectedItem' DataItem = 'ExpressionElements.SomeClass' (HashCode = 49044892); elemento alvo é 'System.Windows.Controls.ComboBox' (Nome = ''); propriedade de destino é 'SelectedItem' (tipo 'System.Object') ..
Como o contexto de dados para o modelo é uma instância da classe SomeClass, tudo que você tem a fazer é mudar a ligação de SelectedItem para SelectedItem StringsChild.SelectedItem :
<DataTemplate x:Key="icTemplate">
<ComboBox ItemsSource="{Binding StringsChild}"
SelectedItem="{Binding StringsChild.SelectedItem}"/>
</DataTemplate>