INotifyPropertyChanged 和反序列化
INotifyPropertyChanged and Deserialization
鉴于:
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);
}
}
}
}
当您序列化然后反序列化此 class 时,它会触发 RaisePropertyChanged
事件,这是不可取的。当 class 反序列化时,是否可以防止触发此事件?
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
如果 class 被反序列化,有没有办法获得 bool
值?
那么我可以这样做:
set
{
if (_StringProp != value)
{
_StringProp = value;
if (!Deserializing)
{
RaisePropertyChanged("StringProp");
_TestFire.Add("fired " + DateTime.Now);
}
}
}
是的,您可以通过在 class 中实现 OnDeserializing
和 OnDeserialized
serialization callback methods 来做您想做的事。在 OnDeserializing
方法中,将您的私有 _isDeserializing
变量设置为 true,并在 OnDeserialized
中将其设置回 false。我建议在 RaisePropertyChanged
方法中执行 _isDeserializing
检查,这样你就不会在每个 属性 中都有重复的代码。
所以你最终会得到这样的结果:
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]
标记 public 属性,然后用 [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);
}
}
}
...
}
鉴于:
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);
}
}
}
}
当您序列化然后反序列化此 class 时,它会触发 RaisePropertyChanged
事件,这是不可取的。当 class 反序列化时,是否可以防止触发此事件?
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
如果 class 被反序列化,有没有办法获得 bool
值?
那么我可以这样做:
set
{
if (_StringProp != value)
{
_StringProp = value;
if (!Deserializing)
{
RaisePropertyChanged("StringProp");
_TestFire.Add("fired " + DateTime.Now);
}
}
}
是的,您可以通过在 class 中实现 OnDeserializing
和 OnDeserialized
serialization callback methods 来做您想做的事。在 OnDeserializing
方法中,将您的私有 _isDeserializing
变量设置为 true,并在 OnDeserialized
中将其设置回 false。我建议在 RaisePropertyChanged
方法中执行 _isDeserializing
检查,这样你就不会在每个 属性 中都有重复的代码。
所以你最终会得到这样的结果:
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]
标记 public 属性,然后用 [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);
}
}
}
...
}