保存设置时未保存OrderedDictionary

本文关键字:保存 OrderedDictionary 设置 | 更新日期: 2023-09-27 18:26:16

在我的应用程序中,我实现了一些Controls,以不同的方式浏览数据。在每个控件中,我都会显示一个TreeView,以允许用户从一个文件夹转到另一个文件夹。

我希望我的控件以一种通用的方式"记住"最后一个选定的树(我的意思是,如果将来我添加另一个控件,我不想做很多调整)。所以我在设置中添加了一个OrderedDictionary。我使用控件的类型名称作为键,使用节点的路径作为值。

由于我无法设置此字典的默认值,我使用了以下技巧:

设置:

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;
    }
}

每次添加/更新值时,我都会调用Saveuser.config文件的时间戳会更改,但内容保持不变:

<setting name="LastsPaths" serializeAs="Xml">
    <value />
</setting>

它不适用于:

  • 应用程序处于调试模式
  • 应用程序处于发布模式
  • 已安装应用程序

我该怎么解决这个问题?

保存设置时未保存OrderedDictionary

似乎OrderedDictionary(以及一般的通用字典)是不可XML序列化的。

您可以将它包装在另一个手动执行序列化的类中。这样就不会直接向XML序列化程序公开字典。您必须实现IXmlSerializable才能实现这一点。

这可能足以让您开始。这将继承Save调用期间所需的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方法进行tweek,并填写GetSchema()的逻辑。