Pregunta

Hace tiempo que me rasco la cabeza con esto y estoy perplejo en este momento.

El escenario del problema es más fácil de explicar como código, así que espero que hable por sí mismo. En primer lugar, tengo una aplicación Silverlight con lo siguiente en 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>

Mi código subyacente se ve así ... (todo escrito en un solo archivo de clase para que le resulte fácil copiarlo en su propio proyecto y compilarlo)

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"));
            }
        }
    }
}

Entonces déjame explicarte ... Me propuse escribir una forma genérica de crear una ObservableCollection que tenga una propiedad SelectedItem para que cuando vincule la colección a un ComboBox, por ejemplo, pueda vincular el SelectedItem del ComboBox propiedad de ella.

Sin embargo, por alguna razón, no parece funcionar cuando el ComboBox está anidado efectivamente a través de un ItemTemplate. Efectivamente tengo una lista de listas, un escenario que es lo suficientemente simple como para perderme en lo que está mal.

Cuando ejecute el código, verá que el ComboBox con plantilla recoge los elementos correctos, pero nunca se establece en un SelectedItem a pesar del enlace.

Sé que es bastante largo, pero ... ¿alguna idea?

Muchas gracias

¿Fue útil?

Solución

La salida del depurador realmente te da una pista del problema:

Error de System.Windows.Data: error de ruta de BindingExpression: propiedad 'SelectedItem' no encontrada en 'ExpressionElements.SomeClass' 'ExpressionElements.SomeClass' (HashCode = 49044892). BindingExpression: Path = 'SelectedItem' DataItem = 'ExpressionElements.SomeClass' (HashCode = 49044892); el elemento de destino es 'System.Windows.Controls.ComboBox' (Name = ''); la propiedad de destino es 'SelectedItem' (tipo 'System.Object') ..

Debido a que el contexto de datos para la plantilla es una instancia de la clase SomeClass, todo lo que tiene que hacer es cambiar el enlace SelectedItem de SelectedItem a StringsChild.SelectedItem :

<DataTemplate x:Key="icTemplate">
    <ComboBox ItemsSource="{Binding StringsChild}" 
     SelectedItem="{Binding StringsChild.SelectedItem}"/>
</DataTemplate>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top