Как я могу привязать ObservableCollection к TextBoxes в DataTemplate? - PullRequest
9 голосов
/ 30 июня 2009

Я пытаюсь успешно TwoWay связать ObservableCollection с TextBoxes в DataTemplate. Я могу заставить данные отображаться правильно, но я не могу изменить данные списка через пользовательский интерфейс. У меня есть класс Model с именем 'model', который содержит ObservableCollection с именем 'List'. Класс реализует интерфейс INotifyPropertyChanged. Вот xaml для оболочки. DataContext для сетки Window1 имеет значение "theGrid.DataContext = model"

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

Это код для класса Model:

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

Может ли кто-нибудь посоветовать, правильно ли я поступлю?

Ответы [ 2 ]

12 голосов
/ 30 июня 2009

Вам нужно свойство для двухстороннего связывания, поэтому строка не подходит для этого.

Оберните его в строковый объект, например:

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

и привязка к свойству Value вместо "."

Кроме того, вам не нужно уведомлять об изменении в наблюдаемой коллекции, поэтому до тех пор, пока у вашей модели не появятся другие собственные свойства, ей не нужно иметь INotifyPropertyChange. Если вы хотите, чтобы ваш ItemsControl реагировал на изменения в отдельных объектах StringObject, вам следует добавить INotifyPropertyChanged в объект StringObject.

И снова, двустороннее связывание по умолчанию, поэтому вам нужно только

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

в вашем переплете.

1 голос
/ 30 июня 2009

Полагаю, вам нужно извлечь элементы коллекции из DependencyObject для привязки TwoWay к работе. Что-то вроде:

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>
...