using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MyUserControls { public partial class HierarchicalTreeView : UserControl { private List propertyHierarchy = new List(); public HierarchicalTreeView() { InitializeComponent(); } // Установка иерархии свойств public void SetPropertyHierarchy(List propertyNames) { if (propertyNames == null) { throw new ArgumentNullException(nameof(propertyNames), "Объект не может быть null."); } foreach (var name in propertyNames) propertyHierarchy.Add(name); } // Параметризованный метод для заполнения дерева public void AddObject(T obj) { if (obj == null) throw new ArgumentNullException(nameof(obj)); // Получаем значение первого свойства из иерархии string initialValue = GetPropertyValue(obj, propertyHierarchy[0]); TreeNode currentNode = FindOrCreateNode(treeView.Nodes, initialValue); // Обходим остальные свойства и строим ветвление for (int i = 1; i < propertyHierarchy.Count; i++) { string nextProperty = propertyHierarchy[i]; string nextValue = GetPropertyValue(obj, nextProperty); currentNode = FindOrCreateNode(currentNode.Nodes, nextValue); } } // Вспомогательный метод для получения значения свойства private string GetPropertyValue(T obj, string propertyName) { // Используем рефлексию для получения значения свойства PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName); if (propertyInfo == null) throw new ArgumentException($"Свойство {propertyName} не найдено в классе {typeof(T).Name}."); object value = propertyInfo.GetValue(obj); return value?.ToString() ?? "null"; // Возвращаем "null" вместо null } // Вспомогательный метод для нахождения или создания узла private TreeNode FindOrCreateNode(TreeNodeCollection nodes, string value) { foreach (TreeNode node in nodes) { if (node.Text.Equals(value, StringComparison.OrdinalIgnoreCase)) { return node; } } TreeNode newNode = new TreeNode(value); nodes.Add(newNode); return newNode; } public T? GetSelectedItem() where T : class, new() { if (treeView.SelectedNode == null) { throw new Exception("There are no selected nodes"); } if (treeView.SelectedNode.Nodes.Count != 0) { throw new Exception("Node is not the end node"); } T result = new T(); Type type = typeof(T); TreeNode treeNode = treeView.SelectedNode; // Перебор узлов сверху вниз, начиная с выбранного узла for (int i = propertyHierarchy.Count - 1; i >= 0 && treeNode != null; i--, treeNode = treeNode.Parent) { // Получаем свойство по названию из propertyHierarchy var property = type.GetProperty(propertyHierarchy[i]); if (property != null && property.CanWrite) { // Сеттим значение свойства из текста узла property.SetValue(result, treeNode.Text); } } // Проверка на выполнение условий: если treeNode не null и i >= 0 (прекращаем заполнение) if (treeNode != null || propertyHierarchy.Count > 0) { return result; } return null; } // Метод для выбора узла по его индексу public void SelectNode(int index, string nodeNameToSelect) { // Получение узла по индексу if (index >= 0 && index < treeView.Nodes.Count) { TreeNode currentNode = treeView.Nodes[1]; for (int i = propertyHierarchy.Count - 1; i >= 0 && currentNode != null; i--, currentNode = currentNode.FirstNode) { if (currentNode.FirstNode.Text == nodeNameToSelect) { treeView.SelectedNode = currentNode.FirstNode; break; // Выход из цикла после выбора узла } } } else { throw new ArgumentOutOfRangeException("Неверный индекс или имя узла"); } } } }