代码拉取完成,页面将自动刷新
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Diagnostics;
using System.Windows.Media; // 添加此行
using System.Windows.Shapes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Win32;
namespace NodeEditor {
public partial class NodeGraph : Border {
public readonly NodeGraphContext context;
private MainWindow _window;
private Node _selectedNode;
public Node selectNode {
get {
return _selectedNode;
}
}
private Node rootNode;
private Path _selectedPipe;
private Brush _selectedPipeBrush;
private ContextMenu _contextMenu;
private double _pipeStiffness = 50;
public double pipeStiffness {
get {
return _pipeStiffness;
}
set {
if (_pipeStiffness == value)
return;
}
}
private ScaleTransform scaleTransform;
private TranslateTransform translateTransform;
private TextBlock filePathTextBlock;
public NodeGraph(NodeGraphContext context, MainWindow window) {
InitializeComponent();
this.context = context;
this._window = window;
this.rootNode = null;
canvas.MouseLeftButtonDown += OnMouseLeftButtonDown;
canvas.MouseRightButtonDown += OnMouseRightButtonDown; // 添加右键事件
// 初始化变换
var transformGroup = new TransformGroup();
scaleTransform = new ScaleTransform(1, 1);
translateTransform = new TranslateTransform(0, 0);
transformGroup.Children.Add(scaleTransform);
transformGroup.Children.Add(translateTransform);
this.RenderTransform = transformGroup;
MouseWheel += NodeGraph_MouseWheel;
// 添加键盘事件监听
KeyDown += NodeGraph_KeyDown;
// 初始化 ContextMenu
_contextMenu = new ContextMenu();
var createNodeItem = new MenuItem { Header = "创建节点" };
createNodeItem.Click += CreateNodeItem_Click;
_contextMenu.Items.Add(createNodeItem);
// 创建 TextBlock
filePathTextBlock = new TextBlock {
Foreground = Brushes.White,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Bottom,
};
// 添加到 canvas
canvas.Children.Add(filePathTextBlock);
// 初始化状态文本块
SetfilePathTextBlock("no save file");
}
private void SetfilePathTextBlock(string txt) {
filePathTextBlock.Text = txt;
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (Pipe.EditingPipe != null && (Mouse.DirectlyOver == this || Mouse.DirectlyOver == canvas)) {
Pipe.EditingPipe.Dispose();
Pipe.EditingPipe = null;
}
// 取消之前选中的连线高亮
if (_selectedPipe != null) {
_selectedPipe.Stroke = _selectedPipeBrush;
}
// 判断点击的元素是否是 Path
if (e.OriginalSource is Path path) {
_selectedPipeBrush = path.Stroke;
_selectedPipe = path;
_selectedPipe.Stroke = new SolidColorBrush(Color.FromArgb(128, 255, 255, 255)); // 设置为淡白色
} else {
_selectedPipeBrush = null;
_selectedPipe = null;
}
if (Mouse.DirectlyOver == canvas || _selectedPipe != null) {
// 点击空白区域时取消选中
SelectNode(null);
}
}
public void SelectNode(Node node) {
if (_selectedNode == node) {
return;
}
if (_selectedNode != null) {
_selectedNode.IsSelected = false; // 取消之前选中的节点
}
_selectedNode = node;
if (_selectedNode != null) {
_selectedNode.IsSelected = true; // 设置当前节点为选中状态
}
_window.ChangeNodeEnabled(node);
}
// 鼠标滚轮缩放
private void NodeGraph_MouseWheel(object sender, MouseWheelEventArgs e) {
double zoomFactor = e.Delta > 0 ? 1.1 : 0.9; // 放大或缩小
Point mousePosition = e.GetPosition(this);
// 调整缩放中心
scaleTransform.CenterX = mousePosition.X;
scaleTransform.CenterY = mousePosition.Y;
// 应用缩放
scaleTransform.ScaleX *= zoomFactor;
scaleTransform.ScaleY *= zoomFactor;
}
// 键盘事件处理
private void NodeGraph_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Delete) {
if (_selectedPipe != null) {
// 删除连线
if (_selectedPipe.Tag is UIElement relatedElement && canvas.Children.Contains(relatedElement)) {
Path path = (Path)_selectedPipe.Tag;
Pipe pipe = (Pipe)path.Tag;
pipe.Dispose();
}
// 清空选中连线
_selectedPipe = null;
_selectedPipeBrush = null;
}
if (_selectedNode != null) {
// 根节点不能删除,因为保存到磁盘时,得通过根节点遍历其下的所有节点
if (_selectedNode == rootNode) {
return;
}
// 删除与该节点相关的连线
_selectedNode.Dispose();
// 从 canvas 中移除节点
if (canvas.Children.Contains(_selectedNode)) {
canvas.Children.Remove(_selectedNode);
}
// 清空选中节点
SelectNode(null);
}
}
if (Keyboard.IsKeyDown(Key.LeftCtrl) && e.Key == Key.V) {
// 复制节点
if (_selectedNode != null) {
CopyNode();
}
}
}
private void CopyNode() {
double x = _selectedNode.position.X + _selectedNode.ActualWidth;
double y = _selectedNode.position.Y + _selectedNode.ActualHeight;
Node cpNode = addNode(x, y);
cpNode.title = _selectedNode.title;
cpNode.desc = _selectedNode.desc;
cpNode.LoadAllVar(_selectedNode.CopyNodeVarList());
}
private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs e) {
// 获取鼠标点击位置
Point mousePosition = e.GetPosition(canvas);
// 动态更新 ContextMenu 的位置
_contextMenu.PlacementTarget = canvas;
_contextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.MousePoint;
// 显示 ContextMenu
_contextMenu.IsOpen = true;
// 防止事件继续传播
e.Handled = true;
}
private void CreateNodeItem_Click(object sender, RoutedEventArgs e) {
// 获取鼠标点击位置
Point mousePosition = Mouse.GetPosition(canvas);
addNode(mousePosition.X, mousePosition.Y);
}
public Node addNode(double x, double y) {
// 创建节点并设置位置
Node newNode = new JsonNode {
position = new Point(x, y)
};
// 添加节点到 canvas
return addNode(newNode);
}
public Node addNode(Node node) {
if (rootNode == null) {
rootNode = node;
// 橙色背景
var converter = new BrushConverter();
rootNode.Background = (Brush)converter.ConvertFromString("#F0A30A");
}
canvas.Children.Add(node);
node.setConnections();
return node;
}
private Dictionary<int, bool> filterNodeMap = new Dictionary<int, bool>();
// 配置 JsonSerializer,忽略 null 值
private JsonSerializer jsonSerializer = new JsonSerializer {
NullValueHandling = NullValueHandling.Ignore
};
public void SaveNodeTreeToJsonByCtrlS(List<VarData> globalVarList) {
if (filePathTextBlock.Text != "") {
SaveNodeTreeToJson(filePathTextBlock.Text, globalVarList);
} else {
OpenSaveJsonDialog(globalVarList);
}
}
public void OpenSaveJsonDialog(List<VarData> globalVarList) {
if (rootNode == null) {
MessageBox.Show("Please add a node to save.", "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "JSON Files (*.json)|*.json"; // 设置文件过滤器
saveFileDialog.Title = "Save Node File"; // 设置对话框标题
saveFileDialog.DefaultExt = ".json"; // 设置默认文件扩展名
// 显示保存对话框
bool? result = saveFileDialog.ShowDialog();
if (result == true) // 如果用户点击了"Save"按钮
{
string filename = saveFileDialog.FileName; // 获取用户选择的文件路径
// 这里编写保存JSON文件的代码
SaveNodeTreeToJson(filename, globalVarList);
}
}
public void SaveNodeTreeToJson(string filePath, List<VarData> globalVarList) {
filterNodeMap.Clear();
JObject jsonObject = new JObject();
JArray nodeList = new JArray();
CoverNodeToJson(nodeList, rootNode);
ForeachNodeToJson(nodeList, rootNode);
if (globalVarList != null && globalVarList.Count > 0) {
JArray jsonArray = JArray.FromObject(globalVarList, jsonSerializer);
jsonObject.Add("Globals", jsonArray);
}
jsonObject.Add("Nodes", nodeList);
filterNodeMap.Clear();
System.IO.File.WriteAllText(filePath, jsonObject.ToString());
SetfilePathTextBlock(filePath);
}
public void CoverNodeToJson(JArray nodeList, Node node) {
filterNodeMap[node.uid] = true;
Vector2 pos;
pos.x = node.position.X;
pos.y = node.position.Y;
var varList = node.GetAllVar();
JsonFullNode fullNode = new JsonFullNode {
uid = node.uid,
name = node.title,
desc = node.desc,
varList = varList.Count > 0 ? varList : null,
nextNodes = GetNextAllNodeUid(node),
pos = pos,
};
JObject nodeJson = JObject.FromObject(fullNode, jsonSerializer);
nodeList.Add(nodeJson);
}
public void ForeachNodeToJson(JArray nodeList, Node curNode) {
foreach (OutputDock output in curNode.getOutputs()) {
foreach (Pipe pipe in output.pipes.ToArray()) {
Node node = pipe.inputDock.node;
if (filterNodeMap.ContainsKey(node.uid)) {
continue;
}
CoverNodeToJson(nodeList, node);
ForeachNodeToJson(nodeList, node);
}
}
}
// 连线信息,连线思路:主要是获取当前节点的子节点有哪些,然后根据当前节点和子节点进行连线
public List<int> GetNextAllNodeUid(Node curNode) {
List<int> tmp = new List<int>();
foreach (OutputDock output in curNode.getOutputs()) {
foreach (Pipe pipe in output.pipes.ToArray()) {
Node node = pipe.inputDock.node;
tmp.Add(node.uid);
}
}
return tmp.Count > 0 ? tmp : null;
}
public void OpenLoadJsonDialog() {
// 创建OpenFileDialog实例
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*"; // 设置过滤器
openFileDialog.Title = "选择一个JSON文件"; // 设置对话框标题
// 显示对话框并检查结果
if (openFileDialog.ShowDialog() == true) {
// 获取选中的文件路径
string filePath = openFileDialog.FileName;
try {
canvas.Children.Clear();
// 读取文件内容到字符串
string jsonContent = System.IO.File.ReadAllText(filePath);
LoadJsonString(jsonContent);
SetfilePathTextBlock(filePath);
canvas.Children.Add(filePathTextBlock);
}
catch (Exception ex) {
MessageBox.Show("读取或解析文件时发生错误: " + ex.Message + " " + ex.StackTrace);
}
}
}
private void LoadJsonString(string jContent) {
Dictionary<int, Node> pipeNodes = new Dictionary<int, Node>();
Dictionary<int, JsonFullNode> jFullNode = new Dictionary<int, JsonFullNode>();
JObject jsonObject = JObject.Parse(jContent);
JArray jsonArray = (JArray)jsonObject["Globals"];
if (jsonArray != null) {
foreach (var item in jsonArray) {
VarData v = item.ToObject<VarData>();
_window.AddGlobalVar(v.type, v.key, v.value);
}
}
JArray jNodeArray = (JArray)jsonObject["Nodes"];
if (jNodeArray == null) {
return;
}
rootNode = null;
foreach (var item in jNodeArray) {
JsonFullNode v = item.ToObject<JsonFullNode>();
Node node = addNode(v.pos.x, v.pos.y);
node.uid = v.uid;
node.desc = v.desc;
node.title = v.name;
node.LoadAllVar(v.varList);
pipeNodes[v.uid] = node;
jFullNode[v.uid] = v;
}
// 两个节点之间连线
foreach (var item in jFullNode) {
int uid = item.Key;
JsonFullNode v = item.Value;
Node node = pipeNodes[uid];
if (v.nextNodes != null && v.nextNodes.Count > 0) {
foreach(int uuid in v.nextNodes) {
Node subNode = pipeNodes[uuid];
Pipe pipe = new Pipe(node.getOutputs()[0], subNode.getInputs()[0]);
pipe.CheckIfPipeCompleted();
}
}
}
}
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。