【问题标题】:How can I bind an ObservableCollection to TextBoxes in a DataTemplate?如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?
【发布时间】:2010-11-06 22:00:37
【问题描述】:

我正在尝试成功将一个 ObservableCollection 绑定到 DataTemplate 中的 TextBoxes。我可以让数据正确显示,但我无法通过 UI 更改列表数据。我有一个名为“模型”的模型类,其中包含一个名为“列表”的 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>

这是模型类的代码:

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

任何人都可以建议我是否以正确的方式解决这个问题?

【问题讨论】:

    标签: wpf binding datatemplate two-way-binding


    【解决方案1】:

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

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

    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 属性而不是“。”

    另外,你不需要通知 observable 集合的变化,所以在你的模型有它自己的一些其他属性之前,它不需要有 INotifyPropertyChange。如果您希望您的 ItemsControl 对单个 StringObjects 中的更改做出反应,那么您应该将 INotifyPropertyChanged 添加到 StringObject。

    再一次,双向绑定是默认的,所以你只需要

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

    在您的绑定中。

    【讨论】:

    • 为我工作!非常感谢!!
    • 我认为你不需要在 Text 属性中添加 "Path=",Text="{Binding Value}" 也可以
    • 为什么单个字符串属性有效但 List 无效?
    【解决方案2】:

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

    【讨论】:

    • 我认为在这种情况下不需要 DependencyProperty。仅当您想将该属性绑定到其他东西时才需要这样做。
    • 现在基于这两个想法,我能够为我的应用程序提出一个解决方案。谢谢你的帖子!!
    • 这对我帮助很大,谢谢。我缺少的部分是设置 Mode=TwoWay 以便在用户进行更改后我可以从 listbox.itemsSource 访问更新的数据。
    【解决方案3】:

    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

    【讨论】:

      猜你喜欢
      • 2011-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-20
      • 2017-05-31
      • 2020-10-06
      • 1970-01-01
      相关资源
      最近更新 更多