INotifyPropertyChanged и десериализация - PullRequest
1 голос
/ 12 апреля 2019

Дано:

public class MyClass : INotifyPropertyChanged
{
    public List<string> _TestFire = new List<string>();

    string _StringProp;
    public string StringProp
    {
        get
        {
            return _StringProp;
        }
        set
        {
            if (_StringProp != value)
            {
                _StringProp = value;
                RaisePropertyChanged("StringProp");
                _TestFire.Add("fired " + DateTime.Now);
            }
        }
    }
}

Когда вы сериализуете, а затем десериализуете этот класс, он запускает событие RaisePropertyChanged, что нежелательно.Можно ли предотвратить запуск этого события при десериализации класса?

var MyclassInstance = new MyClass() { StringProp = "None" };

MyclassInstance._TestFire.Clear(); // Clear property change history

var serobj = JsonConvert.SerializeObject();

var newitem = JsonConvert.DeserializeObject<MyClass>(serobj);

// newitem._TestFire.Count == 1, the set method was executed

Есть ли способ получить значение bool, если класс десериализован?Тогда я мог бы сделать:

        set
        {
            if (_StringProp != value)
            {
                _StringProp = value;

                if (!Deserializing)
                {
                    RaisePropertyChanged("StringProp");
                    _TestFire.Add("fired " + DateTime.Now);
                }
            }
        }

1 Ответ

1 голос
/ 12 апреля 2019

Да, вы можете делать все, что хотите, внедрив в своем классе методы обратного вызова сериализации и OnDeserialized *1004*. В методе OnDeserializing установите для вашей частной переменной _isDeserializing значение true, а в OnDeserialized установите для нее значение false. Я бы порекомендовал сделать проверку _isDeserializing внутри метода RaisePropertyChanged, чтобы у вас не было дублированного кода внутри каждого свойства.

Итак, вы бы получили что-то вроде этого:

public class MyClass : INotifyPropertyChanged
{
    public List<string> _TestFire = new List<string>();

    string _StringProp;
    public string StringProp
    {
        get
        {
            return _StringProp;
        }
        set
        {
            if (_StringProp != value)
            {
                _StringProp = value;
                RaisePropertyChanged("StringProp");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void RaisePropertyChanged(string propertyName)
    {
        // don't raise the event if the property is being changed due to deserialization    
        if (_isDeserializing) return;

        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        _TestFire.Add(propertyName + " was fired " + DateTime.Now);
    }

    bool _isDeserializing = false;

    [OnDeserializing]
    internal void OnDeserializingMethod(StreamingContext context)
    {
        _isDeserializing = true;
    }

    [OnDeserialized]
    internal void OnDeserializedMethod(StreamingContext context)
    {
        _isDeserializing = false;
    }
}

Рабочая демоверсия: https://dotnetfiddle.net/QkOcF4


Другой способ решения этой проблемы - пометить ваши общедоступные свойства [JsonIgnore], а затем пометить соответствующие поля поддержки [JsonProperty], указав имя свойства для использования в JSON. Это позволило бы Json.Net устанавливать поля поддержки напрямую и не выполнять никакой логики мутатора.

public class MyClass : INotifyPropertyChanged
{
    public List<string> _TestFire = new List<string>();

    [JsonProperty("StringProp")]
    string _StringProp;

    [JsonIgnore]
    public string StringProp
    {
        get
        {
            return _StringProp;
        }
        set
        {
            if (_StringProp != value)
            {
                _StringProp = value;
                RaisePropertyChanged("StringProp");
                _TestFire.Add("StringProp was fired " + DateTime.Now);
            }
        }
    }

    ...
}

Рабочая демоверсия: https://dotnetfiddle.net/jc7wDu

...