2009-06-30 16 views
9

Estoy tratando de enlazar TwoWay con éxito un ObservableCollection a TextBoxes en un DataTemplate. Puedo hacer que los datos se muestren correctamente, pero no puedo cambiar los datos de la lista a través de la IU. Tengo una clase de modelo llamada 'modelo' que contiene una ObservableCollection llamada 'Lista'. La clase implementa la interfaz INotifyPropertyChanged. Aquí está el xaml para el caparazón. El DataContext para la red de Window1 se establece en "theGrid.DataContext = modelo"¿Cómo puedo vincular un ObservableCollection a TextBoxes en un DataTemplate?

<Window x:Class="BindThat.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:BindThat" 
Title="Window1" Height="300" Width="300"> 
<StackPanel x:Name="theGrid"> 
    <GroupBox BorderBrush="LightGreen"> 
     <GroupBox.Header> 
      <TextBlock Text="Group" /> 
     </GroupBox.Header> 
     <ItemsControl ItemsSource="{Binding Path=List}"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBox Text="{Binding Path=., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </GroupBox> 
</StackPanel> 

Este es el código de la clase del modelo:

class Model : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private void NotifyPropertyChanged(string name) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(name)); 
    } 

    private ObservableCollection<string> _list = new ObservableCollection<string>(); 
    public ObservableCollection<string> List 
    { 
     get { return _list; } 
     set 
     { 
      _list = value; 
      NotifyPropertyChanged("List"); 
     } 
    } 

    public Model() 
    { 
     List.Add("why"); 
     List.Add("not"); 
     List.Add("these?"); 
    } 
} 

Podría cualquier persona aconsejar si voy acerca esta es la forma correcta?

Respuesta

12

Necesita una propiedad para unir en dos direcciones, por lo que la cadena no es buena para esto.

lo envuelve en un objeto de cadena, así:

public class Model 
{ 
    public ObservableCollection<StringObject> List { get; private set; } 
    public Model() 
    { 
     List = new ObservableCollection<StringObject> 
        { 
         new StringObject {Value = "why"}, 
         new StringObject {Value = "not"}, 
         new StringObject {Value = "these"}, 
        }; 
    } 
} 

public class StringObject 
{ 
    public string Value { get; set; } 
} 

y se unen a la propiedad Valor en lugar de ""

Además, no es necesario que notifique un cambio en la recopilación observable, por lo que hasta que su modelo tenga otras propiedades propias, no es necesario que tenga INotifyPropertyChange. Si desea que su ItemsControl reaccione a los cambios en los StringObjects individuales, debe agregar INotifyPropertyChanged a un StringObject.

Y una vez más, la unión de dos vías es por defecto, por lo que sólo necesitan

<TextBox Text="{Binding Path=Value}" /> 

en su unión.

+0

funciona para mí! ¡¡Muchas gracias!! – Johnathan1

+1

No creo que deba poner "Path =" en la propiedad Text, 'Text =" {Binding Value} "' también funcionaría – user1069816

+0

¿Por qué funciona la cadena simple pero no la lista ? – YukiSakura

1

Creo que necesita derivar los elementos de su colección de DependencyObject para que funcione el enlace TwoWay. Algo así como:

public class DependencyString: DependencyObject { 
    public string Value { 
     get { return (string)GetValue(ValueProperty); } 
     set { SetValue(ValueProperty, value); } 
    } 

    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register("Value", typeof(string), typeof(DependencyString), new UIPropertyMetadata("")); 

    public override string ToString() { 
     return Value; 
    } 

    public DependencyString(string s) { 
     this.Value = s; 
    } 
} 

public class Model { 
    private ObservableCollection<DependencyString> _list = new ObservableCollection<DependencyString>(); 
    public ObservableCollection<DependencyString> List { 
     get { return _list; } 
    } 

    public Model() { 
     List.Add(new DependencyString("why")); 
     List.Add(new DependencyString("not")); 
     List.Add(new DependencyString("these?")); 
    } 
} 

...

<StackPanel x:Name="theGrid"> 
    <GroupBox BorderBrush="LightGreen"> 
     <GroupBox.Header> 
      <TextBlock Text="Group" />   
     </GroupBox.Header> 
     <ItemsControl ItemsSource="{Binding Path=List}"> 
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBox Text="{Binding Path=Value, Mode=TwoWay}"/> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </GroupBox> 
</StackPanel> 
+0

No creo que se necesite una DependencyProperty en este caso. Eso solo es necesario si desea vincular esa propiedad a otra cosa. – Andy

+0

Basado en ambas ideas ahora, pude encontrar una solución para mi aplicación. ¡¡Gracias por tu publicación!! – Johnathan1

+0

Esto me ayudó mucho, gracias. La parte que me faltaba era establecer el modo = TwoWay para que pudiera acceder a los datos actualizados de listbox.itemsSource después de que el usuario hubiera hecho sus cambios. – javram

Cuestiones relacionadas