我正在尝试使用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将起作用。我对序列化不太熟悉。
即使你可以在设置中存储TreeNode
,也不能将反序列化的节点分配给SelectedNode
的TreeView
属性。 TreeNode
是引用类型,因为从设置加载的实例与树中存在的实例不同,所以赋值没有意义,也不起作用。它已经在Taw的comment的b点中提到过了。
要在设置中保留选定节点,最好依赖字符串属性。您至少有两个选择:
Name
属性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;
}
}
这里发生的是调用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的引用。