Using a TreeNode as a User Setting

瘦欲@ 提交于 2020-01-23 16:21:32

问题


I'm trying to use a TreeNode (System.Windows.Forms.TreeNode) as a user setting for one of my applications.

if(treeView.SelectedNode != null)
{
    Properties.Settings.Default.SelectedTreeNode = treeView.SelectedNode;
    Properties.Settings.Default.Save();
}

Then on Application Load I'm trying to use that Setting

if (Properties.Settings.Default.SelectedTreeNode != null)
    treeView.SelectedNode= Properties.Settings.Default.SelectedTreeNode;

but no matter what I do, Properties.Settings.Default.SelectedTreeNode is always null when I reload the application.

I've also tried just using an Object and casting to a TreeNode, but that doesn't work either.

I really don't want to use string Settings for this, and want to stick with TreeNode if possible, but a serialized TreeNode would work if there is no way to use a TreeNode. I'm just not too familiar with Serialization.


回答1:


Even if you could store TreeNode in settings, you cannot assign deserialized node to SelectedNode property of TreeView. TreeNode is reference type and since the instance which you load from setting is not the same instance which exists in the tree, the assignment doesn't make sense and will not work. It's already mentioned in point b in the comment by Taw.

To preserve selected node in settings, it's better to rely on a string property. You have at least two options:

  1. Store Name property of the node in settings
  2. Store FullPath property of the node in settings

Option 1 - Name Property

Each TreeNode has a Name property which can be used to find the node.

  • Assign a unique key to nodes when creating them:

    treeView1.Nodes.Add("key", "text");
    
  • When saving data, store treeView1.SelectedNode.Name in settings.

  • To select the node based on the settings:

    treeView1.SelectedNode = treeView1.Nodes.Find("some key", true).FirstOrDefault();
    

Option 2 - FullPath Property

Each TreeNode has a FullPath which gets the path from the root tree node to the current tree node.

The path consists of the labels of all the tree nodes that must be navigated to reach this tree node, starting at the root tree node. The node labels are separated by the delimiter character specified in the PathSeparator property of the TreeView control that contains this node.

  • When creating node, you don't need to do special settings. Every node has FullPath.

  • When saving data, store treeView1.SelectedNode.FullPath in settings.

  • To select the node based on the settings:

    treeView1.SelectedNode = treeView1.Nodes.FindByPath(@"path\to\the\node");
    

In above code, FindByPath is an extension method which you can create to find the ndoe by path:

using System.Windows.Forms;
public static class TreeViewExtensiona
{
    public static TreeNode FindByPath(this TreeNodeCollection nodes, string path)
    {
        TreeNode found = null;
        foreach (TreeNode n in nodes)
        {
            if (n.FullPath == path)
                found = n;
            else
                found = FindByPath(n.Nodes, path);
            if (found != null)
                return found;
        }
        return null;
    }
}



回答2:


What's happening here is that the call to the Save method attempts to serialize the node in order to store it in the User.config file. If you inspect this file, you will find that the node is empty:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <sectionGroup name="userSettings" type="..." >
            <section name="SomeProject.Properties.Settings" type="..." allowExeDefinition="MachineToLocalUser" requirePermission="false" />
        </sectionGroup>
    </configSections>
    <userSettings>
        <SomeProject.Properties.Settings>
            <setting name="SelectedTreeNode" serializeAs="Xml">
                <value /> <!-- The node was not serialized! -->
            </setting>
        </SomeProject.Properties.Settings>
    </userSettings>
</configuration>

The reason is probably that the Save method is attempting the serialization using the XmlSerializer class, which does not respect the ISerializable interface, which is how serialization is implemented for the TreeNode class. It blows up internally at some point and it swallows the error, leaving an empty value instead.

What you can do to get around this is serialize the TreeNode object using a proper serialization method, which is a formatter. Formatters respect the ISerializable interface. You can then store the resulting string in the setting and later read it and materialize it into the node:

if (string.IsNullOrWhiteSpace(Properties.Settings.Default.SelectedTreeNode))
{                
    Properties.Settings.Default.SelectedTreeNode = SerializeNode(treeView.SelectedNode);
    Properties.Settings.Default.Save();
}

On application load:

if (Properties.Settings.Default.SelectedTreeNode != null)
    treeView.SelectedNode= DeserializeNode(Properties.Settings.Default.SelectedTreeNode);

The serialization functions:

public string SerializeNode(TreeNode node)
{
    var formatter = new SoapFormatter();
    using (var stream = new MemoryStream())
    {
        formatter.Serialize(stream, node);
        stream.Position = 0;
        using (var reader = new StreamReader(stream))
        {
            var serialized = reader.ReadToEnd();
            return serialized;
        }
    }
}

public TreeNode DeserializeNode(string nodeString)
{
    var formatter = new SoapFormatter();
    using (var stream = new MemoryStream())
    {
        using (var writer = new StreamWriter(stream))
        {
            writer.Write(nodeString);
            writer.Flush();
            stream.Position = 0;
            var node = (TreeNode)formatter.Deserialize(stream);
            return node;
        }                
    }          
}

For this answer, I am using the SoapFormatter class. You will need to add a reference to System.Runtime.Serialization.Formatters.Soap.



来源:https://stackoverflow.com/questions/53308604/using-a-treenode-as-a-user-setting

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!