2009-06-30 3 views
9

J'essaye de réussir TwoWay lier un ObservableCollection à TextBoxes dans un DataTemplate. Je peux obtenir les données à afficher correctement, mais je suis incapable de modifier les données de la liste via l'interface utilisateur. J'ai une classe Model nommée 'model' qui contient un ObservableCollection nommé 'List'. La classe implémente l'interface INotifyPropertyChanged. Voici le xaml pour le shell. Le DataContext pour la grille de Window1 est réglé sur "theGrid.DataContext = modèle"Comment lier un ObservableCollection aux TextBoxes dans 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> 

C'est le code pour la classe du modèle:

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

Quelqu'un pourrait-il conseiller si je vais au sujet c'est la bonne façon?

Répondre

12

Vous avez besoin d'une propriété à lier dans les deux sens, donc la chaîne n'est pas bonne pour cela.

envelopper dans un objet chaîne, comme ceci:

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

et se lier à la propriété de la valeur au lieu de « » De même, vous n'avez pas besoin d'avertir d'un changement dans la collection observable, donc jusqu'à ce que votre modèle ait ses propres propriétés, il n'a pas besoin d'avoir INotifyPropertyChange. Si vous voulez que votre ItemsControl réagisse aux changements dans les StringObjects individuels, vous devez ajouter INotifyPropertyChanged à un objet StringObject.

Et encore une fois, deux voies de liaison est par défaut, vous avez donc besoin que

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

dans votre liaison.

+0

Works pour moi! Merci beaucoup!! – Johnathan1

+1

Je ne pense pas que vous devez mettre "Path =" dans la propriété Text, 'Text =" {Binding Value} "' fonctionnerait aussi – user1069816

+0

Pourquoi la propriété de chaîne unique fonctionne mais pas Liste ? – YukiSakura

1

Je crois que vous devez dériver vos éléments de collection de DependencyObject pour que la liaison TwoWay fonctionne. Quelque chose comme:

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

Je ne pense pas qu'un DependencyProperty soit requis dans ce cas. C'est seulement nécessaire si vous voulez lier cette propriété à autre chose. – Andy

+0

Basé sur les deux idées maintenant, j'ai été en mesure de trouver une solution pour mon application. Merci pour votre commentaire!! – Johnathan1

+0

Cela m'a beaucoup aidé, merci. La partie qui me manquait était de définir le mode = TwoWay afin que je puisse accéder aux données mises à jour à partir du listbox.itemsSource après que l'utilisateur ait fait leurs changements. – javram

Questions connexes