Использование TreeNode в качестве пользовательской настройки - PullRequest
0 голосов
/ 14 ноября 2018

Я пытаюсь использовать 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 всегда пусто, когда я перезагружаю приложение.

Я также пытался использовать Object и приведение к TreeNode, но это тоже не работает.

Я действительно не хочу использовать строковые настройки для этого и хочу придерживаться TreeNode, если это возможно, но сериализованный TreeNode будет работать, если нет способа использовать TreeNode. Я просто не слишком знаком с сериализацией.

Ответы [ 2 ]

0 голосов
/ 15 ноября 2018

Даже если вы можете сохранить TreeNode в настройках, вы не можете назначить десериализованный узел свойству SelectedNode свойства TreeView.TreeNode является ссылочным типом, и поскольку экземпляр, который вы загружаете из настроек, не является тем же экземпляром, который существует в дереве, назначение не имеет смысла и не будет работать.Это уже упоминалось в пункте b в комментарии от Taw.

Чтобы сохранить выбранный узел в настройках, лучше полагаться на строковое свойство.У вас есть как минимум две опции:

  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, который получаетпуть от корневого узла дерева до текущего узла дерева.

Путь состоит из меток всех узлов дерева, по которым нужно перейти, чтобы достичь этого узла дерева, начиная с корневого узла дерева.Метки узлов разделяются символом-разделителем, указанным в свойстве PathSeparator элемента управления TreeView, который содержит этот узел.

  • При создании узла вам не нужно делать специальныенастройки.Каждый узел имеет 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 голосов
/ 15 ноября 2018

Здесь происходит то, что вызов метода 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. Затем вы можете сохранить полученный 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.

...