使用TreeNode作为用户设置

问题描述 投票:2回答:2

我正在尝试使用TreeNode(System.Windows.Forms.TreeNode)作为我的一个应用程序的用户设置。

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

然后在应用程序加载我尝试使用该设置

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

但无论我做什么,当我重新加载应用程序时,Properties.Settings.Default.SelectedTreeNode总是为null。

我也试过使用一个Object并转换为TreeNode,但这也不起作用。

我真的不想为此使用字符串设置,并且如果可能的话希望坚持使用TreeNode,但是如果无法使用TreeNode,则序列化的TreeNode将起作用。我对序列化不太熟悉。

c# .net winforms treeview settings
2个回答
3
投票

即使你可以在设置中存储TreeNode,也不能将反序列化的节点分配给SelectedNodeTreeView属性。 TreeNode是引用类型,因为从设置加载的实例与树中存在的实例不同,所以赋值没有意义,也不起作用。它已经在Taw的comment的b点中提到过了。

要在设置中保留选定节点,最好依赖字符串属性。您至少有两个选择:

  1. 在设置中存储节点的Name属性
  2. 在设置中存储节点的FullPath属性

选项1 - 名称属性

每个TreeNode都有一个Name属性,可用于查找节点。

  • 在创建节点时为节点分配唯一键: treeView1.Nodes.Add("key", "text");
  • 保存数据时,请将treeView1.SelectedNode.Name存储在设置中。
  • 要根据设置选择节点: treeView1.SelectedNode = treeView1.Nodes.Find("some key", true).FirstOrDefault();

选项2 - FullPath属性

每个TreeNode都有一个FullPath,它获取从根树节点到当前树节点的路径。

该路径由从根树节点开始必须导航到达此树节点的所有树节点的标签组成。节点标签由包含此节点的TreeView控件的PathSeparator属性中指定的分隔符分隔。

  • 创建节点时,您无需进行特殊设置。每个节点都有FullPath
  • 保存数据时,请将treeView1.SelectedNode.FullPath存储在设置中。
  • 要根据设置选择节点: treeView1.SelectedNode = treeView1.Nodes.FindByPath(@"path\to\the\node");

在上面的代码中,FindByPath是一个扩展方法,您可以创建它来按路径查找ndoe:

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

0
投票

这里发生的是调用Save方法尝试序列化节点,以便将其存储在User.config文件中。如果您检查此文件,您会发现该节点为空:

<?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>

原因可能是Save方法正在尝试使用XmlSerializer类进行序列化,ISerializable类不遵循TreeNode接口,这是为TreeNode类实现序列化的方式。它会在某个时刻内部爆炸并吞下错误,而是留下一个空值。

你可以做些什么来解决ISerializable对象使用适当的序列化方法,这是一个格式化程序。 Formatters尊重string界面。然后,您可以将生成的if (string.IsNullOrWhiteSpace(Properties.Settings.Default.SelectedTreeNode)) { Properties.Settings.Default.SelectedTreeNode = SerializeNode(treeView.SelectedNode); Properties.Settings.Default.Save(); } 存储在设置中,然后将其读取并将其具体化到节点中:

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

在应用程序加载:

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

序列化功能:

SoapFormatter

对于这个答案,我正在使用System.Runtime.Serialization.Formatters.Soap类。您需要添加对qazxswpoi的引用。

© www.soinside.com 2019 - 2024. All rights reserved.