使用TreeNode作为用户设置

时间:2018-11-14 20:57:50

标签: c# .net winforms treeview settings

我正在尝试使用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将起作用。我只是不太了解序列化。

2 个答案:

答案 0 :(得分:3)

即使可以在设置中存储TreeNode,也不能将反序列化的节点分配给SelectedNode的{​​{1}}属性。 TreeView是引用类型,并且由于您从设置加载的实例与树中存在的实例不同,因此该分配没有任何意义,并且将不起作用。 Taw在comment中的b点已经提到过。

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

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

选项1-名称属性

每个FullPath具有一个TreeNode属性,可用于查找该节点。

  • 在创建节点时为节点分配唯一键:

    Name
  • 保存数据时,将treeView1.Nodes.Add("key", "text"); 存储在设置中。

  • 要根据设置选择节点:

    treeView1.SelectedNode.Name

选项2-FullPath属性

每个treeView1.SelectedNode = treeView1.Nodes.Find("some key", true).FirstOrDefault(); 都有一个TreeNode,它获取从根树节点到当前树节点的路径。

  

路径由必须是所有树节点的标签组成   从根树节点开始导航到该树节点。的   节点标签由在   包含以下内容的TreeView控件的PathSeparator属性   节点。

  • 创建节点时,无需进行特殊设置。每个节点都有FullPath

  • 保存数据时,将FullPath存储在设置中。

  • 要根据设置选择节点:

    treeView1.SelectedNode.FullPath

在上面的代码中,treeView1.SelectedNode = treeView1.Nodes.FindByPath(@"path\to\the\node"); 是一种扩展方法,您可以创建该扩展方法以按路径查找ndoe:

FindByPath

答案 1 :(得分: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接口,这是为{{ 1}}类。在某些时候它会在内部爆炸,并吞下错误,而是留下一个空值。

要解决此问题,您可以使用适当的序列化方法(即格式化程序)对TreeNode对象进行序列化。格式化程序尊重TreeNode接口。然后,您可以将结果ISerializable存储在设置中,以后再读取并将它具体化到节点中:

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的引用。