C# ApplicationSettingsBase为自定义集合写入空标记
我已经断断续续地为此奋斗了好几天了。我需要存储一组自定义对象作为用户设置的一部分。基于谷歌的大量工作,从C# ApplicationSettingsBase为自定义集合写入空标记,c#,.net,wpf,serialization,application-settings,C#,.net,Wpf,Serialization,Application Settings,我已经断断续续地为此奋斗了好几天了。我需要存储一组自定义对象作为用户设置的一部分。基于谷歌的大量工作,从ApplicationSettingsBase构建一个preferences类似乎是一种合适的方法。我遇到的问题是,只要我尝试存储自定义类型的集合,就不会为该属性保存任何数据。如果我坚持使用基本类型的集合,例如字符串,那么事情就会正常工作。我有一个单独的概念验证项目,在过去的一天里,我一直在与之合作,以隔离到这个问题 此项目由一个WPF窗口组成,该窗口带有一个列表框和两个按钮“+”和“-“。我
ApplicationSettingsBase
构建一个preferences类似乎是一种合适的方法。我遇到的问题是,只要我尝试存储自定义类型的集合,就不会为该属性保存任何数据。如果我坚持使用基本类型的集合,例如字符串,那么事情就会正常工作。我有一个单独的概念验证项目,在过去的一天里,我一直在与之合作,以隔离到这个问题
此项目由一个WPF窗口组成,该窗口带有一个列表框和两个按钮“+”和“-“。我有一个Prefs类,它有三个属性定义不同类型的集合。在我的窗口代码中,我将listbox绑定到其中一个列表,并且按钮可以向列表添加或从列表中删除项目。关闭窗口应将列表的内容保存到当前用户的users.config文件中。重新打开它应显示已保存列表的内容
如果我使用List1(ObservableCollection
)并单击+按钮几次,然后关闭窗口,数据将正确保存到user.config。但是如果我更改并使用List2(ObservableCollection
)或List3(FooCollection
)我只是以一个空的值标记结束。我尝试实现ISerializable
和IXmlSerializable
,试图在不改变行为的情况下使其正常工作。事实上,在调试模式下运行并带有断点时,显示调用save方法时集合包含数据,但序列化接口方法你从来没有被叫过
我错过了什么
更新:我已经改变了我的方法,暂时将数据与user.config一起写入另一个文件,以便我可以在应用程序的其他部分取得一些进展。但我仍然想知道为什么application settings base无法记录我的收集数据
这是所有相关的代码,如果有人认为一个推荐的部分很重要,我会把它重新添加到帖子中
在向每个列表属性添加两个元素后返回user.config
<setting name="List1" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>0</string>
<string>1</string>
<string>2</string>
</ArrayOfString>
</value>
</setting>
<setting name="List2" serializeAs="Xml">
<value />
</setting>
<setting name="List3" serializeAs="Xml">
<value />
</setting>
高级班
class Prefs : ApplicationSettingsBase
{
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute(null)]
public System.Collections.ObjectModel.ObservableCollection<string> List1
{
get
{
System.Collections.ObjectModel.ObservableCollection<string> Value = this["List1"] as System.Collections.ObjectModel.ObservableCollection<string>;
if (Value == null)
{
Value = new System.Collections.ObjectModel.ObservableCollection<string>();
this["List1"] = Value;
}
return Value;
}
}
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute(null)]
public System.Collections.ObjectModel.ObservableCollection<Foo> List2
{
get
{
System.Collections.ObjectModel.ObservableCollection<Foo> Value = this["List2"] as System.Collections.ObjectModel.ObservableCollection<Foo>;
if (Value == null)
{
Value = new System.Collections.ObjectModel.ObservableCollection<Foo>();
this["List2"] = Value;
}
return Value;
}
}
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute(null)]
public FooCollection List3
{
get
{
FooCollection Value = this["List3"] as FooCollection;
if (Value == null)
{
Value = new FooCollection();
this["List3"] = Value;
}
return Value;
}
}
}
和FoodCollection类
[Serializable()]
class FooCollection : ICollection<Foo>, System.ComponentModel.INotifyPropertyChanged, INotifyCollectionChanged, ISerializable, IXmlSerializable
{
List<Foo> Items;
private const string PropName_Items = "Items";
public FooCollection()
{
Items = new List<Foo>();
}
public Foo this[int index]
{
/***Omitted for space***/
}
#region ICollection<Foo> Members
/***Omitted for space***/
#endregion
public void RemoveAt(int index)
{
/***Omitted for space***/
}
#region IEnumerable Members
/***Omitted for space***/
#endregion
#region INotifyCollectionChanged Members
/***Omitted for space***/
#endregion
#region INotifyPropertyChanged Members
/***Omitted for space***/
#endregion
#region ISerializable Members
public FooCollection(SerializationInfo info, StreamingContext context)
{
this.Items = (List<Foo>)info.GetValue(FooCollection.PropName_Items, typeof(List<Foo>));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(FooCollection.PropName_Items, this.Items);
}
#endregion
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer FooSerializer = new XmlSerializer(typeof(Foo));
reader.MoveToContent();
bool Empty = reader.IsEmptyElement;
reader.ReadStartElement();
if (!Empty)
{
if (reader.IsStartElement(FooCollection.PropName_Items))
{
reader.ReadStartElement();
while (reader.IsStartElement("Foo"))
{
this.Items.Add((Foo)FooSerializer.Deserialize(reader));
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer FooSerializer = new XmlSerializer(typeof(Foo));
writer.WriteStartElement(FooCollection.PropName_Items);
foreach (Foo Item in Items)
{
writer.WriteStartElement("Foo");
FooSerializer.Serialize(writer, Item);
writer.WriteEndElement();//"Foo"
}
writer.WriteEndElement(); //FooCollection.PropName_Items
}
#endregion
}
[Serializable()]
FooCollection类:ICollection、System.ComponentModel.INotifyPropertyChanged、INotifyCollectionChanged、ISerializable、IXmlSerializable
{
清单项目;
private const string PropName_Items=“Items”;
公共图书馆馆藏()
{
项目=新列表();
}
public Foo this[int index]
{
/***为空间省略***/
}
#区域i集合成员
/***为空间省略***/
#端区
公共无效删除(整数索引)
{
/***为空间省略***/
}
#区域可数成员
/***为空间省略***/
#端区
#区域INotifyCollectionChanged成员
/***为空间省略***/
#端区
#区域INotifyProperty更改成员
/***为空间省略***/
#端区
#区域ISerializable成员
公共FooCollection(SerializationInfo信息、StreamingContext上下文)
{
this.Items=(List)info.GetValue(FooCollection.PropName_Items,typeof(List));
}
public void GetObjectData(SerializationInfo信息、StreamingContext上下文)
{
info.AddValue(FooCollection.PropName\u Items,this.Items);
}
#端区
#区域IXmlSerializable成员
public System.Xml.Schema.XmlSchema GetSchema()
{
返回null;
}
public void ReadXml(System.Xml.XmlReader)
{
XmlSerializer FooSerializer=新的XmlSerializer(typeof(Foo));
reader.MoveToContent();
bool Empty=reader.isemptyelment;
reader.ReadStartElement();
如果(!空)
{
if(reader.IsStartElement(FooCollection.PropName_Items))
{
reader.ReadStartElement();
while(reader.IsStartElement(“Foo”))
{
this.Items.Add((Foo)FooSerializer.Deserialize(reader));
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
public void WriteXml(System.Xml.XmlWriter)
{
XmlSerializer FooSerializer=新的XmlSerializer(typeof(Foo));
writer.writeStarteElement(FooCollection.PropName\u项);
foreach(项目中的Foo项目)
{
writer.writeStarteElement(“Foo”);
序列化(writer,Item);
writer.WriteEndElement();/“Foo”
}
writer.WriteEndElement();//FooCollection.PropName_项
}
#端区
}
我也为一个非常类似的问题挣扎了两天,但现在我发现了一个缺失的链接,这可能会有所帮助。
如果你和我的情况实际上相似,那么
类“Foo”和“FooCollection”需要显式公开
我假设,在List2(ObservableCollection
)和List3(FooCollection)
的情况下,.NET运行到IXmlSerializable
,这在某种程度上需要显式的公共访问(跨越自己程序集的边界)
相反的选项List1(ObservableCollection
)似乎是在一个平面字符串类型转换上运行的,它对(内部)类“Foo”很满意
(来自ApplicationsettingsBase文档:
ApplicationSettingsBase
使用两种主要机制来
序列化设置:
1) 如果存在可以与字符串进行转换的TypeConverter
,我们就使用它。
2) 如果没有,我们就回到XmlSerializer
)
亲切问候,,
Rudy我也有一个类似的问题,我设法解决了,但我没有使用
可观察集合
,而是使用一个普通的列表
,列
作为我的一个类,包含为公共成员:string、int和bool,w
class Prefs : ApplicationSettingsBase
{
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute(null)]
public System.Collections.ObjectModel.ObservableCollection<string> List1
{
get
{
System.Collections.ObjectModel.ObservableCollection<string> Value = this["List1"] as System.Collections.ObjectModel.ObservableCollection<string>;
if (Value == null)
{
Value = new System.Collections.ObjectModel.ObservableCollection<string>();
this["List1"] = Value;
}
return Value;
}
}
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute(null)]
public System.Collections.ObjectModel.ObservableCollection<Foo> List2
{
get
{
System.Collections.ObjectModel.ObservableCollection<Foo> Value = this["List2"] as System.Collections.ObjectModel.ObservableCollection<Foo>;
if (Value == null)
{
Value = new System.Collections.ObjectModel.ObservableCollection<Foo>();
this["List2"] = Value;
}
return Value;
}
}
[UserScopedSettingAttribute()]
[DefaultSettingValueAttribute(null)]
public FooCollection List3
{
get
{
FooCollection Value = this["List3"] as FooCollection;
if (Value == null)
{
Value = new FooCollection();
this["List3"] = Value;
}
return Value;
}
}
}
[Serializable()]
class Foo : System.ComponentModel.INotifyPropertyChanged, ISerializable, IXmlSerializable
{
private string _Name;
private const string PropName_Name = "Name";
public string Name
{
get { return this._Name; }
set
{
if (value != this._Name)
{
this._Name = value;
RaisePropertyChanged(Foo.PropName_Name);
}
}
}
public override string ToString()
{
return Name;
}
public Foo() { }
public Foo(string name)
{
this._Name = name;
}
#region INotifyPropertyChanged Members
/***Omitted for space***/
#endregion
#region ISerializable Members
public Foo(SerializationInfo info, StreamingContext context)
{
this._Name = (string)info.GetValue(Foo.PropName_Name, typeof(string));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(Foo.PropName_Name, this._Name);
}
#endregion
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
reader.MoveToContent();
_Name = reader.GetAttribute(Foo.PropName_Name);
bool Empty = reader.IsEmptyElement;
reader.ReadStartElement();
if (!Empty)
{
reader.ReadEndElement();
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteAttributeString(Foo.PropName_Name, _Name);
}
#endregion
}
[Serializable()]
class FooCollection : ICollection<Foo>, System.ComponentModel.INotifyPropertyChanged, INotifyCollectionChanged, ISerializable, IXmlSerializable
{
List<Foo> Items;
private const string PropName_Items = "Items";
public FooCollection()
{
Items = new List<Foo>();
}
public Foo this[int index]
{
/***Omitted for space***/
}
#region ICollection<Foo> Members
/***Omitted for space***/
#endregion
public void RemoveAt(int index)
{
/***Omitted for space***/
}
#region IEnumerable Members
/***Omitted for space***/
#endregion
#region INotifyCollectionChanged Members
/***Omitted for space***/
#endregion
#region INotifyPropertyChanged Members
/***Omitted for space***/
#endregion
#region ISerializable Members
public FooCollection(SerializationInfo info, StreamingContext context)
{
this.Items = (List<Foo>)info.GetValue(FooCollection.PropName_Items, typeof(List<Foo>));
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(FooCollection.PropName_Items, this.Items);
}
#endregion
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer FooSerializer = new XmlSerializer(typeof(Foo));
reader.MoveToContent();
bool Empty = reader.IsEmptyElement;
reader.ReadStartElement();
if (!Empty)
{
if (reader.IsStartElement(FooCollection.PropName_Items))
{
reader.ReadStartElement();
while (reader.IsStartElement("Foo"))
{
this.Items.Add((Foo)FooSerializer.Deserialize(reader));
}
reader.ReadEndElement();
}
reader.ReadEndElement();
}
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer FooSerializer = new XmlSerializer(typeof(Foo));
writer.WriteStartElement(FooCollection.PropName_Items);
foreach (Foo Item in Items)
{
writer.WriteStartElement("Foo");
FooSerializer.Serialize(writer, Item);
writer.WriteEndElement();//"Foo"
}
writer.WriteEndElement(); //FooCollection.PropName_Items
}
#endregion
}