Сохранение и восстановление состояния узлов древовидной структуры элемента управления «TreeView»


      В данной статье рассмотрено создание методов сохранения и восстановления состояния узлов древовидной структуры элемента управления «TreeView», после обновления данных или изменения состояния узлов.
      Создайте проект «Windows Form» в «Microsoft Visual Studio» и добавьте на главную форму вашего проекта следующие элементы управления:
  • «TreeView 1»;
  • «Button 1» - кнопка сохранения состояния;
  • «Button 2» - кнопка загрузки состояния.
У вас получится приведенный ниже пример.
      Для заполнения элемента управления «TreeView» данными, воспользуемся приведенным ниже листингом. Сделайте двойной клик левой клавишей мыши по любому свободному месту главной формы, вы перейдете в редактор кода с установкой курсора в автоматически созданном методе «Form1_Load», события «Load», выполняющегося при загрузке формы. Вставьте в тело данного метода приведенный ниже листинг.
for (int i = 0; i < 5; i++)
{
    treeView1.Nodes.Add(
        i.ToString(),
        "Узел " + i.ToString());

    for (int ii = i; ii < 5; ii++)
    {
        treeView1.Nodes[i].Nodes.Add(
            ii.ToString(),
            "Под узел " + ii.ToString());                   
    }
}
      Перейдите в конструктор главной формы и сделайте двойной клик левой клавишей мыши по элементу управления «button1». Вы перейдете в редактор кода с автоматической установкой курсора в созданном методе «button1_Click», события «Click», возникающего при нажатии на кнопку. Добавьте приведенный ниже листинг, реализующий поиск узлов и сохранения их состояния в словарь, в тело данного метода.
foreach (TreeNode nodeToSave in treeView1.Nodes)
{
    SaveExpandedStates(nodeToSave);
}
      Снова перейдите в конструктор главной формы и проделайте туже операцию с элементом управления «button2», с добавлением приведенного ниже листинга поиска узлов и восстановления их состояния, в тело данного метода.
foreach (TreeNode nodeToRestore in treeView1.Nodes)
{
    RestoreExpandedStates(nodeToRestore);
}
      Для сохранения состояния узла дерева (развернутое/свернутое) будет использоваться словарь (класс Dictionary), который представляет собой сложную структуру данных, позволяющую обеспечить доступ к элементам по ключу. Главное свойство таких словарей, это быстрый поиск на основе ключей. Можно также свободно добавлять и удалять элементы, подобно тому, как это делается в «List».
Словари имеют динамический характер, расширяясь по мере необходимости.
      При сохранении состояния узла дерева и добавлении его в словарь, выполняется проверка существования добавляемого объекта «key» в качестве ключа с использованием метода «ContainsKey()» из класса «Dictionary». Данный метод возвращает логическое значение «true», если вызывающий словарь содержит объект «key» в качестве ключа; а иначе — логическое значение «false». В качестве значения ключа для проверки, передается путь из корневого узла дерева к текущему узлу дерева, которое возвращает свойство «TreeNode.FullPath». В случае если данный ключ отсутствует, он добавляется. Класс словарей так же, как и другие коллекции, предоставляет метод «Add» для добавления элементов. Только в случае словарей в метод «Add» передаются два параметра: ключ и значение. Так как в нашем проекте, ключами является объекты типа «object», а значениями - объекты типа «bool», то словарь в нашем случае будет хранить объекты «KeyValuePair< object, bool>».
Если ключ «key» уже находится в словаре, то его значение не изменяется, и генерируется исключение «ArgumentException».
      При добавлении новой записи в словарь будут передаваться два параметра, в качестве значения ключа «key», будет передается путь из корневого узла дерева к текущему узлу дерева, которое возвращает свойство «TreeNode.FullPath», а значением «value» будет возвращаемое логическое значение свойства «TreeNode.IsExpanded», указывающее, является ли узел дерева в развернутом состоянии. В классе «Dictionary» реализуется приведенный ниже индексатор, определенный в интерфейсе «IDictionary» public TValue this[TKey key] { get; set; } 
      Этот индексатор служит для получения и установки значения элемента коллекции, а также для добавления в коллекцию нового элемента. Но в качестве индекса в данном случае служит ключ элемента, а не сам индекс. 
      Именно с помощью данного индексатора будет присваиваться новое состояние узла дерева, если он уже был добавлен в словарь ранее.
if (!nodeStates.ContainsKey(nodeToSave.FullPath))
{                    
    nodeStates.Add(nodeToSave.FullPath, nodeToSave.IsExpanded);
}
else
{                    
    nodeStates[nodeToSave.FullPath] = nodeToSave.IsExpanded;
}
      Добавьте в листинг главной формы код инициализации нового словаря и метода добавления состояния узлов в словарь.
Dictionary<object, bool> nodeStates = new Dictionary<object, bool>();
private void SaveExpandedStates(TreeNode nodeToSave)
{
    if (nodeToSave != null && nodeToSave.FullPath != null)
    {
        if (!nodeStates.ContainsKey(nodeToSave.FullPath))
        {                    
            nodeStates.Add(nodeToSave.FullPath, nodeToSave.IsExpanded);
        }
        else
        {                    
            nodeStates[nodeToSave.FullPath] = nodeToSave.IsExpanded;
        }
    }

    foreach (TreeNode childNode in nodeToSave.Nodes)
    {
        SaveExpandedStates(childNode);
    }
}
      При восстановлении состояния узла дерева выполняются две проверки, первая на существования ключа в словаре, переменная узла и значение пути из корневого узла дерева к текущему узлу дерева не пустые. Вторая проверка заключается в получении логического значения хранящегося в словаре, указывающего состояние узла. В зависимости от этого значения, выполняется сворачивание или разворачивание узла дерева. Добавьте приведенный ниже метод восстановления состояния дерева, в листинг главной формы.
private void RestoreExpandedStates(TreeNode nodeToRestore)
{
    if (nodeToRestore != null && nodeToRestore.FullPath != null &&
        nodeStates.ContainsKey(nodeToRestore.FullPath))
    {                
        if (nodeStates[nodeToRestore.FullPath])
            nodeToRestore.Expand();
        else
            nodeToRestore.Collapse();
    }

    foreach (TreeNode childNode in nodeToRestore.Nodes)
    {
        RestoreExpandedStates(childNode);
    }
}
      Запустите проект, нажав на клавишу «F5». После успешной компиляции и запуска вашего проекта у вас откроется главная форма проекта с заполненным деревом, тестовыми данными.
      Для проверки работоспособности вашего проекта, разверните несколько узлов и нажмите кнопку «Сохранить», а затем снова измените состояние узлов. Нажмите кнопку «Загрузить», состояние узлов должно вернуться на момент сохранения.

Ссылка для скачивания примера: Яндекс.Диск


1 комментарий:

  1. Здравствуйте! У меня такая ситуация: на карту нанесены маркеры, но при приближении объекта маркеры не перемещаются, хотя масштаб карты меняется

    ОтветитьУдалить

Большая просьба, не писать в комментариях всякую ерунду не по теме!