I have an ObservableCollection
with Students
. Each Student has a Grade Property. I want the AverageGrade
property (of all students) to work without having to press a button or creating a timer.
How do I use a DependencyProperty
here for this read-only AverageGrade
Property?
using System.ComponentModel;
using System.Windows;
using System;
namespace WpfApplication17.Models
{
class Student : INotifyPropertyChanged
{
#region Constructors
public Student(string firstName, string lastName, double grade)
{
this.FirstName = firstName;
this.LastName = lastName;
this.Grade = grade;
}
#endregion
#region Properties
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged("LastName");
}
}
private double _grade;
public double Grade
{
get { return _grade; }
set
{
_grade = value;
OnPropertyChanged("Grade");
}
}
#endregion
#region PropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
using WpfApplication17.ViewModel;
using System.Collections.ObjectModel;
using WpfApplication17.Models;
namespace WpfApplication17.ViewModels
{
class MainWindowViewModel : ViewModelBase
{
#region Constructors
public MainWindowViewModel()
{
Students = new ObservableCollection<Student>();
Students.Add(new Student("Frank", "Sinatra", 7));
Students.Add(new Student("Bart", "Simpson", 6));
}
#endregion
#region Properties
private ObservableCollection<Student> _students;
public ObservableCollection<Student> Students
{
get { return _students; }
set
{
_students = value;
OnPropertyChanged("Students");
}
}
public double AverageGrade
{
get { return GetAverageGrade(); }
}
public double GetAverageGrade()
{
double sum = 0;
foreach (Student s in Students)
sum += s.Grade;
return sum / (double)Students.Count;
}
#endregion
}
}
<Window x:Class="WpfApplication17.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Horizontal">
<DataGrid ItemsSource="{Binding Students}" />
<Label Content="Average Grade:" />
<Label Content="{Binding AverageGrade}" />
</StackPanel>
</Window>
Why you want DP for that it seem like normal VM property take care of this. What you need is whenever new student is added or existing student's grade is changed, AverageGrade must be updated.
Maybe try this approach:
class MainWindowViewModel
{
#region Constructors
public MainWindowViewModel()
{
Students = new ObservableCollection<Student>();
Students.Add(new Student("Frank", "Sinatra", 7));
Students.Add(new Student("Bart", "Simpson", 6));
Students.CollectionChanged += (s, e) => AverageGrade = this.GetAverageGrade();
foreach (var student in Students)
{
student.PropertyChanged += OnStudentPropertyChanged;
}
AverageGrade = this.GetAverageGrade();
}
private void OnStudentPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Grade")
{
AverageGrade = this.GetAverageGrade();
}
}
#endregion
#region Properties
private ObservableCollection<Student> _students;
public ObservableCollection<Student> Students
{
get { return _students; }
set
{
_students = value;
OnPropertyChanged("Students");
}
}
private double average;
public double AverageGrade
{
get
{
return this.average;
}
set
{
this.average = value;
OnPropertyChanged("AverageGrade");
}
}
public double GetAverageGrade()
{
return this.Students.Sum(s => s.Grade) / Students.Count;
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}