准备做控件序列化工作
This commit is contained in:
@@ -26,18 +26,18 @@ namespace Ramitta
|
||||
{
|
||||
public partial class winTreeList : UserControl, INotifyPropertyChanged
|
||||
{
|
||||
#region 初始化
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
protected void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public winTreeList()
|
||||
{
|
||||
InitializeComponent();
|
||||
Nodes = new ObservableCollection<TreeNode>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region 公共属性
|
||||
/// <summary>
|
||||
/// 获取或设置树形列表的节点集合
|
||||
@@ -78,7 +78,6 @@ namespace Ramitta
|
||||
AddNode(node, parent);
|
||||
return node;
|
||||
}
|
||||
|
||||
public CheckboxTreeNode AddCheckboxNode(string text, string? tag = null, bool isChecked = false, TreeNode? parent = null)
|
||||
{
|
||||
var checkbox = new CheckBox()
|
||||
@@ -87,13 +86,10 @@ namespace Ramitta
|
||||
Content = text,
|
||||
Tag = tag ?? text,
|
||||
ToolTip = tag ?? text,
|
||||
Foreground = Brushes.White,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
// 处理选中状态变化
|
||||
checkbox.Checked += (s, e) => OnCheckboxStateChanged(checkbox, true);
|
||||
checkbox.Unchecked += (s, e) => OnCheckboxStateChanged(checkbox, false);
|
||||
|
||||
var node = new CheckboxTreeNode
|
||||
{
|
||||
Text = text,
|
||||
@@ -103,7 +99,6 @@ namespace Ramitta
|
||||
AddNode(node, parent);
|
||||
return node;
|
||||
}
|
||||
|
||||
public ComboboxTreeNode AddComboboxNode(string text, List<string>? items = null, TreeNode? parent = null)
|
||||
{
|
||||
var combobox = new ComboBox()
|
||||
@@ -113,15 +108,6 @@ namespace Ramitta
|
||||
MinWidth = 100
|
||||
};
|
||||
|
||||
// 处理选择改变事件
|
||||
combobox.SelectionChanged += (s, e) =>
|
||||
{
|
||||
if (combobox.SelectedItem is string selected)
|
||||
{
|
||||
OnComboboxSelectionChanged(combobox, selected);
|
||||
}
|
||||
};
|
||||
|
||||
var node = new ComboboxTreeNode
|
||||
{
|
||||
Text = text,
|
||||
@@ -131,246 +117,276 @@ namespace Ramitta
|
||||
AddNode(node, parent);
|
||||
return node;
|
||||
}
|
||||
|
||||
// 可选:添加事件处理方法
|
||||
private void OnCheckboxStateChanged(CheckBox checkbox, bool isChecked)
|
||||
{
|
||||
// 这里可以处理复选框状态变化逻辑
|
||||
Debug.WriteLine($"Checkbox '{checkbox.Tag}' changed to: {isChecked}");
|
||||
}
|
||||
|
||||
private void OnComboboxSelectionChanged(ComboBox combobox, string selectedValue)
|
||||
{
|
||||
// 这里可以处理组合框选择变化逻辑
|
||||
Debug.WriteLine($"Combobox selection changed to: {selectedValue}");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 查(这里面的函数下一个版本全被杀)
|
||||
/// <summary>
|
||||
/// 获取所有被勾选的Checkbox节点的Tag
|
||||
/// </summary>
|
||||
/// <param name="nodes">当前节点集合</param>
|
||||
/// <returns>被勾选Checkbox节点的Tag列表</returns>
|
||||
public List<string> GetCheckedCheckboxTags(IEnumerable<TreeNode> nodes)
|
||||
{
|
||||
var tags = new List<string>();
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (node is CheckboxTreeNode checkboxNode && (checkboxNode.obj.IsChecked ?? false))
|
||||
{
|
||||
tags.Add(checkboxNode.obj.Tag.ToString());
|
||||
}
|
||||
|
||||
// 递归查找子节点
|
||||
tags.AddRange(GetCheckedCheckboxTags(node.Children));
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有被勾选的Checkbox节点的Tag
|
||||
/// </summary>
|
||||
/// <param name="nodes">当前节点集合</param>
|
||||
/// <returns>被勾选Checkbox节点的Tag列表</returns>
|
||||
public List<string> GetNoCheckedCheckboxTags(IEnumerable<TreeNode> nodes)
|
||||
{
|
||||
var tags = new List<string>();
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (node is CheckboxTreeNode checkboxNode && checkboxNode.obj.IsChecked != true)
|
||||
{
|
||||
tags.Add(checkboxNode.obj.Tag.ToString());
|
||||
}
|
||||
|
||||
// 递归查找子节点
|
||||
tags.AddRange(GetCheckedCheckboxTags(node.Children));
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 查
|
||||
/// <summary>
|
||||
/// 按照指定key路径查找元素(返回一个)
|
||||
/// </summary>
|
||||
public TreeNode? FindArgvNode(IEnumerable<TreeNode> nodes, List<string> key) {
|
||||
if (nodes == null) nodes = Nodes;
|
||||
if(key.Count == 0) return null;
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
if (node is TreeNode obj &&
|
||||
obj.Text == key[0] &&
|
||||
key.Count==1)
|
||||
{
|
||||
// 最后的层级,且符合指标的第一个值
|
||||
return obj;
|
||||
}
|
||||
|
||||
var foundNode = FindArgvNode(node.Children, key.Skip(1).ToList());
|
||||
|
||||
if (foundNode != null)
|
||||
{
|
||||
return foundNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public List<xTreeNode>? FindTreeNodes<xTreeNode>(IEnumerable<TreeNode>? nodes, string key)
|
||||
public List<xTreeNode> FindAllTreeNodes<xTreeNode>(
|
||||
IEnumerable<TreeNode>? nodes,
|
||||
Func<TreeNode, bool> predicate = null)
|
||||
where xTreeNode : class
|
||||
{
|
||||
List<xTreeNode>? result = null;
|
||||
var result = new List<xTreeNode>();
|
||||
|
||||
if (nodes == null) nodes = Nodes;
|
||||
if (nodes == null)
|
||||
nodes = Nodes;
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
// 检查当前节点是否匹配
|
||||
if (node.Text == key && node is xTreeNode)
|
||||
// 检查当前节点是否匹配类型和条件
|
||||
if (node is xTreeNode targetNode &&
|
||||
(predicate == null || predicate(node)))
|
||||
{
|
||||
if(result == null) result = new List<xTreeNode>();
|
||||
result.Add(node as xTreeNode);
|
||||
}
|
||||
// 跳过空子
|
||||
if (node.Children.Count == 0)
|
||||
continue;
|
||||
// 迭代下层
|
||||
List<xTreeNode>? res = FindTreeNodes<xTreeNode>(node.Children, key);
|
||||
|
||||
if (res == null)continue;
|
||||
|
||||
if (res.Count != 0) {
|
||||
if (result == null) result = new List<xTreeNode>();
|
||||
result.AddRange(res);
|
||||
result.Add(targetNode);
|
||||
}
|
||||
|
||||
// 递归查找子节点
|
||||
if (node.Children.Count > 0)
|
||||
{
|
||||
var childResults = FindAllTreeNodes<xTreeNode>(node.Children, predicate);
|
||||
result.AddRange(childResults);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// 改这个玩意
|
||||
public xControl? Find<xTreeNode, xControl>(IEnumerable<TreeNode>? nodes, string key)
|
||||
where xTreeNode : class
|
||||
where xControl : DependencyObject
|
||||
#endregion
|
||||
#region 删
|
||||
/// <summary>
|
||||
/// 从树中删除指定节点
|
||||
/// </summary>
|
||||
/// <param name="nodeToRemove">要删除的节点</param>
|
||||
/// <returns>是否成功删除</returns>
|
||||
public bool RemoveNode(TreeNode nodeToRemove)
|
||||
{
|
||||
if (nodes == null) nodes = Nodes;
|
||||
if (nodeToRemove == null)
|
||||
return false;
|
||||
|
||||
xTreeNode? targetNode = FindTreeNodes<xTreeNode>(nodes, key)[0];
|
||||
|
||||
if (targetNode == null)
|
||||
return null;
|
||||
// 如果节点有父节点,从父节点的 Children 中删除
|
||||
if (nodeToRemove.Parent != null)
|
||||
{
|
||||
return nodeToRemove.Parent.Children.Remove(nodeToRemove);
|
||||
}
|
||||
// 如果是根节点,从 Nodes 集合中删除
|
||||
else
|
||||
return To<xTreeNode, xControl>(targetNode);
|
||||
}
|
||||
public xControl? To<xTreeNode, xControl>(xTreeNode node)
|
||||
where xTreeNode : class
|
||||
where xControl : DependencyObject
|
||||
{
|
||||
var treeViewItem = FindTreeViewItem<xTreeNode>(treeView, node);
|
||||
|
||||
if (treeViewItem != null)
|
||||
{
|
||||
xControl xCtrl = FindVisualChild<xControl>(treeViewItem);
|
||||
if (xCtrl != null)
|
||||
{
|
||||
return xCtrl;
|
||||
}
|
||||
return Nodes.Remove(nodeToRemove);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private TreeViewItem? FindTreeViewItem<T>(ItemsControl container, T xTreeNode) where T : class
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除多个节点
|
||||
/// </summary>
|
||||
/// <param name="nodesToRemove">要删除的节点列表</param>
|
||||
public void RemoveNodes(IEnumerable<TreeNode> nodesToRemove)
|
||||
{
|
||||
for (int i = 0; i < container.Items.Count; i++)
|
||||
foreach (var node in nodesToRemove.ToList()) // 使用 ToList() 避免修改集合时的枚举错误
|
||||
{
|
||||
TreeViewItem? item = container.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem;
|
||||
if (item != null)
|
||||
{
|
||||
if (item.DataContext == xTreeNode)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
TreeViewItem? childItem = FindTreeViewItem<T>(item, xTreeNode);
|
||||
if (childItem != null)
|
||||
{
|
||||
return childItem;
|
||||
}
|
||||
}
|
||||
RemoveNode(node);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
||||
{
|
||||
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
|
||||
if (child is T)
|
||||
{
|
||||
return (T)child;
|
||||
}
|
||||
#endregion
|
||||
|
||||
T childOfChild = FindVisualChild<T>(child);
|
||||
if (childOfChild != null)
|
||||
{
|
||||
return childOfChild;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public JObject JsonPrint(IEnumerable<TreeNode>? nodes, int loop = 0)
|
||||
#region 序列化
|
||||
public JObject JsonPrint(IEnumerable<TreeNode>? nodes = null, int loop = 0)
|
||||
{
|
||||
// 如果传入的节点为空,使用默认的 Nodes 集合
|
||||
if (nodes == null) nodes = Nodes;
|
||||
|
||||
JObject resultObject = new JObject();
|
||||
|
||||
// 为每个节点构建一个 JObject
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
JObject nodeObject = new JObject();
|
||||
|
||||
// 为当前节点添加基本信息
|
||||
nodeObject["Type"] = node.GetType().Name;
|
||||
nodeObject["Text"] = node.Text; // 添加文本内容
|
||||
|
||||
if (node.GetType() == typeof(CheckboxTreeNode))
|
||||
// 使用模式匹配简化类型检查
|
||||
switch (node)
|
||||
{
|
||||
nodeObject["IsChecked"] = (node as CheckboxTreeNode)?.obj.IsChecked.ToString();
|
||||
case CheckboxTreeNode checkboxNode:
|
||||
nodeObject["IsChecked"] = checkboxNode.obj.IsChecked?.ToString() ?? "false";
|
||||
nodeObject["Tag"] = checkboxNode.obj.Tag?.ToString() ?? string.Empty;
|
||||
break;
|
||||
|
||||
case ComboboxTreeNode comboboxNode:
|
||||
nodeObject["SelectedItem"] = comboboxNode.obj.SelectedItem?.ToString() ?? string.Empty;
|
||||
nodeObject["SelectedIndex"] = comboboxNode.obj.SelectedIndex;
|
||||
// 添加所有选项
|
||||
var items = new JArray();
|
||||
foreach (var item in comboboxNode.obj.Items)
|
||||
{
|
||||
items.Add(item.ToString());
|
||||
}
|
||||
nodeObject["Items"] = items;
|
||||
break;
|
||||
|
||||
case LabelTreeNode labelNode:
|
||||
nodeObject["Content"] = labelNode.obj.Content?.ToString() ?? string.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (node.GetType() == typeof(ComboboxTreeNode))
|
||||
{
|
||||
var target = node as ComboboxTreeNode;
|
||||
nodeObject["SelectedItem"] = target?.obj.SelectedItem.ToString();
|
||||
}
|
||||
|
||||
|
||||
// 处理子节点
|
||||
// 处理子节点 - 使用更合适的属性名
|
||||
if (node.Children.Count > 0)
|
||||
{
|
||||
// 递归调用以处理子节点,并将结果放在 "child" 属性下
|
||||
JObject childrenObject = JsonPrint(node.Children, loop + 1);
|
||||
nodeObject["child"] = childrenObject;
|
||||
nodeObject["Children"] = childrenObject; // 改为更合适的属性名
|
||||
}
|
||||
|
||||
// 使用节点文本作为属性名,将当前节点对象添加到结果中
|
||||
resultObject.Add(node.Text, nodeObject);
|
||||
// 使用唯一键名避免重复键问题
|
||||
string key = node.Text;
|
||||
int counter = 1;
|
||||
while (resultObject.ContainsKey(key))
|
||||
{
|
||||
key = $"{node.Text}_{counter}";
|
||||
counter++;
|
||||
}
|
||||
|
||||
resultObject.Add(key, nodeObject);
|
||||
}
|
||||
|
||||
// 返回结果对象
|
||||
return resultObject;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 删
|
||||
public void JsonParse(string jsonContent)
|
||||
{
|
||||
// 清空现有数据
|
||||
Clear();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(jsonContent))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
JObject rootObject = JObject.Parse(jsonContent);
|
||||
ParseNodes(rootObject, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理解析异常,可以根据需要记录日志或抛出异常
|
||||
Debug.WriteLine($"JSON解析失败: {ex.Message}");
|
||||
throw new ArgumentException("无效的JSON格式", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseNodes(JObject jObject, TreeNode parent)
|
||||
{
|
||||
foreach (var property in jObject.Properties())
|
||||
{
|
||||
JObject nodeObject = property.Value as JObject;
|
||||
if (nodeObject == null)
|
||||
continue;
|
||||
|
||||
// 获取节点类型
|
||||
string nodeType = nodeObject["Type"]?.ToString() ?? "";
|
||||
string text = nodeObject["Text"]?.ToString() ?? "";
|
||||
|
||||
TreeNode newNode = null;
|
||||
|
||||
// 根据类型创建相应的节点
|
||||
switch (nodeType)
|
||||
{
|
||||
case nameof(LabelTreeNode):
|
||||
newNode = CreateLabelTreeNode(nodeObject, text);
|
||||
break;
|
||||
|
||||
case nameof(CheckboxTreeNode):
|
||||
newNode = CreateCheckboxTreeNode(nodeObject, text);
|
||||
break;
|
||||
|
||||
case nameof(ComboboxTreeNode):
|
||||
newNode = CreateComboboxTreeNode(nodeObject, text);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (newNode != null)
|
||||
{
|
||||
// 添加到树中
|
||||
if (parent == null)
|
||||
{
|
||||
Nodes.Add(newNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
newNode.Parent = parent;
|
||||
parent.Children.Add(newNode);
|
||||
}
|
||||
|
||||
// 递归处理子节点
|
||||
if (nodeObject["Children"] is JObject childrenObject)
|
||||
{
|
||||
ParseNodes(childrenObject, newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LabelTreeNode CreateLabelTreeNode(JObject nodeObject, string text)
|
||||
{
|
||||
var labelNode = new LabelTreeNode
|
||||
{
|
||||
Text = text,
|
||||
obj = new Label
|
||||
{
|
||||
Content = nodeObject["Content"]?.ToString() ?? text
|
||||
}
|
||||
};
|
||||
return labelNode;
|
||||
}
|
||||
|
||||
private CheckboxTreeNode CreateCheckboxTreeNode(JObject nodeObject, string text)
|
||||
{
|
||||
bool isChecked = bool.TryParse(nodeObject["IsChecked"]?.ToString(), out var result) && result;
|
||||
string tag = nodeObject["Tag"]?.ToString() ?? text;
|
||||
|
||||
var checkboxNode = new CheckboxTreeNode
|
||||
{
|
||||
Text = text,
|
||||
obj = new CheckBox
|
||||
{
|
||||
Content = text,
|
||||
IsChecked = isChecked,
|
||||
Tag = tag,
|
||||
ToolTip = tag,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
}
|
||||
};
|
||||
return checkboxNode;
|
||||
}
|
||||
|
||||
private ComboboxTreeNode CreateComboboxTreeNode(JObject nodeObject, string text)
|
||||
{
|
||||
var comboboxNode = new ComboboxTreeNode
|
||||
{
|
||||
Text = text,
|
||||
obj = new ComboBox
|
||||
{
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
MinWidth = 100
|
||||
}
|
||||
};
|
||||
|
||||
// 添加选项
|
||||
if (nodeObject["Items"] is JArray itemsArray)
|
||||
{
|
||||
foreach (var item in itemsArray)
|
||||
{
|
||||
comboboxNode.obj.Items.Add(item.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// 设置选中项
|
||||
int selectedIndex = nodeObject["SelectedIndex"]?.Value<int>() ?? 0;
|
||||
if (selectedIndex >= 0 && selectedIndex < comboboxNode.obj.Items.Count)
|
||||
{
|
||||
comboboxNode.obj.SelectedIndex = selectedIndex;
|
||||
}
|
||||
|
||||
return comboboxNode;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 动力学
|
||||
@@ -392,42 +408,8 @@ namespace Ramitta
|
||||
CollapseNode(node);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
private void AddNode(TreeNode node, TreeNode parent)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
Nodes.Add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Children.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<TreeNode> GetAllNodes()
|
||||
{
|
||||
return GetAllNodes(Nodes);
|
||||
}
|
||||
|
||||
private IEnumerable<TreeNode> GetAllNodes(IEnumerable<TreeNode> nodes)
|
||||
{
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
yield return node;
|
||||
foreach (var child in GetAllNodes(node.Children))
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ExpandNode(TreeNode node)
|
||||
public void ExpandNode(TreeNode node)
|
||||
{
|
||||
var container = treeView.ItemContainerGenerator.ContainerFromItem(node) as TreeViewItem;
|
||||
if (container != null)
|
||||
@@ -441,7 +423,7 @@ namespace Ramitta
|
||||
}
|
||||
}
|
||||
|
||||
private void CollapseNode(TreeNode node)
|
||||
public void CollapseNode(TreeNode node)
|
||||
{
|
||||
var container = treeView.ItemContainerGenerator.ContainerFromItem(node) as TreeViewItem;
|
||||
if (container != null)
|
||||
@@ -454,7 +436,35 @@ namespace Ramitta
|
||||
CollapseNode(child);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
private void AddNode(TreeNode node, TreeNode parent)
|
||||
{
|
||||
if (parent == null)
|
||||
{
|
||||
node.Parent = null;
|
||||
Nodes.Add(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
node.Parent = parent;
|
||||
parent.Children.Add(node);
|
||||
}
|
||||
}
|
||||
private IEnumerable<TreeNode> GetAllNodes(IEnumerable<TreeNode>? nodes=null)
|
||||
{
|
||||
if (nodes == null) nodes = null;
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
yield return node;
|
||||
foreach (var child in GetAllNodes(node.Children))
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -463,19 +473,19 @@ namespace Ramitta
|
||||
{
|
||||
private string _text;
|
||||
private ObservableCollection<TreeNode> _children;
|
||||
private TreeNode _parent;
|
||||
|
||||
#region 初始化结构
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public TreeNode()
|
||||
{
|
||||
_children = new ObservableCollection<TreeNode>();
|
||||
}
|
||||
|
||||
#endregion
|
||||
public string Text
|
||||
{
|
||||
get => _text;
|
||||
@@ -488,7 +498,6 @@ namespace Ramitta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<TreeNode> Children
|
||||
{
|
||||
get => _children;
|
||||
@@ -501,11 +510,33 @@ namespace Ramitta
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Label类型的树节点
|
||||
/// </summary>
|
||||
public TreeNode Parent
|
||||
{
|
||||
get => _parent;
|
||||
set
|
||||
{
|
||||
if (_parent != value)
|
||||
{
|
||||
// 防止设置自己为自己的父节点
|
||||
if (value == this)
|
||||
throw new InvalidOperationException("不能将节点设置为自己的父节点");
|
||||
|
||||
// 防止循环引用(检查祖先链)
|
||||
var current = value;
|
||||
while (current != null)
|
||||
{
|
||||
if (current == this)
|
||||
throw new InvalidOperationException("检测到循环引用");
|
||||
current = current.Parent;
|
||||
}
|
||||
|
||||
_parent = value;
|
||||
OnPropertyChanged(nameof(Parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public class LabelTreeNode : TreeNode
|
||||
{
|
||||
private Label _obj;
|
||||
@@ -523,10 +554,6 @@ namespace Ramitta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combobox类型的树节点
|
||||
/// </summary>
|
||||
public class ComboboxTreeNode : TreeNode
|
||||
{
|
||||
private ComboBox _obj;
|
||||
@@ -544,10 +571,6 @@ namespace Ramitta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checkbox类型的树节点
|
||||
/// </summary>
|
||||
public class CheckboxTreeNode : TreeNode
|
||||
{
|
||||
private CheckBox _obj;
|
||||
|
||||
Reference in New Issue
Block a user