准备做控件序列化工作

This commit is contained in:
2025-09-03 16:16:00 +08:00
parent 31d3517ecb
commit e773052a85
365 changed files with 3078 additions and 374 deletions

View File

@@ -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;