如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?

Posted

技术标签:

【中文标题】如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?【英文标题】:How can I bind an ObservableCollection to TextBoxes in a 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?");
    

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

【问题讨论】:

【参考方案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

【讨论】:

以上是关于如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 WPF DataGrid 绑定到 ObservableCollection

如何将 ObservableCollection 与 datagrid WPF 绑定

将 ObservableCollection 保存到文件 (.txt)

C#如何将实体框架实体与ObservableCollection一起使用

如何使 ObservableCollection 线程安全?

如何通过工作线程更新 ObservableCollection?