我遇到了一个我知道必须非常普遍的情况,所以我希望解决方案很简单。我有一个包含List<>的对象对象它还有一些属性反映了List<>中对象的聚合数据。 (实际上是BindingList<>所以我可以绑定它)。在我的表单上,我有一个List的DataGridView,以及聚合数据的一些其他字段。当DataGridView中的值发生变化时,我无法弄清楚如何触发聚合数据的刷新。
我已尝试在更改List中对象的属性时引发PropertyChanged事件,但这似乎不会刷新聚合数据的显示。如果我访问聚合属性(例如,在消息框中显示),则刷新主窗体上的文本框。
这里有一些简化的代码来说明我正在尝试做的事情:
namespace WindowsFormsApplication1 {
public class Person {
public int Age {
get;
set;
}
public String Name {
get;
set;
}
}
public class Roster : INotifyPropertyChanged {
public BindingList<Person> People {
get;
set;
}
public Roster () {
People = new BindingList<Person>();
}
private int totalage;
public int TotalAge {
get {
calcAges();
return totalage;
}
set {
totalage = value;
NotifyPropertyChanged("TotalAge");
}
}
private void calcAges () {
int total = 0;
foreach ( Person p in People ) {
total += p.Age;
}
TotalAge = total;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged ( String info ) {
if ( PropertyChanged != null ) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
答案 0 :(得分:3)
calcAges
方法和TotalAge
属性看起来非常可疑。
首先,TotalAge
应该是只读的。如果允许它是公共的和可写的,那么改变构成年龄的组件的逻辑是什么?
其次,每次获得该值时,您都会触发PropertyChanged
事件,这是不好的。
您的Roster
课程应如下所示:
public class Roster : INotifyPropertyChanged {
public Roster ()
{
// Set the binding list, this triggers the appropriate
// event binding which would be gotten if the BindingList
// was set on assignment.
People = new BindingList<Person>();
}
// The list of people.
BindingList<Person> people = null;
public BindingList<Person> People
{
get
{
return people;
}
set
{
// If there is a list, then remove the delegate.
if (people != null)
{
// Remove the delegate.
people.ListChanged -= OnListChanged;
}
/* Perform error check here */
people = value;
// Bind to the ListChangedEvent.
// Use lambda syntax if LINQ is available.
people.ListChanged += OnListChanged;
// Technically, the People property changed, so that
// property changed event should be fired.
NotifyPropertyChanged("People");
// Calculate the total age now, since the
// whole list was reassigned.
CalculateTotalAge();
}
}
private void OnListChanged(object sender, ListChangedEventArgs e)
{
// Just calculate the total age.
CalculateTotalAge();
}
private void CalculateTotalAge()
{
// Store the old total age.
int oldTotalAge = totalage;
// If you can use LINQ, change this to:
// totalage = people.Sum(p => p.Age);
// Set the total age to 0.
totalage = 0;
// Sum.
foreach (Person p in People) {
totalage += p.Age;
}
// If the total age has changed, then fire the event.
if (totalage != oldTotalAge)
{
// Fire the property notify changed event.
NotifyPropertyChanged("TotalAge");
}
}
private int totalage = 0;
public int TotalAge
{
get
{
return totalage;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged ( String info ) {
if ( PropertyChanged != null ) {
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
现在,当列表项中的属性发生更改时,父对象将触发属性更改事件,并且绑定到它的任何内容也应该更改。
答案 1 :(得分:-1)