问题
I write WPF MVVM modular application using Prism 6 in MS VS 2015 Professional. When I try to serialize to XML file the hierarchical ObservableCollection using System.Xml.Serialization.XmlSerializer then System.InvalidOperationException is thrown in System.Xml.dll. Below is definition of the collection:
public class Group : ProfileElementType
{
. . . . . .
private ObservableCollection<ProfileElementType> _childProfileElenents;
[Browsable(false)]
public ObservableCollection<ProfileElementType> ChildProfileElenents
{
get { return this._childProfileElenents; }
set { this_childProfileElenents = value; }
}
public Group()
{
. . . . .
this.ChildProfileElenents = new ObservableCollection<ProfileElementType>();
. . . . .
}
. . . . .
}
Where [Browsable(false)] is System.ComponentModel.BrowsableAttribute. And now, let me give further details. Please see below the complete definition of ProfileElementType class and classes which are inherited from it. This is ProfileElementType class:
[XmlInclude(typeof(Group))]
[XmlInclude(typeof(Register))]
public class ProfileElementType : BindableBase, IProfileElementType
{
#region Fields
private string _elementTypeName;
#endregion
#region Properties
[Browsable(false)]
public string ElementTypeName
{
get { return this._elementTypeName; }
set { this._elementTypeName = value; }
}
#endregion
#region IProfileElementType Implementation
private Type _elementType;
[Browsable(false)]
public Type ElementType
{
get { return this._elementType; }
set { this._elementType = value; }
}
#endregion
}
Where BindableBase class here is Prism.MVVM.BindableBase. And IProfileElementType interface is shown below:
public interface IProfileElementType
{
Type ElementType { get; set; }
}
Below is Group and Register classes. These classes are inherited from ProfileElementType class. So this is Group class definition:
public class Group : ProfileElementType
{
#region Fields
private string name;
private string description;
private ObservableCollection<ProfileElementType> _childProfileElenents;
private Group parent;
#endregion
#region Constructors
public Group()
{
this.ElementType = this.GetType();
this.ElementTypeName = this.ElementType.Name;
this.Name = "Group 1";
this.ChildProfileElenents = new ObservableCollection<ProfileElementType>();
}
#endregion
#region Properties
[Display(Description = "The Name of this Group.", Name = "The Name")]
public string Name
{
get { return this.name; }
set { this.SetProperty(ref this.name, value); }
}
[Display(Description = "The Brief Description of this Group", Name = "The Description")]
public string Description
{
get { return this.description; }
set { this.SetProperty(ref this.description, value); }
}
/// <summary>
/// The collection of elements which are the children elements of this group.
/// These elements can be of Group class instances or Register class instances
/// </summary>
[Browsable(false)]
public ObservableCollection<ProfileElementType> ChildProfileElenents
{
get { return this._childProfileElenents; }
set { this.childProfileElenents = value; }
}
/// <summary>
/// Parent group whose ChildProfileElenents collection comprises this Group instance.
/// </summary>
[Browsable(false)]
public Group Parent
{
get { return this.parent; }
set { this.parent = value; }
}
#endregion
}
And now, let me give you the definition of Register class:
public class Register : ProfileElementType
{
#region Fields
private int number;
private string name;
private string description;
private string currentValue;
private string defaultValue;
private string minimalValue;
private string maximalValue;
private string dataTypeName;
private RegisterDataAccess accessToData;
private Group parent;
#endregion
#region Constructors
public Register()
{
this.ElementType = this.GetType();
this.ElementTypeName = this.ElementType.Name;
this.Name = "REgister 1";
this.AccessToData = RegisterDataAccess.Read_Write;
}
#endregion
#region Properties
[Display(Description = "Register Address.", Name = "The Address", GroupName = "Common Information")]
public int Number
{
get { return this.number; }
set { this.SetProperty(ref this.number, value); }
}
[Display(Description = "Register Name.", Name = "The Name", GroupName = "Common Information")]
public string Name
{
get { return this.name; }
set { this.SetProperty(ref this.name, value); }
}
[Display(Description = "Breif description.", Name = "The Description", GroupName = "Common Information")]
public string Description
{
get { return this.description; }
set { this.SetProperty(ref this.description, value); }
}
[Display(Description = "Register current value.", Name = "Current Value", GroupName = "Data")]
public string CurrentValue
{
get { return this.currentValue; }
set { this.SetProperty(ref this.currentValue, value); }
}
[Display(Description = "Register default value.", Name = "Default value", GroupName = "Data")]
public string DefaultValue
{
get { return this.defaultValue; }
set { this.SetProperty(ref this.defaultValue, value); }
}
[Display(Description = "Register Minimal Value.", Name = "Minimal Value", GroupName = "Data")]
public string MinimalValue
{
get { return this.minimalValue; }
set { this.SetProperty(ref this.minimalValue, value); }
}
[Display(Description = "Register Maximal Value.", Name = "Maximal Value", GroupName = "Data")]
public string MaximalValue
{
get { return this.maximalValue; }
set { this.SetProperty(ref this.maximalValue, value); }
}
[Display(Description = "Register Data Type.", Name = "Data Type", GroupName = "Data")]
public string DataTypeName
{
get { return this.dataTypeName; }
set { this.SetProperty(ref this.dataTypeName, value); }
}
[Display(Description = "Access to Register Data.", Name = "Data Access", GroupName = "Data")]
public RegisterDataAccess AccessToData
{
get { return this.accessToData; }
set { this.SetProperty(ref this.accessToData, value); }
}
/// <summary>
/// Parent group whose ChildProfileElenents collection comprises this Register instance.
/// </summary>
[Browsable(false)]
public Group Parent
{
get { return this.parent; }
set { this.parent = value; }
}
#endregion
}
Where [Display(Description = "description_string", Name = "name_string")] is from System.ComponentModel.DataAnnotations namespace. Here is RegisterDataAccess enumeration which is the type of accessToData field and AccessToData property in Register class:
public enum RegisterDataAccess
{
/// <summary>
/// Access to data in register is read-only.
/// </summary>
Read,
/// <summary>
/// Access to data in register is write-only.
/// </summary>
Write,
/// <summary>
/// Read and write access to data in register.
/// </summary>
Read_Write
}
Below is serializeProfile generic method definition in DeviceProfileViewModel class. This method executes XML serialization:
public class DeviceProfileViewModel : BindableBase, IConfirmNavigationRequest
{
. . . . . . .
private string PathToXmlRepository;
private string XmlRepositoryFileName = "XmlRepository.XML";
private Group _profileTreeRoot;
public Group ProfileTreeRoot
{
get { return this._profileTreeRoot; }
set { this.SetProperty(ref this._profileTreeRoot, value); }
}
. . . . . . .
public DeviceProfileViewModel()
{
. . . . . . .
this.ProfileTreeRoot = new Group();
this.ProfileTreeRoot.ChildProfileElenents.CollectionChanged += this.ChildProfileElenents_CollectionChanged;
this.PathToXmlRepository = Path.GetFullPath("../../XML_DeviseProfileRepository");
. . . . . . .
}
/// <summary>
/// Executes XML serialization.
/// </summary>
/// <typeparam name="T">Type of serialized element</typeparam>
/// <param name="parameter">Serialized element itself</param>
private void serializeProfile<T>(T parameter)
{
string pathToXml = Path.Combine(this.PathToXmlRepository, this.XmlRepositoryFileName);
if (File.Exists(pathToXml))
File.Delete(pathToXml);
XmlSerializer xs = new XmlSerializer(typeof(T));
using (StreamWriter wr = new StreamWriter(pathToXml))
{
xs.Serialize(wr, parameter);
}
}
. . . . . . . .
}
Below is serializeProfile() method call in DeviceProfileViewModel class:
ObservableCollection<ProfileElementType> coll = new ObservableCollection<ProfileElementType>(this.ProfileTreeRoot.ChildProfileElenents);
this.serializeProfile(coll);
I do assignment above because this.ProfileTreeRoot.ChildProfileElenents ObservableCollection is used in data binding as ItemsSource for telerik:RadTreeView in the view. You can see a device profile tree (group and registers) on the picture below:
So this.ProfileTreeRoot here is the instance of Group class. Execution of
xs.Serialize(wr, parameter);
line of code in serializeProfile() method throws InvalideOperationException exception in System.Xml.dll and an empty XML file is created in the specified path. What should I do to eliminate this error? Your help will be greatly appreciated. HELP me please serialize such a collection to XML file!!!
来源:https://stackoverflow.com/questions/37058259/why-is-invalideoperationexception-thrown-when-i-try-to-serialize-to-xml-an-obser