wpf 属性更改时列表框项目未更新
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15396786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ListBox item not updated when property changed
提问by Abdul
I have problem updating Listbox containing ObservableCollection when property of collection changes (adding/removing items from list works fine):
当集合的属性更改时,我在更新包含 ObservableCollection 的列表框时遇到问题(从列表中添加/删除项目工作正常):
listbox has set ItemsSource="{Binding Path=AllPerson}"and data context in code behind is set like this this.DataContext = allPersonClass;.
列表框已经设置ItemsSource="{Binding Path=AllPerson}",后面的代码中的数据上下文是这样设置的this.DataContext = allPersonClass;。
allPersonClasscontains ObservableCollection<Person> allPerson
allPersonClass包含 ObservableCollection<Person> allPerson
Class Personcontains properties like Name etc.
类Person包含名称等属性。
I've overwritten person's ToStringmethod to return Nameproperty so listBox shows valid data
我已经覆盖了 person 的ToString返回Name属性的方法,因此 listBox 显示了有效数据
I've tried to make Personimplement INotifyPropertyChanged
我试过Person实现INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(object sender, string propertyName) {
if (this.PropertyChanged != null) {
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}
public string Name {
get { return name; }
set {
name = value;
onPropertyChanged(this, "allPersonClass");
}
}
and in every property setter has onPropertyChanged(this, "propertyName");which is executed but listBox never updates already created item
并且在每个属性 setter 中都有onPropertyChanged(this, "propertyName");which 被执行但 listBox 永远不会更新已经创建的项目
Any idea what might be wrong?
知道可能有什么问题吗?
here is window with listBox xaml
这是带有 listBox xaml 的窗口
<Button x:Name="btnDetail" Content="Detail" HorizontalAlignment="Left" Margin="361,249,0,0" VerticalAlignment="Top" Width="75" Click="ButtonDetailClick"/>
<ListBox x:Name="listPerson" ItemsSource="{Binding Path=AllPerson}" HorizontalAlignment="Left" Height="170" Margin="33,29,0,0" VerticalAlignment="Top" Width="155" IsSynchronizedWithCurrentItem="True"/>
<Button x:Name="btnLoad" Content="Load" HorizontalAlignment="Left" Margin="58,249,0,0" VerticalAlignment="Top" Width="75" Click="btnLoad_Click"/>
<Button x:Name="btnSave" Content="Save" HorizontalAlignment="Left" Margin="138,249,0,0" VerticalAlignment="Top" Width="75" Click="ButtonSaveClick"/>
this is part of DetailView window where modifications are made (binded to Person)
这是进行修改的 DetailView 窗口的一部分(绑定到 Person)
<TextBox Text="{Binding Path=Name}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />
here is part AllPersonClass:
这是 AllPersonClass 的一部分:
public class AllPersonClass {
private ObservableCollection<Person> allPerson;
public AllPersonClass() {
allPerson = new ObservableCollection<Person>();
}
public ObservableCollection<Person> AllPerson {
get { return allPerson; }
set { allPerson = value; }
}
public void addPerson(Person newPerson) {
allPerson.Add(newPerson);
}
public Person getPerson(int personIndex) {
return allPerson[personIndex];
}
}
EDIT
编辑
here is relevant part of method to save changes in detail view
这是在详细视图中保存更改的方法的相关部分
private void OnBtnSaveClick(object sender, RoutedEventArgs e) {
person.Name = txtName.Text;
person.SurName = txtSurName.Text;
}
note that changes are made in ′ObservableCollection allPerson′ only listBox keeps showing old data
请注意,在“ObservableCollection allPerson”中进行了更改,仅列表框会继续显示旧数据
回答by sa_ddam213
If you want the UI to update when you make changes to Person properties you have to notifiy that that property has changed, not the class
如果您希望在更改 Person 属性时更新 UI,则必须通知该属性已更改,而不是类
public string Name
{
get { return name; }
set
{
name = value;
onPropertyChanged(this, "allPersonClass");
}
}
<TextBox Text="{Binding Path=Name}" .....
Should be
应该
public string Name
{
get { return name; }
set
{
name = value;
onPropertyChanged(this, "Name");
}
}
<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" .....
And you dont have to override ToString()on the Personmodel to show correctly in your ListBox, you can set the ListBoxDisplayMemberPathto show the property you want in the ListBox
而你没有覆盖ToString()的Person模型正确地在你展示ListBox,你可以设置ListBoxDisplayMemberPath显示你的希望属性ListBox
<ListBox ItemsSource="{Binding Path=AllPerson}" DisplayMemberPath="Name" />
Edit: to answer your comment question:
编辑:回答您的评论问题:
public string Name
{
get { return name; }
set
{
name = value;
onPropertyChanged(this, "Name");
onPropertyChanged(this, "Display");
}
}
public string Surname
{
get { return surname; }
set
{
surname= value;
onPropertyChanged(this, "Surname");
onPropertyChanged(this, "Display");
}
}
public string Display
{
get { return Name + " " + Surname; }
}
回答by Jehof
In your DetailView you need to define a TwoWay-Binding to update the Property Name of your personclass.
在您的 DetailView 中,您需要定义一个 TwoWay-Binding 来更新您的person类的属性名称。
<TextBox Text="{Binding Path=Name, Mode=TwoWay}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />
Also if you want to update the property every time text is written you also need to define the UpdateSourceTriggerwith PropertyChanged. Otherwise is the property only update when the TextBox loses focus.
此外,如果您想在每次写入文本时更新该属性,您还需要定义UpdateSourceTriggerwith PropertyChanged。否则,该属性仅在 TextBox 失去焦点时更新。
<TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />
回答by WiiMaxx
your problem is that your collection get never Notifed about your PropertyChanged
您的问题是您的收藏从未收到关于您的 PropertyChanged 的通知
this should help you
这应该可以帮助你
ObservableCollection<INotifyPropertyChanged> items = new ObservableCollection<INotifyPropertyChanged>();
items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(items_CollectionChanged);
static void items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (INotifyPropertyChanged item in e.OldItems)
item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
foreach (INotifyPropertyChanged item in e.NewItems)
item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
}
static void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
see also this Link
另见此链接
回答by code4life
I think you might want to review how you're doing the binding at the item level. Check out this link, it will get you started:
我想您可能想回顾一下您是如何在项目级别进行绑定的。看看这个链接,它会让你开始:
How to determine if a row in ObservableCollection<T> actually changed

