使用`DataContractSerializer`

时间:2015-07-16 22:21:22

标签: c# wpf serialization

我有一个我正在序列化的课程:

using (FileStream fileStreamWriter = new FileStream(fileName, FileMode.Create))
{
    var dataContractSerializer = new DataContractSerializer(typeof(ClassToBeSerialized));
    dataContractSerializer.WriteObject(fileStreamWriter, btChartGroupList);
    fileStreamWriter.Close();
}

在我将Brush类型的属性(称为AreaBrush)添加到ClassToBeSerialized类之前,这样可以正常工作。此AreaBrush属性可以是SolidBrushLinearGradientBrushRadialGradientBrush。在序列化期间,DataContractSerializer抛出:

  

键入' System.Windows.Media.MatrixTransform'使用数据合同名称' MatrixTransform:http://schemas.datacontract.org/2004/07/System.Windows.Media'不是预期的。如果您正在使用DataContractSerializer或者将任何静态未知的类型添加到已知类型列表中,请考虑使用DataContractResolver - 例如,使用KnownTypeAttribute属性或将它们添加到传递给序列化程序的已知类型列表中。

关于如何让它发挥作用的任何想法? 我和BrushConverter一起玩,但没有那么好运。

我想我可以添加所有3种类型的画笔作为属性,但我希望有更好的解决方案。

编辑: 在VMaleev的帮助下,我最终做到了这一点:

        [IgnoreDataMember]
    public Brush AreaBrush
    {
        get { return _areaBrush; }
        set
        {
            SetProperty(ref _areaBrush, value, () => AreaBrush);
        }
    }

    [DataMember]
    public string AreaBrushText
    {
        get
        {
            using (StringWriter sw = new StringWriter())
            {
                XamlWriter.Save(AreaBrush, sw);
                string s = sw.ToString();
                return sw.ToString();
            }
        }
        set
        {
            AreaBrush = (Brush)XamlReader.Parse(value);
        }
    }

2 个答案:

答案 0 :(得分:2)

你不能简单地这样做。我建议您将Brush属性标记为[XmlIgnore],并使用XamlWriterXamlReader分别对其进行序列化和反序列化:

// example of writing
using (var outfile = File.CreateText("Brush.xaml"))
{
    XamlWriter.Save(brush, outfile);
}

// example of reading
using (Stream s = File.OpenRead("Brush.xaml"))
{
    Brush b = XamlReader.Load(s);
}

查看this主题以获取更多信息

答案 1 :(得分:2)

您可以通过将任意WPF元素包装在实现IXmlSerializable的类中来序列化它:

[DataContract]
class ClassToBeSerialized
{
    public LinearGradientBrush Brush { get; set; }

    [DataMember(Name = "Brush")]
    private XamlSerializationWrapper<LinearGradientBrush> BrushSerializer
    {
        get { return new XamlSerializationWrapper<LinearGradientBrush>(Brush); }
        set { Brush = value.Element; }
    }
}

class XamlSerializationWrapper<TElement> : IXmlSerializable
{
    public TElement Element { get; private set; }

    protected XamlSerializationWrapper()
    {
    }

    public XamlSerializationWrapper(TElement element)
    {
        this.Element = element;
    }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(XmlReader reader)
    {
        // this is a bit circuitous, but XamlReader.Load closes the reader for some reason
        var element = (XElement)XElement.ReadFrom(reader);
        Element = (TElement)XamlReader.Parse(element.Elements().Single().ToString());
    }

    public void WriteXml(XmlWriter writer)
    {
        XamlWriter.Save(Element, writer);
    }
}

示例XML:

<?xml version="1.0" encoding="utf-16"?>
<ClassToBeSerialized xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WpfSerialization">
  <Brush>
    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
      <LinearGradientBrush.GradientStops>
        <GradientStop Color="#FF000000" Offset="0" />
        <GradientStop Color="#FFFFFFFF" Offset="1" />
      </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
  </Brush>
</ClassToBeSerialized>

使用示例:

public static string ToXml(ClassToBeSerialized cts)
{
    var dcs = new DataContractSerializer(typeof(ClassToBeSerialized));
    using (var sb = new StringWriter())
    {
        using (var xs = XmlWriter.Create(sb, new XmlWriterSettings() { Indent = true }))
        {
            dcs.WriteObject(xs, cts);
        }
        return sb.ToString();
    }
}

public static ClassToBeSerialized FromXml(string xml)
{
    var dcs = new DataContractSerializer(typeof(ClassToBeSerialized));
    return (ClassToBeSerialized)dcs.ReadObject(XmlReader.Create(new StringReader(xml)));
}