Pergunta

There have been similar questions like this on this site but I have not found an answer that really works, so I post it again.

public MyClass
{

   public person Person1 {get; set;}

   public person Person2 {get; set;}

  CalculatedProperty 
   { 
     get
     { return Person1.Salary + (Person2.Salary/2) ; }
   }

}

public class Person
{
  public double Salary
    { get; set;}
}

I want to be able to notify changes in CalculatedProperty whenever Person1.Salary and/or Person2.Salary changes.

I have tried adding OnPropertyChanged("CalculatedProperty") on the setters of Person1 and Person2 but it does not work (and I understand why), but can't find a way to notify changes. Please help =)

(Is there a way to use an ObjectDataProvider for this?... Been trying that too...)

Foi útil?

Solução

You need Person to implement INotifyPropertyChanged too, then register to the two properties you have. Once PropertyChanged is invoked with Salary on either of them, invoke PropertyChanged on CalculatedProperty

void PersonPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "Salary")
        OnPropertyChanged("CalculatedProperty");
}

Just remember to unregister when person is changed.

UPDATE:

As Jim said, your setter should look something like this:

private Person _person;
public Person Person
{
    get { return _person; }
    set
    {
        if (Equals(value, _person)) return;

        if (_person != null)
            _person.PropertyChanged -= PersonPropertyChanged;

        _person = value;

        if(_person != null)
            _person.PropertyChanged += PersonPropertyChanged;

        OnPropertyChanged("Person");
    }
}

Outras dicas

Give CLII the check but this is a complete example

using System.ComponentModel;

namespace NotifyBubble
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // This method is called by the Set accessor of each property. 
        // The CallerMemberName attribute that is applied to the optional propertyName 
        // parameter causes the property name of the caller to be substituted as an argument. 
        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            Person = new Person();
            Person.Salary = 100;
        }
        void PersonPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Salary")
                NotifyPropertyChanged("CalculatedProperty");
        }
        public Double CalculatedProperty
        {
            get
            {
                return Person.Salary / 2;
            }
        }
        private Person _person;
        public Person Person
        {
            get { return _person; }
            set
            {
                if (Equals(value, _person)) return;

                if (_person != null)
                    _person.PropertyChanged -= PersonPropertyChanged;

                _person = value;

                if (_person != null)
                    _person.PropertyChanged += PersonPropertyChanged;
                NotifyPropertyChanged("Person");
            }
        }
    }
    public class Person: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // This method is called by the Set accessor of each property. 
        // The CallerMemberName attribute that is applied to the optional propertyName 
        // parameter causes the property name of the caller to be substituted as an argument. 
        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        private double salary = 0;
        public double Salary
        { 
            get { return salary; }
            set
            {
                if (salary == value) return;
                salary = value;
                NotifyPropertyChanged("Salary");
            }
        }
    }
}

Just for the record, this is how I implemented the same problem but in a collection (using a different example)

public class Fields : ObservableCollection<Field>
{
    protected override event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    void FieldPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "IsSelected")
        {
            NotifyPropertyChanged("SelectedItemsCount"); 
        }
    }

    protected override void InsertItem(int index, Field item)
    {
    if (item != null)
            item.PropertyChanged -= FieldPropertyChanged;

        base.InsertItem(index, item);

        if (item != null)
            item.PropertyChanged += FieldPropertyChanged;
    }

    protected override void ClearItems()
    {
        foreach (Field field in this)
        {
            field.PropertyChanged -= FieldPropertyChanged;
        }
        base.ClearItems();
    }

    protected override void RemoveItem(int index)
    {
        if (this[index] != null)
            this[index].PropertyChanged -= FieldPropertyChanged;

        base.RemoveItem(index);
    }

    private int selectedItemsCount;

    public int SelectedItemsCount
    {
        //This can be more efficient, not have to count everytime
        get
        {
            selectedItemsCount = 0;

            foreach (Field field in this)
            {
                if (field.IsSelected)
                    selectedItemsCount++;
            }

            return selectedItemsCount;
        }
    }


}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top