Подтвердить что ты не робот

Обработка OnPropertyChanged

Я не хорошо разбираюсь в программировании на основе событий. В принципе, я все еще спотыкаюсь с этим. Я пытаюсь получить что-то настроенное, но даже с учебниками я не могу обернуть вокруг себя. То, что я хотел бы сделать (на словах), следующее:

  • У меня есть объект данных, где свойство изменяется. Я замечаю это в настройщике свойства и хочу поднять событие, которое изменило свойство.

  • В другом месте (в другом классе полностью), я хочу знать, что свойство на этом объекте изменилось и предпринять некоторые действия.

Теперь я уверен, что это довольно распространенный сценарий, но мой google-fu подводит меня. Я просто не понимаю http://msdn.microsoft.com/en-us/library/ms743695.aspx.

У меня есть это:

public class ChattyClass {
  private int someMember;

  public event PropertyChangedEventHandler PropertyChanged;

  public int SomeMember {
    get {
      return this.someMember;
    }
    set {
      if (this.someMember != value){
        someMember = value;
        // Raise event/fire handlers. But how?
      }
   }
}

public class NosyClass{
  private List<ChattyClass> myChatters;

  public void addChatter(ChattyClass chatter){
    myChatters.add(chatter);
    // Start listening to property changed events
  }

  private void listner(){
    // I want this to be called when the PropertyChangedEvent is called
    Console.WriteLine("Hey! Hey! Listen! A property of a chatter in my list has changed!");
  }
}

Что мне делать, чтобы связать это?

Относительно комментария, указывающего на ссылку:

В примере я вижу:

protected void OnPropertyChanged(string name)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}

Что я не понимаю:

  • Почему это не просто вызов PropertyChanged(this, new PropertyCHangedEventArgs(name))
  • Где назначается PropertyChanged?
  • Как выглядит присваивание?
4b9b3361

Ответ 1

Вам нужно запустить событие. В примере в MSDN они сделали защищенный метод OnPropertyChanged более удобным (и чтобы избежать дублирования кода).

// Create the OnPropertyChanged method to raise the event 
protected void OnPropertyChanged(string name)
{
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(name));
    }
}

Что делает этот метод, посмотрите, есть ли назначенный обработчик события или нет (если он не назначен, и вы просто назовете его, вы получите NullReferenceException). Если есть назначенный, вызовите этот обработчик событий. Предоставляемый обработчик событий должен иметь подпись делегата PropertyChangedEventHandler. Эта подпись:

void MyMethod(object sender, PropertyChangedEventArgs e)

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

Теперь, чтобы реагировать на срабатывание события, вам нужно назначить обработчик события для класса. В этом случае вам придется назначить это в свой метод addChatter. Кроме того, вы должны сначала определить своего обработчика. В вашем NosyClass вам нужно будет добавить метод для этого, например:

private void chatter_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    Console.WriteLine("A property has changed: " + e.PropertyName);
}

Как вы можете видеть, этот метод соответствует сигнатуре, которую я объяснил ранее. Во втором параметре вы сможете найти информацию о том, какой параметр был изменен. Последнее, что нужно сделать, - добавить обработчик событий. Теперь в вашем методе addChatter вам придется назначить это:

public void AddChatter(ChattyClass chatter)
{
    myChatters.Add(chatter);
    // Assign the event handler
    chatter.PropertyChanged += new PropertyChangedEventHandler(chatter_PropertyChanged);
}

Я бы предложил вам прочитать что-то о событиях в .NET/С#: http://msdn.microsoft.com/en-us/library/awbftdfh. Я думаю, что после прочтения/изучения этого вещи вам станет понятнее.

Вы можете найти консольное приложение здесь на pastebin, если вы хотите быстро его протестировать (просто скопируйте/вставьте в новое консольное приложение).

Ответ 2

Ссылка, которую вы искали, предназначена для MVVM и WPF. Это не общая реализация С#. Вам нужно что-то вроде этого:

public event EventHandler PropertyChanged;

    public int SomeMember {
        get {
            return this.someMember;
        }
        set {
            if (this.someMember != value) {
                someMember = value;
                if (PropertyChanged != null) { // If someone subscribed to the event
                    PropertyChanged(this, EventArgs.Empty); // Raise the event
                }
            }
        }

...

public void addChatter(ChattyClass chatter) {
    myChatters.add(chatter);
    chatter.PropertyChanged += listner; // Subscribe to the event
}
// This will be called on property changed
private void listner(object sender, EventArgs e){
    Console.WriteLine("Hey! Hey! Listen! A property of a chatter in my list has changed!");
}

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

public event PropertyChangedEventHandler PropertyChanged;

И измените вызов на:

public int SomeMember {
    get {
        return this.someMember;
    }
    set {
        if (this.someMember != value){
            someMember = value;
            if (PropertyChanged != null) { // If someone subscribed to the event
                PropertyChanged(this, new PropertyChangedEventArgs("SomeMember")); // Raise the event
            }
        }
   }

   private void listner(object sender, PropertyChangedEventArgs e) {
       string propertyName = e.PropertyName;
       Console.WriteLine(String.Format("Hey! Hey! Listen! a {0} of a chatter in my list has changed!", propertyName));
   }

Ответ 3

почему это не просто вызов PropertyChanged (это, новый PropertyCHangedEventArgs (название))

Потому что, если никто не прикреплял обработчик к событию, объект PropertyChanged возвращает null. Таким образом, вы должны будете убедиться, что это не null, прежде чем вызывать его.

где задано свойство PropertyChanged?

В классах "слушателя".

Например, вы можете написать в другом классе:

ChattyClass tmp = new ChattyClass();
tmp.PropertyChanged += (sender, e) =>
    {
        Console.WriteLine(string.Format("Property {0} has been updated", e.PropertyName));
    };

Как выглядит присваивание?

В С# мы используем операторы присваивания += и -= для событий. Я рекомендую прочитать следующую статью, чтобы понять, как писать обработчики событий с использованием формы анонимного метода (пример выше) и "старой" формы.

Ответ 4

От взятия исходного кода и включения ответа @Styxxy я получаю:

public class ChattyClass  : INotifyPropertyChanged 
{
  private int someMember, otherMember;

  public int SomeMember
  {
      get
      {
          return this.someMember;
      }
      set
      {
          if (this.someMember != value)
          {
              someMember = value;
              OnPropertyChanged("Some Member");
          }
      }
  }

  public int OtherMember
  {
      get
      {
          return this.otherMember;
      }
      set
      {
          if (this.otherMember != value)
          {
              otherMember = value;
              OnPropertyChanged("Other Member");
          }
      }
  }

  protected virtual void OnPropertyChanged(string propertyName)
  {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
  }

  public event PropertyChangedEventHandler PropertyChanged;

}

public class NosyClass
{
    private List<ChattyClass> myChatters = new List<ChattyClass>();

    public void AddChatter(ChattyClass chatter)
    {
        myChatters.Add(chatter);
        chatter.PropertyChanged+=chatter_PropertyChanged;
    }

    private void chatter_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine("A property has changed: " + e.PropertyName);
    }
}