Обработка 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?
- Как выглядит присваивание?
Ответы
Ответ 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);
}
}