Search code examples
c#wpfwpfdatagriddependency-properties

Can I use a DependencyProperty for this?


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?

Student.cs

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
}

}

MainWindowViewModel

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
    }
}

MainWindow.xaml

<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>

Solution

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