2009-06-30 6 views
9

Sto tentando di associare correttamente TwoWay a ObservableCollection a TextBoxes in un DataTemplate. Posso visualizzare correttamente i dati, ma non riesco a modificare i dati dell'elenco tramite l'interfaccia utente. Ho una classe Model chiamata 'model' che contiene una ObservableCollection chiamata 'List'. La classe implementa l'interfaccia INotifyPropertyChanged. Ecco l'xaml per la shell. Il DataContext per la griglia di Window1 è impostato su "theGrid.DataContext = modello"Come posso associare una ObservableCollection a TextBoxes in 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> 

Questo è il codice per la classe del modello:

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

Qualcuno potrebbe avvisare se sto andando su questo è il modo corretto?

risposta

12

Hai bisogno di una proprietà da associare in due direzioni, quindi la stringa non è buona per questo.

avvolgerla in un oggetto stringa, in questo modo:

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

e legarsi a proprietà Value invece di ""

Inoltre, non è necessario notificare un cambiamento nella raccolta osservabile, quindi finché il modello non ha altre proprietà proprie, non è necessario disporre di INotifyPropertyChange. Se vuoi che ItemsControl reagisca alle modifiche nei singoli StringObjects, devi aggiungere INotifyPropertyChanged a StringObject.

E ancora una volta, il legame a doppio senso è di default, quindi è necessario solo

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

nel vostro legame.

+0

funziona per me! Grazie mille!! – Johnathan1

+1

Non penso che sia necessario inserire "Path =" nella proprietà Text, "Text =" {Binding Value} "' funzionerebbe anche – user1069816

+0

Perché funziona a stringa singola ma non nell'elenco ? – YukiSakura

1

Credo che sia necessario ricavare gli elementi della raccolta da DependencyObject per il binding TwoWay. Qualcosa di simile:

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

Non credo che in questo caso sia richiesta una DependencyProperty. Questo è necessario solo se vuoi legare quella proprietà a qualcos'altro. – Andy

+0

Basandomi su entrambe le idee ora, sono riuscito a trovare una soluzione per la mia applicazione. Grazie per il tuo post!! – Johnathan1

+0

Questo mi ha aiutato molto, grazie. La parte che mi mancava era impostare Mode = TwoWay in modo da poter accedere ai dati aggiornati da listbox.itemsource dopo che l'utente aveva apportato le modifiche. – javram