如何将ObservableCollection绑定到DataTemplate中的TextBoxes?

时间:2009-06-30 06:34:36

标签: wpf binding datatemplate two-way-binding

我试图成功地将一个ObservableCollection绑定到DataTemplate中的TextBoxes。我可以正确显示数据,但我无法通过UI更改列表数据。我有一个名为'model'的Model类,它包含一个名为'List'的ObservableCollection。该类实现了INotifyPropertyChanged接口。这是shell的xaml。 Window1网格的DataContext设置为“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?");
    }
}

有人可以告诉我这是否正确吗?

3 个答案:

答案 0 :(得分:12)

你需要一个属性绑定两个方式,所以字符串不适合这个。

将其包装在字符串对象中,如下所示:

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对单个StringObjects中的更改做出反应,则应将INotifyPropertyChanged添加到StringObject。

然而,双向绑定是默认的,所以你只需要

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

在您的装订中。

答案 1 :(得分:1)

我相信您需要从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>

答案 2 :(得分:0)

xaml视图:

<ItemsControl ItemsSource="{Binding List}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

在构造函数后面的代码中:

DataContext = new ViewModel();

在ViewModel类中:

class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

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

        public ViewModel()
        {
            List = new ObservableCollection<StringObject>
                {
                    new StringObject {Value = "why"},
                    new StringObject {Value = "not"},
                    new StringObject {Value = "these"}
                };
        }
    }

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

请注意类型为string的集合不起作用,您必须使用一个对象=> StringObject