将XML反序列化为ObservableCollection

时间:2013-10-17 16:32:41

标签: wpf c#-4.0 xml-serialization observablecollection

使用VS 2012和.NET 4.0,我有以下代码正确反序列化XML文件:

XML文件:

<?xml version="1.0"?> 
<Codes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
  <Code>
    <AccpacCode>CA9998</AccpacCode>
    <LAC>90699999999999999</LAC>
    <SCSCode>SDI</SCSCode>
  </Code>
  <Code>
    <AccpacCode>ORWC</AccpacCode>
    <LAC>94199999999999999</LAC>
    <SCSCode>WC</SCSCode>
  </Code>
  <Code>
    <AccpacCode>AK9999</AccpacCode>
    <LAC>90299999999999999</LAC>
    <SCSCode>UI</SCSCode>
    <ParentEmployerAccpacCode>AKSUTA</ParentEmployerAccpacCode>
  </Code>
<Codes>

XSD文件:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Codes" xmlns="SerializeObservableCollection" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Codes" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Code">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="AccpacCode" type="xs:string" minOccurs="0" />
              <xs:element name="LAC" type="xs:string" minOccurs="0" />
              <xs:element name="SCSCode" type="xs:string" minOccurs="0" />
              <xs:element name="ParentEmployerAccpacCode" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

C#代码:

try
{
    XmlSerializer _serializer = new XmlSerializer(typeof(Codes));

    // A file stream is used to read the XML file into the ObservableCollection
    using (StreamReader _reader = new StreamReader(@"LocalCodes.xml"))
    {
        var codes = _serializer.Deserialize(_reader) as Codes;

    }                
}
catch (Exception ex)
{
    // Catch exceptions here
}

我想将反序列化的结果放入一个ObservableCollection中,并找到了一些示例,说明以下内容应该有效:

ObservableCollection<Codes> CodeCollection;

...

try
{
    XmlSerializer _serializer = new XmlSerializer(typeof(ObservableCollection<Codes>));

    // A file stream is used to read the XML file into the ObservableCollection
    using (StreamReader _reader = new StreamReader(@"LocalCodes.xml"))
    {
        CodeCollection = _serializer.Deserialize(_reader) as ObservableCollection<Codes>;

    }                
}

当我运行此代码时,我收到"There is an error in XML document (2, 2)."的错误消息和"<Codes xmlns=''> was not expected."的内部异常我已经看到提到需要一个默认构造函数来使这个工作,而Codes.cs类确实有一个(它是由VS2012由XSD文件生成的文件)。这是Codes.cs文件的片段:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.18051
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#pragma warning disable 1591

namespace SerializeObservableCollection {


    /// <summary>
    ///Represents a strongly typed in-memory cache of data.
    ///</summary>
    [global::System.Serializable()]
    [global::System.ComponentModel.DesignerCategoryAttribute("code")]
    [global::System.ComponentModel.ToolboxItem(true)]
    [global::System.Xml.Serialization.XmlSchemaProviderAttribute("GetTypedDataSetSchema")]
    [global::System.Xml.Serialization.XmlRootAttribute("Codes")]
    [global::System.ComponentModel.Design.HelpKeywordAttribute("vs.data.DataSet")]
    public partial class Codes : global::System.Data.DataSet {

        private CodeDataTable tableCode;

        private global::System.Data.SchemaSerializationMode _schemaSerializationMode = global::System.Data.SchemaSerializationMode.IncludeSchema;

        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")]
        public Codes() {
            this.BeginInit();
            this.InitClass();
            global::System.ComponentModel.CollectionChangeEventHandler schemaChangedHandler = new global::System.ComponentModel.CollectionChangeEventHandler(this.SchemaChanged);
            base.Tables.CollectionChanged += schemaChangedHandler;
            base.Relations.CollectionChanged += schemaChangedHandler;
            this.EndInit();
        }

我需要更改/修复什么才能使其工作并填充ObservableCollection?

2 个答案:

答案 0 :(得分:1)

@BrianKE我非常怀疑这对你来说仍然有用,但也许它会对其他人有用。我和你今天有同样的问题。我花了半天时间来弄明白。

首先,您看到的消息是因为您指定的类型......

XmlSerializer _serializer = new XmlSerializer(typeof(ObservableCollection<Codes>));

..不是ObservableCollection。如果类型错误,则会出现此错误。代码需要是一个可观察的集合,以使您的陈述发挥作用。

你需要的是root元素,目前代码是你的根元素,所以你需要一个只为root用户的Class,然后你就有了许多Code元素。例如

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class MIGRATION : object, INotifyPropertyChanged, INotifyPropertyChanging
{

    private string projectNameField;

    private ObservableCollection<FileDescriptions> fileDescriptionsField;

    //private FileDescriptions[] fileDescriptionsField;

    /// <remarks/>
    //[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    [XmlElement("ProjectName")]
    public string ProjectName
    {
        get
        {
            return this.projectNameField;
        }
        set
        {
            this.RaisePropertyChanging("ProjectName");
            this.projectNameField = value;
            this.RaisePropertyChanged("ProjectName");
        }
    }

    /// <remarks/>
    [XmlElement("FileDescriptions")]
    public ObservableCollection<FileDescriptions> FileDescriptions 
    { 
        get
        {
            return this.fileDescriptionsField;
        }
        set
        {
            this.fileDescriptionsField = value;
            this.RaisePropertyChanged("FileDescriptions");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null))
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }

    public event System.ComponentModel.PropertyChangingEventHandler PropertyChanging;

    protected void RaisePropertyChanging(string propertyName)
    {
        System.ComponentModel.PropertyChangingEventHandler propertyChanging = this.PropertyChanging;
        if ((propertyChanging != null))
        {
            propertyChanging(this, new System.ComponentModel.PropertyChangingEventArgs(propertyName));
        }
    }
}

因此,Observable集合位于反序列化类中的元素上。我知道你在谈论什么,我看过你正在描述的例子,但我不知道那是什么。据我所知,反序列化与可观察的集合无关。除非他们有多个根元素?或者也许是因为你没有反序列化整个XML,而只是其中的一部分,才有意义。

答案 1 :(得分:-1)

反序列化只能用于以前使用Serialize序列化的内容。否则,你只是在玩火。

您可以使用XDocument轻松打开并遍历XML文档。

XDocument xml = XDocument.Load(filename);
var collection = new ObservableCollection<Code>();
foreach (XElement e in xml.Elements("code"))
{
   collection.Add(new Code() { AccpacCode = e.Element("AccpacCode").Value,
                               LAC = e.Element("LAC").Value });
}

您可以轻松地迭代所有xml.Elements并激活您添加到ObservableCollection的代码对象。在加载过程中,界面可能会略微闪烁。