и события (в частности, INotifyPropertyChanged) - PullRequest
3 голосов
/ 14 июля 2011

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

У меня есть человек, который содержит адрес.Оба наследуют от BaseEntity, который реализует INotifyPropertyChanged.Я хочу, чтобы класс Person NotifyPropertyChanged ("Address") не только при задании адреса, но и при изменении самого этого адреса, поэтому мой метод get / set в Person выглядит следующим образом:

class Person : BaseEntity
{
    private Address address;
    public Address Address
    {
        get { return address; }
        set
        {
            address = value;
            NotifyPropertyChanged("Address");

            // propagate changes in Address to changes in Person
            address.PropertyChanged += (s, e) => { NotifyPropertyChanged("Address"); };
        }
    }

    ...
}

Это имеетхорошо работал в течение нескольких месяцев.

Я добавил [Serializable] в Person, Address и BaseEntity (и [field: NonSerialized] в PropertyChanged BaseEntity), а теперь, когда я изменяю Address (somePerson.Address).Street = "что-то новое") invocationCount адреса PropertyChanged этого адреса равен 0, где он был равен 1, поэтому Person не получает уведомления и сам не запускает NotifyPropertyChanged ("Address");

Снова,если я удаляю [Serializable] из Person, он работает, а если я добавляю его обратно, он не работает.На самом деле я еще ничего не сериализую, я только что добавил атрибут [Serializable].

Есть идеи?

Ответы [ 4 ]

2 голосов
/ 15 июля 2011

Я предполагаю (слегка подстегнутый обсуждением в комментариях), что некоторый код где-то в вашем приложении обнаруживает [Serializable] и решает сериализовать объект.Например, вероятным кандидатом может быть кеш - как и любой код «глубокого клонирования».

Попробуйте реализовать ISerializable (или просто добавьте обратный вызов сериализации) и добавьте точку останова.Если ваша точка останова сработала, загрузите окно стека вызовов и перейдите обратно вверх по стеку, чтобы увидеть, что сериализует ваш объект и почему.

2 голосов
/ 14 июля 2011

Является ли ваш Person / Address / BaseEntity сериализованным / десериализованным и , а затем демонстрирует это поведение, или это просто дополнительный атрибут [Serializable], который вызывает такое поведение?

Я спрашиваю, десериализованы ли объекты, а затем демонстрирует поведение, потому что в большинстве моих реализаций INotifyPropertyChanged я явно отмечаю событие PropertyChanged как не сериализованное, а затем вручную перехватываю событие при десериализации соответствующим образом.,(Сериализация событий расширяет объект-граф и может вызвать сериализацию неожиданных объектов.)

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

1 голос
/ 14 июля 2011

Я провел небольшой тест, и не было никакой разницы между сериализуемостью классов и нет.Вот пример рабочего кода.

    [Serializable]
    public class BaseEntity : INotifyPropertyChanged
    {
        [NonSerialized]
        private PropertyChangedEventHandler _propertyChanged;

        public event PropertyChangedEventHandler PropertyChanged
        {
            add { _propertyChanged += value; }
            remove { _propertyChanged -= value; }
        }

        protected void NotifyPropertyChanged(string propertyName)
        {
            _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    [Serializable]
    public class Person : BaseEntity
    {
        private Address _address;

        public Address Address
        {
            get { return _address; }
            set
            {
                _address = value;
                NotifyPropertyChanged("Address");
                Address.PropertyChanged += (s, e) =>
                                               {
                                                   Console.WriteLine("Address Property Changed {0}", e.PropertyName);
                                                   NotifyPropertyChanged("Address");
                                               };
            }
        }

    }
    [Serializable]
    public class Address : BaseEntity
    {
        private string _city;
        public string City
        {
            get { return _city; }
            set
            {
                _city = value;
                NotifyPropertyChanged("City");
            }
        }
    }
    static void Main(string[] args)
    {



        var person = new Person();
        person.PropertyChanged += (s, e) => Console.WriteLine("Property Changed {0}", e.PropertyName);
        person.Address = new Address();
        person.Address.City = "TestCity";

    }

Вывод программы:

Свойство измененный адрес

Адрес Свойство измененный город

Свойство измененный адрес

1 голос
/ 14 июля 2011

Смотрите, если добавление:

[field:NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;

делает свое дело.

Первоначально из: Как исключить несериализуемые наблюдатели из реализации [Serializable] INotifyPropertyChanged?

...