8

当集合的属性发生更改时,我在更新包含 ObservableCollection 的列表框时遇到问题(从列表中添加/删除项目工作正常):

列表框已设置ItemsSource="{Binding Path=AllPerson}",后面代码中的数据上下文设置如下this.DataContext = allPersonClass;

allPersonClass包含ObservableCollection<Person> allPerson

Person包含名称等属性。

我已经覆盖了人员ToString返回Name属性的方法,因此 listBox 显示有效数据

我试图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");
     }
}

并在每个属性设置器中onPropertyChanged(this, "propertyName");执行但 listBox 从不更新已创建的项目

知道可能出了什么问题吗?

这是带有 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"/>

这是进行修改的 DetailView 窗口的一部分(绑定到 Person)

<TextBox Text="{Binding Path=Name}" Height="23" HorizontalAlignment="Left" Margin="118,20,0,0" Name="txtName" VerticalAlignment="Top" Width="141" />

这是 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];
  }
}

编辑

这是在详细视图中保存更改的方法的相关部分

private void OnBtnSaveClick(object sender, RoutedEventArgs e) {
     person.Name = txtName.Text;
     person.SurName = txtSurName.Text;
}

请注意,在“ObservableCollection allPerson”中进行了更改,只有 listBox 一直显示旧数据

4

4 回答 4

11

如果您希望在更改 Person 属性时更新 UI,您必须通知该属性已更改,而不是类

public string Name 
{
     get { return name; }
     set 
     {
        name = value;
        onPropertyChanged(this, "allPersonClass");
     }
}

<TextBox Text="{Binding Path=Name}" .....

应该

public string Name 
{
     get { return name; }
     set 
     {
        name = value;
        onPropertyChanged(this, "Name");
     }
}

<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" .....

而且您不必覆盖模型以在您的 中正确显示ToString(),您可以设置以在PersonListBoxListBox DisplayMemberPathListBox

  <ListBox ItemsSource="{Binding Path=AllPerson}" DisplayMemberPath="Name" />

编辑:回答您的评论问题:

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; }
}
于 2013-03-13T22:07:00.323 回答
5

在您的 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" />

此外,如果您想在每次写入文本时更新属性,您还需要定义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" />
于 2013-03-13T21:55:06.077 回答
4

您的问题是您的收藏永远不会收到有关您的 PropertyChanged 的​​通知

这应该可以帮助你

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();
    }

另请参阅此链接

于 2013-03-14T09:01:41.403 回答
3

我想你可能想回顾一下你是如何在项目级别进行绑定的。查看此链接,它将帮助您入门:

如何确定 ObservableCollection<T> 中的一行是否实际更改

于 2013-03-13T21:40:31.880 回答