保存设置时未保存 OrderedDictionary
OrderedDictionary is not being saved when saving Settings
在我的应用程序中,我实现了一些 Controls
以不同方式浏览数据。在每个控件中,我显示一个 TreeView
以允许用户从一个文件夹转到另一个文件夹。
我希望我的控件以通用方式 "remember" 最后选择的树(我的意思是,如果将来我添加另一个控件,我不想做很多改编) .所以我在设置中添加了一个OrderedDictionary
。我使用控件的类型名称作为键,使用节点的路径作为值。
因为我无法为这本词典设置默认值,所以我使用了这个技巧:
Settings.cs :
public OrderedDictionary Paths
{
get
{
return LastsPaths ?? (LastsPaths = new OrderedDictionary());
}
set
{
this["LastsPaths"] = value;
}
}
Settings.Designer.cs:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.OrderedDictionary LastsPaths {
get {
return ((global::System.Collections.Specialized.OrderedDictionary)(this["LastsPaths"]));
}
set {
this["LastsPaths"] = value;
}
}
每次我 add/update 一个值时,我都会调用 Save
,user.config
文件时间戳发生变化,但内容保持不变:
<setting name="LastsPaths" serializeAs="Xml">
<value />
</setting>
不适用于:
- 应用处于调试模式;
- 应用处于发布模式;
- 已安装应用程序。
我该如何解决这个问题?
似乎 OrderedDictionary
(以及一般的通用词典)are not XML serializable。
您可以将其包装在另一个手动执行序列化的 class 中。这样,您就不会将字典直接公开给 XML 序列化程序。您必须实施 IXmlSerializable
才能实现此目的。
这可能足以让您入门。这继承了保存调用期间需要的 IXMLSerializable
。
[XmlRoot("PreviouslyVisitedPaths")]
public class PreviouslySelectedPaths : OrderedDictionary, IXmlSerializable
{
#region Implementation of IXmlSerializable
/// <summary>
/// This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> to the class.
/// </summary>
/// <returns>
/// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> method.
/// </returns>
public XmlSchema GetSchema()
{
return null;
}
/// <summary>
/// Generates an object from its XML representation.
/// </summary>
/// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized. </param>
public void ReadXml(XmlReader reader)
{
var keySerializer = new XmlSerializer(typeof(object));
var valueSerializer = new XmlSerializer(typeof(object));
var wasEmpty = reader.IsEmptyElement;
reader.Read();
if(wasEmpty)
{
return;
}
while(reader.NodeType != XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
var key = keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
var value = valueSerializer.Deserialize(reader);
reader.ReadEndElement();
Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
/// <summary>
/// Converts an object into its XML representation.
/// </summary>
/// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized. </param>
public void WriteXml(XmlWriter writer)
{
var keySerializer = new XmlSerializer(typeof(object));
var valueSerializer = new XmlSerializer(typeof(object));
foreach(var key in Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
var value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
#endregion
}
}
然后您可以将代码更改为:
public PreviouslySelectedPaths Paths
{
get
{
return LastsPaths ?? (LastsPaths = new PreviouslySelectedPaths());
}
set
{
this["LastsPaths"] = value;
}
}
您还需要 LastsPaths
输入 PreviouslySelectedPaths
。
这只是为了让您开始使用,您可能需要调整 IXMLSerializable
方法并为 GetSchema()
填写逻辑。
在我的应用程序中,我实现了一些 Controls
以不同方式浏览数据。在每个控件中,我显示一个 TreeView
以允许用户从一个文件夹转到另一个文件夹。
我希望我的控件以通用方式 "remember" 最后选择的树(我的意思是,如果将来我添加另一个控件,我不想做很多改编) .所以我在设置中添加了一个OrderedDictionary
。我使用控件的类型名称作为键,使用节点的路径作为值。
因为我无法为这本词典设置默认值,所以我使用了这个技巧:
Settings.cs :
public OrderedDictionary Paths
{
get
{
return LastsPaths ?? (LastsPaths = new OrderedDictionary());
}
set
{
this["LastsPaths"] = value;
}
}
Settings.Designer.cs:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.Specialized.OrderedDictionary LastsPaths {
get {
return ((global::System.Collections.Specialized.OrderedDictionary)(this["LastsPaths"]));
}
set {
this["LastsPaths"] = value;
}
}
每次我 add/update 一个值时,我都会调用 Save
,user.config
文件时间戳发生变化,但内容保持不变:
<setting name="LastsPaths" serializeAs="Xml">
<value />
</setting>
不适用于:
- 应用处于调试模式;
- 应用处于发布模式;
- 已安装应用程序。
我该如何解决这个问题?
似乎 OrderedDictionary
(以及一般的通用词典)are not XML serializable。
您可以将其包装在另一个手动执行序列化的 class 中。这样,您就不会将字典直接公开给 XML 序列化程序。您必须实施 IXmlSerializable
才能实现此目的。
这可能足以让您入门。这继承了保存调用期间需要的 IXMLSerializable
。
[XmlRoot("PreviouslyVisitedPaths")]
public class PreviouslySelectedPaths : OrderedDictionary, IXmlSerializable
{
#region Implementation of IXmlSerializable
/// <summary>
/// This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> to the class.
/// </summary>
/// <returns>
/// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> method.
/// </returns>
public XmlSchema GetSchema()
{
return null;
}
/// <summary>
/// Generates an object from its XML representation.
/// </summary>
/// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized. </param>
public void ReadXml(XmlReader reader)
{
var keySerializer = new XmlSerializer(typeof(object));
var valueSerializer = new XmlSerializer(typeof(object));
var wasEmpty = reader.IsEmptyElement;
reader.Read();
if(wasEmpty)
{
return;
}
while(reader.NodeType != XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
var key = keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
var value = valueSerializer.Deserialize(reader);
reader.ReadEndElement();
Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
/// <summary>
/// Converts an object into its XML representation.
/// </summary>
/// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized. </param>
public void WriteXml(XmlWriter writer)
{
var keySerializer = new XmlSerializer(typeof(object));
var valueSerializer = new XmlSerializer(typeof(object));
foreach(var key in Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key);
writer.WriteEndElement();
writer.WriteStartElement("value");
var value = this[key];
valueSerializer.Serialize(writer, value);
writer.WriteEndElement();
writer.WriteEndElement();
}
#endregion
}
}
然后您可以将代码更改为:
public PreviouslySelectedPaths Paths
{
get
{
return LastsPaths ?? (LastsPaths = new PreviouslySelectedPaths());
}
set
{
this["LastsPaths"] = value;
}
}
您还需要 LastsPaths
输入 PreviouslySelectedPaths
。
这只是为了让您开始使用,您可能需要调整 IXMLSerializable
方法并为 GetSchema()
填写逻辑。