Как избежать реализации INotifyPropertyChanged вручную
есть ли способ избежать этого. У меня есть много классов, которые привязаны к DataGridViews, и они просто простая коллекция свойств с геттером и сеттером по умолчанию. Поэтому эти занятия очень просты. Теперь мне нужно реализовать интерфейс INotifyPropertyChanged для них, который значительно увеличит объем кода. Есть ли класс, который я могу наследовать, чтобы избежать написания всего этого скучного кода? Я представляю, что я могу наследовать свои классы от некоторого класса и украсить свойства некоторые атрибуты, и это сделает магию. Это возможно?
Я хорошо знаю аспектно-ориентированное программирование, но я бы предпочел сделать это объектно-ориентированным способом.
7 ответов
создайте базовый класс контейнера, например:
abstract class Container : INotifyPropertyChanged
{
Dictionary<string, object> values;
protected object this[string name]
{
get {return values[name]; }
set
{
values[name] = value;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
class Foo : Container
{
public int Bar
{
{get {return (int) this["Bar"]; }}
{set { this["Bar"] = value; } }
}
}
Примечание: очень упрощенный код
это зависит; вы можете использовать PostSharp написать такой атрибут,переписан Ткачом; однако, я бы соблазнился просто сделать это вручную-возможно, используя общий метод для обработки обновлений данных, т. е.
private string name;
public string Name {
get { return name; }
set { Notify.SetField(ref name, value, PropertyChanged, this, "Name"); }
}
С:
public static class Notify {
public static bool SetField<T>(ref T field, T value,
PropertyChangedEventHandler handler, object sender, string propertyName)
{
if(!EqualityComparer<T>.Default.Equals(field,value)) {
field = value;
if(handler!=null) {
handler(sender, new PropertyChangedEventArgs(propertyName));
}
return true;
}
return false;
}
}
без AOP, я не думаю, что есть простой способ модифицировать это для ваших существующих классов. Как бы вы это ни сделали, вам, по крайней мере, придется изменить все свои свойства.
Я использую базовый класс, наследующий INotifyPropertyChanged с методом OnPropertyChanged(string propertyName) для запуска события. Затем я использую фрагмент кода Visual Studio для создания свойств, которые автоматически вызывают OnPropertyChanged в сеттере свойств.
вот аналогичное решение для Marc, которое было расширено, чтобы разрешить несколько свойств onpropertychanges и несколько RaiseCanExecuteChanged
простой пример использования
string _firstName;
public string FirstName
{
get { return _firstName; }
set { OnPropertyChanged(ref _firstName, value, "FirstName"); }
}
расширенный пример использования нескольких обновлений свойств и нескольких команд
string _firstName;
public string FirstName
{
get { return _firstName; }
set { OnPropertyChanged(ref _firstName, value, "FirstName", "FullName", Command1, Command2); }
}
расширенный пример вызывает OnProperty изменен на firstname и fullname, а также вызывает RaiseCanExecuteChanged для command1 и command2
базовый ViewModel код
protected void OnPropertyChanged<T>(ref T field, T value, params object[] updateThese)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(updateThese);
}
}
protected void OnPropertyChanged(params object[] updateThese)
{
if (PropertyChanged != null)
{
foreach (string property in updateThese.Where(property => property is string))
PropertyChanged(this, new PropertyChangedEventArgs(property));
foreach (DelegateCommand<object> command in updateThese.Where(property => property is DelegateCommand<object>))
command.RaiseCanExecuteChanged();
}
}
использование кода gen (скажем,T4) есть еще один способ. Проверьте обсуждение по адресу:автоматическая реализация INotifyPropertyChanged через генерацию кода T4?.
Я использую этот метод, и он работает хорошо.
Я только что нашел ActiveSharp-Автоматический INotifyPropertyChanged, Я еще не использовал его, но он выглядит хорошо.
процитировать с его веб-сайта...
отправлять уведомления об изменении свойств без указания имени свойства в качестве строка.
вместо этого напишите такие свойства:
public int Foo
{
get { return _foo; }
set { SetValue(ref _foo, value); } // <-- no property name here
}
обратите внимание, что нет необходимости содержать имя свойства как строку. ActiveSharp надежно и правильно вычисляет это для себя. Он работает на основе того факта, что реализация вашего свойства передает поле поддержки (_foo) по ref. (ActiveSharp использует этот вызов "по ref", чтобы определить, какое резервное поле было передано, и из поля он идентифицирует свойство).