WPF自带的一些属性比如System.Windows.Media.Brush、System.Windows.Media.FontFamily、System.Windows.FontWeight等不具有直接序列化能力,本文针对这一点设计名为PropertySerializateDictionary的类,实现了不同类不同对象公有属性的序列化和反序列化。本类继承于Dictionary<string, TypeAndValue>, IXmlSerializable,调用了自实现类TypeAndValue。
代码:
/// <summary>
/// 用于记录对象和类型的类
/// 用在PropertySerializateDictionary中
/// 单元测试:PropertySerializateDictionaryTest
/// </summary>
public class TypeAndValue
{
public TypeAndValue(Type type, object value)
{
Type = type;
Value = value;
}
public TypeAndValue()
{
}
public Type Type { get; set; }
public object Value { get; set; }
public override bool Equals(object obj)
{
TypeAndValue tav = obj as TypeAndValue;
if (tav == null)
{
return false;
}
var EqualsMehtod = Type.GetMethod("Equals");
if (tav.Type.FullName == this.Type.FullName
&& ((bool)EqualsMehtod.Invoke(tav.Value, new object[]{ this.Value}))
)
{
return true;
};
return false;
}
/// <summary>
/// 不同类不同对象公有属性的序列化和反序列化
/// 可序列化、反序列化WPF体系Color、Brush、FontFamily、FontWeight
/// 无法识别集合类型与Struct?类型
/// </summary>
/// <typeparam name="T"></typeparam>
public class PropertySerializateDictionary : Dictionary<string, TypeAndValue>, IXmlSerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
if (reader.IsEmptyElement)
{
return;
}
reader.Read();
string TypeString = reader.GetAttribute("Type");
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
string key = reader.Name;
Type tpe = Type.GetType(TypeString);
PropertyInfo[] props = tpe.GetProperties();
this[key] = new TypeAndValue(tpe, tpe.GetConstructor(new Type[] { }).Invoke(null));
if (!reader.IsEmptyElement)
{
//填充属性值
reader.ReadStartElement();
if (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
foreach (PropertyInfo pi in props)
{
if (pi.PropertyType.FullName == "System.Windows.Media.Brush")
{
System.Windows.Media.BrushConverter brushConverter = new System.Windows.Media.BrushConverter();
pi.SetValue(this[key].Value, (System.Windows.Media.Brush)brushConverter.ConvertFromString(reader.ReadElementString(pi.Name)), null);
//根据属性的类型对读取出来的字符串进行转换
}
else if (pi.PropertyType.FullName == "System.Windows.Media.FontFamily")
{
System.Windows.Media.FontFamilyConverter fontFamilyConverter = new System.Windows.Media.FontFamilyConverter();
pi.SetValue(this[key].Value, (System.Windows.Media.FontFamily)fontFamilyConverter.ConvertFromString(reader.ReadElementString(pi.Name)), null);
}
else if (pi.PropertyType.FullName == "System.Windows.FontWeight")
{
System.Windows.FontWeightConverter fontFamilyConverter = new System.Windows.FontWeightConverter();
pi.SetValue(this[key].Value, (System.Windows.FontWeight)fontFamilyConverter.ConvertFromString(reader.ReadElementString(pi.Name)), null);
}
else
{
pi.SetValue(this[key].Value, Convert.ChangeType(reader.ReadElementString(pi.Name), pi.PropertyType), null);
}
}
}
}
reader.Read();
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
if (this.Keys.Count < 1)
{
return;
}
foreach (string name in Keys)
{
TypeAndValue tandv = new TypeAndValue();
writer.WriteStartElement(name);
if (this.TryGetValue(name, out tandv))
{
writer.WriteAttributeString("Type", tandv.Type.FullName);
//存储该类型的公有属性
PropertyInfo[] props = tandv.Type.GetProperties();
//将对象的每个属性名和属性值写入xml文件中
foreach (PropertyInfo prop in props)
{
//<属性名>属性值</属性名>
writer.WriteElementString(prop.Name, prop.GetValue(tandv.Value, null).ToString());
}
}
writer.WriteEndElement();
}
}
public override bool Equals(object obj)
{
PropertySerializateDictionary dic = obj as PropertySerializateDictionary;
if (dic == null)
{
return false;
}
if (dic.Count != this.Count)
{
return false;
}
foreach (string key in dic.Keys)
{
if (!this[key].Equals(dic[key]))
{
return false;
}
}
return true;
}
}
单元测试代码如下:
[Serializable]
public class SerialMock
{
// Private fields.
string strFirstName = "<first name>";
DateTime dtBirthDate = new DateTime(1800, 1, 1);
private FontWeight m_fontWeight = FontWeights.Heavy;
[XmlElement(ElementName="XAxisProperty_Caption_FontWeight")]
public FontWeight FontWeight
{
get { return m_fontWeight; }
set { m_fontWeight = value; }
}
[XmlElement(ElementName = "XAxisProperty_Caption_FonFamily")]
private FontFamily m_FontFamily = new FontFamily("TechnicBold");
public FontFamily FontFamily
{
get { return m_FontFamily; }
set { m_FontFamily = value; }
}
public SerialMock()
{
}
// Public properties.
public string FirstName
{
set
{
strFirstName = value;
}
get { return strFirstName; }
}
[XmlElement(DataType = "date")]
public DateTime BirthDate
{
set
{
dtBirthDate = value;
}
get { return dtBirthDate; }
}
public override bool Equals(object obj)
{
SerialMock p = obj as SerialMock;
if (p == null)
{
return false;
}
return p.FirstName.Equals(this.FirstName)
&& p.BirthDate.Equals(this.BirthDate)
&& p.FontWeight.Equals(this.FontWeight);
}
public override int GetHashCode()
{
return this.FirstName.GetHashCode() ^ this.BirthDate.GetHashCode() ^ this.FontWeight.GetHashCode();
}
public override string ToString()
{
return strFirstName.ToArray() + dtBirthDate.ToShortDateString() + FontWeight.ToString() + FontFamily;
}
}
/// <summary>
///ReadXml 的测试
///</summary>
[TestMethod()]
public void ReadXmlTest()
{
Property_Setting.Add("People1", new TypeAndValue(typeof(SerialMock), new SerialMock() { FirstName = "a",
FontWeight = FontWeights.Light,
BirthDate=new DateTime(1984, 05, 17)}));
Property_Setting.Add("People2", new TypeAndValue(typeof(SerialMock), new SerialMock() { FirstName = "b",
FontWeight = FontWeights.Black,
FontFamily = new System.Windows.Media.FontFamily("宋体") }));
MemoryStream stream = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(typeof(PropertySerializateDictionary));
serializer.Serialize(stream, Property_Setting);
stream.Flush();
stream.Position = 0;
//stream = new FileStream(System.AppDomain.CurrentDomain.BaseDirectory + "tst.axml", FileMode.Open);
PropertySerializateDictionary dict = (PropertySerializateDictionary)serializer.Deserialize(stream);
Assert.AreEqual<PropertySerializateDictionary>(Property_Setting, dict);
stream.Close();
}