ПРИВЕТ!
Здесь у меня есть простой пример класса с тремя полями класса B типа и некоторого другого материала. Поскольку Вы видите, что я слушаю на каждом изменении дочернего объекта. Так как мне могло быть нужно много свойств класса B типа, я задаюсь вопросом, существует ли способ уменьшить код. При создании слушателя + метод для каждого кажется, что у меня будет МНОГО кода. Как я зафиксировал бы это... использование словаря или чего-то подобного? Мне сказали, что МОК мог зафиксировать это, но я не уверен, где запустить.
public class A : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int _id;
public int Id
{
get { return _id; }
set
{
if (_id == value)
{
return;
}
_id = value;
OnPropertyChanged("Id");
}
}
public string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
{
return;
}
_name = value;
OnPropertyChanged("Name");
}
}
public B _firstB;
public B FirstB
{
get { return _firstB; }
set
{
if (_firstB == value)
{
return;
}
if (_firstB != null)
{
FirstB.PropertyChanged -= firstObjectB_Listener;
}
_firstB = value;
if (_firstB != null)
FirstB.PropertyChanged += new PropertyChangedEventHandler(firstObjectB_Listener);
OnPropertyChanged("FirstB");
}
}
public B _secondB;
public B SecondB
{
get { return _secondB; }
set
{
if (_secondB == value)
{
return;
}
if (_secondB != null)
{
FirstB.PropertyChanged -= secondObjectB_Listener;
}
_secondB = value;
if (_secondB != null)
SecondB.PropertyChanged += new PropertyChangedEventHandler(secondObjectB_Listener);
OnPropertyChanged("FirstB");
}
}
public B _thirdB;
public B ThirdB
{
get { return _thirdB; }
set
{
if (_thirdB == value)
{
return;
}
if (_thirdB != null)
{
ThirdB.PropertyChanged -= thirdObjectB_Listener;
}
_thirdB = value;
if (_thirdB != null)
ThirdB.PropertyChanged += new PropertyChangedEventHandler(thirdObjectB_Listener);
OnPropertyChanged("ThirdB");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
void firstObjectB_Listener(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Object A has found a change of " + e.PropertyName + " on first object B");
}
void secondObjectB_Listener(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Object A has found a change of " + e.PropertyName + " on second object B");
}
void thirdObjectB_Listener(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Object A has found a change of " + e.PropertyName + " on third object B");
}
}
Самый элегантный способ, который я знаю, - это использовать аспектно-ориентированное программирование (АОП) с таким инструментом, как PostSharp . Я нашел примеры реализации INotifyPropertyChanged здесь и здесь . Это позволяет вам украсить ваши свойства атрибутом, а PostSharp затем реализует INotifyPropertyChanged для вас при построении кода.
Чтобы немного упростить, вы можете сделать следующие две вещи.
Во-первых, в обработчике PropertyChanged первый параметр, отправитель, - это объект, который инициировал событие, по крайней мере, если вы внедрили OnPropertyChanged в класс B так же, как в классе A. Это означает, что вам нужен только один обработчик для всех свойств B.
private void BValueListener(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Found change of {0} on object {1}", e.PropertyName, sender);
}
Если вам нужно точно знать, какое из свойств B было отправлено, вы можете проверить его в методе BValueListener.
if (sender == FirstB) { /* Do special stuff here */ }
Имея один и тот же слушатель для всех свойств B, мы можем перейти к написанию установщика свойств, например:
private B _thirdB;
public B ThirdB
{
get { return _thirdB; }
set {
if (UpdateBValue(ref _thirdB, value)) {
OnPropertyChanged("ThirdB");
}
}
}
private bool UpdateBValue(ref B value, B newValue)
{
if (value == newValue)
{
return false;
}
if (value != null)
{
value.PropertyChanged -= BValueListener;
}
value = newValue;
if (value != null)
{
value.PropertyChanged += BValueListener;
}
return true;
}
Если вам действительно нужны разные обработчики для каждого свойства, вы можете изменить приведенный выше код на что-то вроде
private B _thirdB;
public B ThirdB
{
get { return _thirdB; }
set
{
if (UpdateBValue(ref _thirdB, value, BValueListener))
{
OnPropertyChanged("ThirdB");
}
}
}
private bool UpdateBValue(ref B value, B newValue, PropertyChangedEventHandler eventHandler)
{
if (value == newValue)
{
return false;
}
if (value != null)
{
value.PropertyChanged -= eventHandler;
}
value = newValue;
if (value != null)
{
value.PropertyChanged += eventHandler;
}
return true;
}
, где вы может отправить метод прослушивателя, который вы хотели бы использовать в каждом случае.
Один хороший способ упростить настройку свойств можно найти здесь .
Что касается ваших каскадных уведомлений: я предполагаю, что вы могли бы использовать описанный выше подход для обработки (отмены) подписки на события для свойств, реализующих там INotifyPropertyChanged
.