Почему .NET считывает значения незатронутых свойств при получении события INotifyPropertyChanged.PropertyChanged?

Я новичок в привязке данных и сегодня столкнулся со следующей странностью, которую не могу понять:

У меня есть форма с двумя метками (labelA и labelB) и двумя кнопками (buttonA и buttonB).

Форма содержит объект (называемый «formState») с двумя свойствами (CountA и CountB). labelA.Text связан данными с formState.CountA, labelB.Text связан данными с formState.CountB.

Когда нажата кнопка A, formState вызывает событие PropertyChange с «CountA» в качестве имени свойства. Когда кнопка B нажата, она вызывает formState.PropertyChange с "CountB" в качестве имени свойства.

Я ожидаю, что только метка A обновляется при нажатии кнопки A, и только метка B обновляется при нажатии кнопки B. Однако обе метки обновляются, когда я нажимаю любую кнопку. Я вижу это, потому что свойства CountA и CountB увеличиваются и возвращают счетчик каждый раз, когда считываются их значения. Код ниже.

У кого-нибудь есть объяснение такому поведению?

public partial class Form1 : Form
{
    private FormState formState = new FormState();

    public Form1()
    {
        InitializeComponent();

        labelA.DataBindings.Add(
            new Binding("Text", formState, "CountA"));

        labelB.DataBindings.Add(
            new Binding("Text", formState, "CountB"));
    }

    private void buttonA_Click(object sender, EventArgs e)
    {
        formState.raisePropertyChangedEvent("CountA");
        // both labelA and labelB get updated - why not just labelA?
    }

    private void buttonB_Click(object sender, EventArgs e)
    {
        formState.raisePropertyChangedEvent("CountB");
        // both labelA and labelB get updated - why not just labelB?
    }

    public class FormState : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private int countA = 0;
        private int countB = 0;

        public int CountA
        {
            get { return ++countA; }
        }

        public int CountB
        {
            get { return ++countB; }
        }

        public void raisePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

person Johannes Petzold    schedule 13.11.2009    source источник


Ответы (2)


Это может быть наивный потребитель наблюдаемых объектов. Наивные потребители INotifyPropertyChangedObjects могут игнорировать имя свойства и просто переоценивать все это. Можно представить, что класс выглядит так:

class NaiveConsumer
{
   void Foo(INotifyPropertyChanged observable)
   {
       observable.PropertyChanged += PropertyChangedHandler;
   }

   void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
   {
      // Evaluate all properties, even though only 1 prop changed.
      this.NameTextBox.Text = observable.Name;
      this.AgeTextBox.Text = observable.Age;
   }
}
person Judah Gabriel Himango    schedule 13.11.2009
comment
Похоже, это не совсем так - я протестировал создание события PropertyChanged с недопустимым именем свойства, и ни одна из моих меток не была обновлена. Однако я также протестировал повышение его с помощью «null» в качестве имени свойства, что снова обновило обе метки. В любом случае, если нет проблем с моим кодом, все это означает, что элементы управления .NET с привязкой к данным не реагируют на события PropertyChanged, как я ожидал: в случае сложного пользовательского интерфейса с привязкой к данным каждое изменение данных приведет к обновлению всего пользовательского интерфейса. Звучит довольно неэффективно. - person Johannes Petzold; 13.11.2009

Ответственность вашего класса состоит в том, чтобы предоставить уведомление об изменении, а потребитель должен решить, как с этим справиться. Если он решит проверить каждое свойство любого измененного свойства, он может это сделать.

person vanja.    schedule 13.11.2009