开发者

and events (INotifyPropertyChanged, specifically)

开发者 https://www.devze.com 2023-03-20 04:35 出处:网络
I\'ve run into a really strange p开发者_StackOverflow社区roblem I can\'t seem to reproduce with a small example.Sorry if this question is a little vague.

I've run into a really strange p开发者_StackOverflow社区roblem I can't seem to reproduce with a small example. Sorry if this question is a little vague.

I have a Person which contains an Address. Both inherit from BaseEntity which implements INotifyPropertyChanged. I want the Person class to NotifyPropertyChanged("Address") not only when an Address is set, but also when that Address itself changes, so my get/set in Person looks like this:

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"); };
        }
    }

    ...
}

This has worked nicely for months.

I've added [Serializable] to Person, Address, and BaseEntity (and [field: NonSerialized] to BaseEntity's PropertyChanged), and now when I make a change to Address (somePerson.Address.Street = "something new") that address's PropertyChanged's invocationCount is 0 where it used to be 1, so Person doesn't get notified, and doesn't itself fire NotifyPropertyChanged("Address");

Again, if I remove [Serializable] from Person, it works, and if I add it back, it doesn't work. I'm not actually serializing anything yet, I've just added the [Serializable] attribute.

Any ideas?


My guess (slightly spurred on from a discussion in the comments) is that some code somewhere in your application is detecting [Serializable] and deciding to serialize the object. For example, a cache would be a likely candidate - as might any "deep clone" code.

Try implementing ISerializable (or just add a serialization callback), and add a break-point. If your break-point hits, load the call-stack window and navigate back up the stack to see what is serializing your object, and why.


Are your Person/Address/BaseEntity being serialized/deserialized and then exhibiting this behavior, or is it simply the additional of the [Serializable] attribute that is causing this behavior?

I ask if the objects are being deserialized and then exhibiting the behavior becaseu in most of my implementations of INotifyPropertyChanged I explicitly mark the PropertyChanged event as being non-serialized and then manually re-hook the event upon deserialization as appropriate. (Having events serialized expands the object-graph and can cause serialization of unexpected objects.)

If your object's are not serializing the event, then upon deserialization, it would make sense that they're not appearing to fire. They're probably being raised, but nobody is listening any more.


See if adding:

[field:NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;

does the trick.

Originally from: How to exclude nonserializable observers from a [Serializable] INotifyPropertyChanged implementor?


I did a little test and there was no difference between having the classes serializable and not. Here is some working sample code.

    [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";

    }

Program output is

Property Changed Address

Address Property Changed City

Property Changed Address

0

精彩评论

暂无评论...
验证码 换一张
取 消