通过修改文本框中的文本来更新可观察集合的字符串元素



问题从链接继承了问题 如何将 ItemTemplate 的文本框文本正确绑定到 List 的字符串元素?

当代码如下时,预期效果显示在应用程序初始化开始时:

<ItemsControl ItemsSource="{Binding PathsCollection,  UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding ., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public class SomeClass
{
private List<string> _paths;
public List<string> Paths
{
get {return _paths;}
set {_paths = value; }
}
public ObservableCollection<string> PathsCollection
{
get 
{ 
return new ObservableCollection<string>(Paths);
}
set 
{
Paths = value.ToList();
}
}
}

但是,它仅在应用程序的第一次初始化时起作用。当我在TextBox中添加、删除或修改某些文本时,它无法更改_paths的任何字符串元素。此外,当我执行操作时,它没有修改 ObservableCollectionPathsCollection的任何元素。为什么?


更新 1

<ItemsControl ItemsSource="{Binding PathsCollection,  UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding ., Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public class SomeClass : INotifyPropertyChanged
{
private List<string> _paths;
public List<string> Paths
{
get {return _paths;}
set {_paths = value; InformPropertyChanged("Paths");}
}
public ObservableCollection<string> PathsCollection
{
get 
{ 
return new ObservableCollection<string>(Paths);
}
set 
{
Paths = value.ToList();
InformPropertyChanged("PathsCollection");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void InformPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}

两个问题:

  1. 这是行不通的,因为对象正在您未保留引用的实例内更新。从下面的get返回的实例是绑定到 UI 但未在代码中跟踪的实例:

    get 
    { 
    return new ObservableCollection<string>(Paths);
    }
    

从此get返回的实例在启动期间被绑定。所有更新都发生在该绑定实例中。由于您没有在SomeClass中保留此实例的引用,因此您看不到所做的任何更改。

  1. 其次,这是这里的主要原因:您有绑定到 TextBox 的字符串集合。.Net 中的字符串是不可变的(即一旦创建就无法更改)。更改文本框中的数据时,将创建一个字符串的新实例;但仅在 UI 上,而不是在集合中。这就是您看不到要传播的新实例的原因。通常,这种传播是通过 INotifyPropertyChanged 接口进行的,该接口监视更改并更新属性。原始字符串集合没有要更新的属性,因此会丢失。

要解决此问题,

  1. 您必须将 ObservableCollection 连接回您的列表 反映更改。您还需要保留 类中的可观察集合。

  2. 创建将保留字符串数据的容器/持有者类。这 将确保数据通过属性更改事件传播。

编辑版本:

//This is place holder class to hold state of your string data
public class SomeContainer
{
public string Path { get; set; }
}

public class SomeClass
{
private List<string> _paths;
public List<string> Paths
{
//This will ensure you return the current list of bound of items.
get { return PathsCollection.Select(s => s.Path).ToList(); }
set { _paths = value; }
}
private string test;
public string Test
{
get
{
return test;
}
set
{
test = value;
}
}
private ObservableCollection<SomeContainer> pathsCollection;        
public ObservableCollection<SomeContainer> PathsCollection
{
get
{
return pathsCollection;
}
set
{
pathsCollection = value;
}
}
//Constructor
public SomeClass()
{
_paths = new List<string>()
{
"testing 1", "testing 2"
};
var container = _paths.Select(s => new SomeContainer() { Path = s });
//Initialize
PathsCollection = new ObservableCollection<SomeContainer>(container);
}
}

Xaml 绑定

<ItemsControl ItemsSource="{Binding Path=PathsCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Path}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

最新更新