mirror of
https://gitee.com/wang-yin1/wpf-visual-process-framework
synced 2026-03-02 15:50:51 +08:00
1118 lines
36 KiB
C#
1118 lines
36 KiB
C#
using CommunityToolkit.Mvvm.ComponentModel;
|
||
using CommunityToolkit.Mvvm.Input;
|
||
using Microsoft.Win32;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
using System.Windows.Media.Imaging;
|
||
using System.Windows.Media.Media3D;
|
||
using System.Xml.Linq;
|
||
using VisionFrame.Base;
|
||
using VisionFrame.Base.Models;
|
||
using VisionFrame.Models;
|
||
using VisionFrame.Nodes;
|
||
|
||
namespace VisionFrame.ViewModels
|
||
{
|
||
public class FlowTabViewModel : ObservableObject, IFlowContext
|
||
{
|
||
private bool _isCurrent;
|
||
|
||
public bool IsCurrent
|
||
{
|
||
get { return _isCurrent; }
|
||
set
|
||
{
|
||
SetProperty<bool>(ref _isCurrent, value);
|
||
|
||
if (!value) TitleEditVisible = Visibility.Hidden;
|
||
}
|
||
}
|
||
|
||
#region Title与编辑
|
||
private string _title;
|
||
|
||
public string Title
|
||
{
|
||
get { return _title; }
|
||
set { SetProperty<string>(ref _title, value); }
|
||
}
|
||
|
||
|
||
private Visibility _titleEditVisible = Visibility.Hidden;
|
||
|
||
public Visibility TitleEditVisible
|
||
{
|
||
get { return _titleEditVisible; }
|
||
set { SetProperty<Visibility>(ref _titleEditVisible, value); }
|
||
}
|
||
|
||
|
||
public ICommand SelectCommand { get; set; }
|
||
public ICommand EditTitleCommand { get; set; }
|
||
public ICommand AcceptTitleCommand { get; set; }
|
||
#endregion
|
||
|
||
#region 节点创建
|
||
public ObservableCollection<NodeModelBase> NodeList { get; set; } =
|
||
new ObservableCollection<NodeModelBase>();
|
||
|
||
public ICommand DragDropCommand { get; set; }
|
||
|
||
public ICommand DeleteElementCommand { get; set; }
|
||
#endregion
|
||
|
||
#region 连线集合
|
||
public ObservableCollection<LinkModel> LinkList { get; set; } =
|
||
new ObservableCollection<LinkModel>();
|
||
#endregion
|
||
|
||
#region 节点移动相关动作
|
||
public ICommand NodeMouseDownCommand { get; set; }
|
||
public ICommand NodeMouseMoveCommand { get; set; }
|
||
public ICommand NodeMouseUpCommand { get; set; }
|
||
#endregion
|
||
|
||
#region 锚点操作
|
||
public ICommand AnchorDownCommand { get; set; }
|
||
public ICommand AnchorUpCommand { get; set; }
|
||
#endregion
|
||
|
||
#region 流程控制
|
||
public ICommand RunCommand { get; set; }
|
||
public ICommand CircleCommand { get; set; }
|
||
public ICommand StopCommand { get; set; }
|
||
public ICommand StepCommand { get; set; }
|
||
#endregion
|
||
|
||
#region 流程参数管理
|
||
public ObservableCollection<FlowArgModel> ArgumentList { get; set; } =
|
||
new ObservableCollection<FlowArgModel>();
|
||
|
||
public ICommand AddArgumentCommand { get; set; }
|
||
public ICommand DelArgumentCommand { get; set; }
|
||
|
||
public List<string> ArgTypeList { get; set; } = new List<string>
|
||
{
|
||
"Int32","IntPtr","Double","String","Boolean"
|
||
};
|
||
|
||
|
||
// 参数处理相关命令
|
||
public ICommand SelectFolderCommand { get; set; }
|
||
#endregion
|
||
|
||
private ImageSource _previewImage;
|
||
/// <summary>
|
||
/// 预览图像
|
||
/// </summary>
|
||
public ImageSource PreviewImage
|
||
{
|
||
get { return _previewImage; }
|
||
set { SetProperty<ImageSource>(ref _previewImage, value); }
|
||
}
|
||
|
||
|
||
public ObservableCollection<LogModel> LogList { get; set; } =
|
||
new ObservableCollection<LogModel>();
|
||
|
||
|
||
//画布缩放
|
||
#region 画布缩放
|
||
private double _mainZoom = 1.0;
|
||
|
||
public double MainZoom
|
||
{
|
||
get { return _mainZoom; }
|
||
set { SetProperty<double>(ref _mainZoom, value); }
|
||
}
|
||
|
||
private double _dragX = 0;
|
||
|
||
public double DragX
|
||
{
|
||
get { return _dragX; }
|
||
set { SetProperty<double>(ref _dragX, value); }
|
||
}
|
||
|
||
private double _dragY = 0;
|
||
|
||
public double DragY
|
||
{
|
||
get { return _dragY; }
|
||
set { SetProperty<double>(ref _dragY, value); }
|
||
}
|
||
|
||
public ICommand MouseWheelCommand { get; set; }
|
||
|
||
public ICommand CanvasMouseDownCommand { get; set; }
|
||
public ICommand CanvasMouseUpCommand { get; set; }
|
||
public ICommand CanvasMouseMoveCommand { get; set; }
|
||
|
||
public ICommand ZoomIncreaseCommand { get; set; }
|
||
public ICommand ZoomReduceCommand { get; set; }
|
||
public ICommand ZoomResetCommand { get; set; }
|
||
#endregion
|
||
|
||
#region 鹰眼视图
|
||
private double _hwakeyeZoom = 1.0;
|
||
|
||
public double HwakeyeZoom
|
||
{
|
||
get { return _hwakeyeZoom; }
|
||
set { SetProperty<double>(ref _hwakeyeZoom, value); }
|
||
}
|
||
|
||
private double _hwakeyeDragX;
|
||
|
||
public double HwakeyeDragX
|
||
{
|
||
get { return _hwakeyeDragX; }
|
||
set { SetProperty<double>(ref _hwakeyeDragX, value); }
|
||
}
|
||
private double _hwakeyeDragY;
|
||
|
||
public double HwakeyeDragY
|
||
{
|
||
get { return _hwakeyeDragY; }
|
||
set { SetProperty<double>(ref _hwakeyeDragY, value); }
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
public List<string> Operator { get; set; } = new List<string>
|
||
{
|
||
"=","<",">","<=",">=","!="
|
||
};
|
||
|
||
public FlowTabViewModel()
|
||
{
|
||
SelectCommand = new RelayCommand(() =>
|
||
{
|
||
this.IsCurrent = true;
|
||
});
|
||
DragDropCommand = new RelayCommand<object>(OnDragDrop);
|
||
|
||
DeleteElementCommand = new RelayCommand<object>(DoElementDelete);
|
||
|
||
#region Tab Title编辑动作
|
||
EditTitleCommand = new RelayCommand(() =>
|
||
{
|
||
TitleEditVisible = Visibility.Visible;
|
||
});
|
||
AcceptTitleCommand = new RelayCommand(() =>
|
||
{
|
||
TitleEditVisible = Visibility.Hidden;
|
||
});
|
||
#endregion
|
||
|
||
#region 节点移动动作
|
||
NodeMouseDownCommand = new RelayCommand<object>(OnNodeMouseDown);
|
||
NodeMouseMoveCommand = new RelayCommand<object>(OnNodeMove);
|
||
NodeMouseUpCommand = new RelayCommand(OnNodeMouseUp);
|
||
#endregion
|
||
|
||
//默认起始节点添加
|
||
string node_name = "VisionFrame.Nodes.StartNode";
|
||
//INodeBase node = Activator.CreateInstance(Assembly.GetExecutingAssembly().GetType(node_name)) as INodeBase;
|
||
//node.AnchorDownCommand = new RelayCommand<object>(OnAnchorDown);
|
||
NodeList.Add(new StartNodeModel
|
||
{
|
||
IsStart = true,
|
||
TargetNodeObject = node_name,
|
||
X = 600,
|
||
Y = 450,
|
||
W = 100,
|
||
H = 34,
|
||
FlowLevel = new List<int> { 0 }
|
||
});
|
||
|
||
|
||
// 流程控制
|
||
RunCommand = new RelayCommand(DoRunFlowchart);
|
||
CircleCommand = new RelayCommand(DoCircleExecute);
|
||
StopCommand = new RelayCommand(DoStopExecute);
|
||
StepCommand = new RelayCommand(DoStepExecute);
|
||
|
||
// 添加参数
|
||
AddArgumentCommand = new RelayCommand(DoAddArgument);
|
||
DelArgumentCommand = new RelayCommand<object>(DoDelArgument);
|
||
|
||
// 参数列表命令
|
||
SelectFolderCommand = new RelayCommand<object>(DoSelectFolder);
|
||
|
||
|
||
// 锚点控制
|
||
AnchorDownCommand = new RelayCommand<object>(DoAnchorDown);
|
||
AnchorUpCommand = new RelayCommand<object>(DoAnchorUp);
|
||
|
||
|
||
// 缩放操作
|
||
//MouseWheelCommand = new RelayCommand<object>(DoMainZoom);
|
||
|
||
CanvasMouseDownCommand = new RelayCommand<object>(DoCanvasMouseDown);
|
||
CanvasMouseUpCommand = new RelayCommand<object>(DoCanvasMouseUp);
|
||
//CanvasMouseMoveCommand = new RelayCommand<object>(DoCanvasMouseMove);
|
||
|
||
ZoomIncreaseCommand = new RelayCommand<object>(DoZoomIncrease);
|
||
ZoomReduceCommand = new RelayCommand<object>(DoZoomReduce);
|
||
ZoomResetCommand = new RelayCommand<object>(DoZoomReset);
|
||
}
|
||
|
||
// 这个命令是ItemsControl执行
|
||
private void OnDragDrop(object obj)
|
||
{
|
||
var e = obj as DragEventArgs;
|
||
|
||
var component_model = e.Data.GetData(typeof(ComponentModel)) as ComponentModel;
|
||
|
||
// 动态创建出来的节点对象
|
||
//object instance = GetInstance(component_model.TargetNode);
|
||
// 关联锚点动作事件命令
|
||
//(instance as INodeBase).AnchorDownCommand =
|
||
// new RelayCommand<object>(OnAnchorDown);
|
||
//(instance as INodeBase).AnchorUpCommand =
|
||
// new RelayCommand<object>(OnAnchorUp);
|
||
|
||
// 获取鼠标松开时的坐标
|
||
Point point = e.GetPosition((IInputElement)e.Source);
|
||
|
||
// 创建每个显示节点所对应的数据Model
|
||
string model_str = component_model.TargetModel;
|
||
NodeModelBase node_model =
|
||
(NodeModelBase)this.GetInstance(component_model.TargetModel);
|
||
|
||
//node_model.TargetNodeObject = instance;
|
||
node_model.TargetNodeObject = component_model.TargetNode;
|
||
node_model.IsDecision = node_model is DecisionNodeModelBase;
|
||
|
||
node_model.X = point.X - component_model.W / 2;
|
||
node_model.Y = point.Y - component_model.H / 2;
|
||
node_model.W = component_model.W;
|
||
node_model.H = component_model.H;
|
||
|
||
|
||
NodeList.Add(node_model);
|
||
}
|
||
|
||
private object GetInstance(string target)
|
||
{
|
||
string[] _info = target.Split(";");
|
||
|
||
Assembly assembly =
|
||
Assembly.LoadFile(Environment.CurrentDirectory + "/Activities/" + _info[0] + ".dll");
|
||
if (assembly == null) return null;
|
||
|
||
Type type = assembly.GetType(_info[1]);
|
||
if (type == null) return null;
|
||
|
||
return Activator.CreateInstance(type);
|
||
}
|
||
|
||
private void DoElementDelete(object obj)
|
||
{
|
||
if (obj is NodeModelBase model)
|
||
{
|
||
var links = this.LinkList.Where(l => l.StartId == model.NodeId || l.EndId == model.NodeId)
|
||
.ToList();
|
||
int len = links.Count;
|
||
for (int i = len - 1; i >= 0; i--)
|
||
{
|
||
this.LinkList.Remove(links[i]);
|
||
|
||
RestAnchorShow(links[i]);
|
||
}
|
||
this.NodeList.Remove(model);
|
||
|
||
// 后续节点的Level信息的同步更新
|
||
|
||
// .....
|
||
}
|
||
else if (obj is LinkModel linkModel)
|
||
{
|
||
this.LinkList.Remove(linkModel);
|
||
|
||
RestAnchorShow(linkModel);
|
||
}
|
||
|
||
isCanvasDrag = false;
|
||
isLinking = false;
|
||
is_hwakeye_drag = false;
|
||
}
|
||
private void RestAnchorShow(LinkModel model)
|
||
{
|
||
var start_node = NodeList.FirstOrDefault(n => n.NodeId == model.StartId);
|
||
start_node?.SetAnchorShow(model.StartAnchor, true);
|
||
|
||
var end_node = NodeList.FirstOrDefault(n => n.NodeId == model.EndId);
|
||
end_node?.SetAnchorShow(model.EndAnchor, true);
|
||
}
|
||
|
||
|
||
#region 处理节点移动
|
||
bool _is_moving = false;
|
||
public NodeModelBase CurrentNodeModel { get; set; } = new NodeModelBase();
|
||
|
||
Point _node_point = new Point();
|
||
// 这个命令是由创建出来的节点触发的
|
||
private void OnNodeMouseDown(object obj)
|
||
{
|
||
var e = obj as MouseEventArgs;
|
||
|
||
if (CurrentNodeModel != null)
|
||
{
|
||
CurrentNodeModel.IsShowProperties = false;
|
||
CurrentNodeModel.IsSelected = false;
|
||
}
|
||
|
||
CurrentNodeModel = (e.Source as FrameworkElement).DataContext as NodeModelBase;
|
||
|
||
if (CurrentNodeModel != null)
|
||
{
|
||
CurrentNodeModel.IsSelected = true;
|
||
|
||
// 修改Model中X和Y 至使页面节点进行位置更新
|
||
// 什么时候?鼠标移动的时候
|
||
//model.X
|
||
_node_point = e.GetPosition((IInputElement)e.Source);
|
||
|
||
_is_moving = true;
|
||
}
|
||
else
|
||
CurrentNodeModel = new NodeModelBase();
|
||
this.OnPropertyChanged(nameof(CurrentNodeModel));
|
||
|
||
e.Handled = true;
|
||
}
|
||
|
||
// 命令是由ItemsControl触发的
|
||
private void OnNodeMove(object obj)
|
||
{
|
||
var e = obj as MouseEventArgs;
|
||
Point current_point = e.GetPosition((IInputElement)e.Source);
|
||
// 节点移动的时候
|
||
if (_is_moving)
|
||
{
|
||
// 根据光标位置 将节点进行移动
|
||
CurrentNodeModel.X = current_point.X - _node_point.X;
|
||
CurrentNodeModel.Y = current_point.Y - _node_point.Y;
|
||
|
||
#region 更新连线坐标
|
||
var start_list = LinkList.Where(ll => ll.StartId == CurrentNodeModel.NodeId);
|
||
var end_list = LinkList.Where(ll => ll.EndId == CurrentNodeModel.NodeId);
|
||
|
||
// 更新连线的起始端坐标
|
||
var node = start_list.FirstOrDefault(sl => sl.StartAnchor == "T");
|
||
if (node != null)
|
||
{
|
||
node.StartX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
|
||
node.StartY = CurrentNodeModel.Y + 3;
|
||
}
|
||
node = start_list.FirstOrDefault(sl => sl.StartAnchor == "B");
|
||
if (node != null)
|
||
{
|
||
node.StartX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
|
||
node.StartY = CurrentNodeModel.Y + CurrentNodeModel.H - 3;
|
||
}
|
||
node = start_list.FirstOrDefault(sl => sl.StartAnchor == "L");
|
||
if (node != null)
|
||
{
|
||
node.StartX = CurrentNodeModel.X + 3;
|
||
node.StartY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
|
||
}
|
||
node = start_list.FirstOrDefault(sl => sl.StartAnchor == "R");
|
||
if (node != null)
|
||
{
|
||
node.StartX = CurrentNodeModel.X + CurrentNodeModel.W - 3;
|
||
node.StartY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
|
||
}
|
||
|
||
// 更新连线的终止端坐标
|
||
node = end_list.FirstOrDefault(sl => sl.EndAnchor == "T");
|
||
if (node != null)
|
||
{
|
||
node.EndX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
|
||
node.EndY = CurrentNodeModel.Y + 3;
|
||
}
|
||
node = end_list.FirstOrDefault(sl => sl.EndAnchor == "B");
|
||
if (node != null)
|
||
{
|
||
node.EndX = CurrentNodeModel.X + CurrentNodeModel.W / 2;
|
||
node.EndY = CurrentNodeModel.Y + CurrentNodeModel.H - 3;
|
||
}
|
||
node = end_list.FirstOrDefault(sl => sl.EndAnchor == "L");
|
||
if (node != null)
|
||
{
|
||
node.EndX = CurrentNodeModel.X + 3;
|
||
node.EndY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
|
||
}
|
||
node = end_list.FirstOrDefault(sl => sl.EndAnchor == "R");
|
||
if (node != null)
|
||
{
|
||
node.EndX = CurrentNodeModel.X + CurrentNodeModel.W - 3;
|
||
node.EndY = CurrentNodeModel.Y + CurrentNodeModel.H / 2;
|
||
}
|
||
#endregion
|
||
|
||
e.Handled = true;
|
||
}
|
||
if (isLinking)
|
||
{
|
||
// 更新当前LinkModel的终点坐标?
|
||
linkModel.EndX = current_point.X;
|
||
linkModel.EndY = current_point.Y;
|
||
|
||
e.Handled = true;
|
||
}
|
||
}
|
||
// 鼠标左键在画布上弹起
|
||
private void OnNodeMouseUp()
|
||
{
|
||
_is_moving = false;
|
||
|
||
// 清除临时Link
|
||
if (isLinking && linkModel != null)
|
||
{
|
||
LinkList.Remove(linkModel);
|
||
linkModel = null;
|
||
isLinking = false;
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 锚点处理
|
||
LinkModel linkModel;
|
||
bool isLinking = false;
|
||
// 当在锚点按下的时候
|
||
private void DoAnchorDown(object obj)
|
||
{
|
||
string[] info = obj.ToString().Split(";");
|
||
string id = info[0];
|
||
// 确定对应的节点(Model)
|
||
NodeModelBase model = NodeList.FirstOrDefault(n => n.NodeId == id);
|
||
if (model == null) return;
|
||
|
||
linkModel = new LinkModel
|
||
{
|
||
StartId = id,
|
||
StartAnchor = info[1]
|
||
};
|
||
|
||
if (info[1] == "T")
|
||
{
|
||
linkModel.StartX = model.X + (model.W / 2);
|
||
linkModel.StartY = model.Y + 3;
|
||
}
|
||
else if (info[1] == "B")
|
||
{
|
||
linkModel.StartX = model.X + (model.W / 2);
|
||
linkModel.StartY = model.Y + model.H - 3;
|
||
}
|
||
else if (info[1] == "L")
|
||
{
|
||
linkModel.StartX = model.X + 3;
|
||
linkModel.StartY = model.Y + model.H / 2;
|
||
}
|
||
else if (info[1] == "R")
|
||
{
|
||
linkModel.StartX = model.X + model.W - 3;
|
||
linkModel.StartY = model.Y + model.H / 2;
|
||
}
|
||
|
||
if (model is DecisionNodeModelBase dnmb)
|
||
{
|
||
// T/F
|
||
linkModel.Condition = info[2];
|
||
}
|
||
|
||
linkModel.EndAnchor = "N";
|
||
linkModel.EndX = linkModel.StartX;
|
||
linkModel.EndY = linkModel.StartY;
|
||
//
|
||
LinkList.Add(linkModel);
|
||
isLinking = true;
|
||
|
||
isCanvasDrag = false;
|
||
}
|
||
// 当在锚点释放鼠标的时候
|
||
private void DoAnchorUp(object obj)
|
||
{
|
||
string[] info = obj.ToString().Split(";");
|
||
string id = info[0];
|
||
// 确定对应的节点(Model)
|
||
NodeModelBase model = NodeList.FirstOrDefault(n => n.NodeId == id);
|
||
if (model == null || linkModel == null)
|
||
{
|
||
//LinkList.Remove(linkModel);
|
||
return;
|
||
}
|
||
|
||
linkModel.EndId = id;
|
||
linkModel.EndAnchor = info[1];
|
||
|
||
if (info[1] == "T")
|
||
{
|
||
var result = SetLinkTopPoint(model);
|
||
linkModel.EndX = result.x;
|
||
linkModel.EndY = result.y;
|
||
}
|
||
else if (info[1] == "B")
|
||
{
|
||
linkModel.EndX = model.X + (model.W / 2);
|
||
linkModel.EndY = model.Y + model.H - 3;
|
||
}
|
||
else if (info[1] == "L")
|
||
{
|
||
linkModel.EndX = model.X + 3;
|
||
linkModel.EndY = model.Y + model.H / 2;
|
||
}
|
||
else if (info[1] == "R")
|
||
{
|
||
linkModel.EndX = model.X + model.W - 3;
|
||
linkModel.EndY = model.Y + model.H / 2;
|
||
}
|
||
//LinkList.Add(linkModel);
|
||
|
||
|
||
// 处理连接成功的节点中当前连线的锚点状态
|
||
// 设置终节点的对应的锚点显示
|
||
model.SetAnchorShow(info[1], false);
|
||
// 设置起始节点的对应铁锚点显示
|
||
var start = NodeList.FirstOrDefault(n => n.NodeId == linkModel.StartId);
|
||
if (start != null)
|
||
start.SetAnchorShow(linkModel.StartAnchor, false);
|
||
|
||
model.FlowLevel.Add(start.FlowLevel[0] + 1);
|
||
|
||
isLinking = false;
|
||
|
||
isCanvasDrag = false;
|
||
}
|
||
|
||
private (double x, double y) SetLinkTopPoint(NodeModelBase model)
|
||
{
|
||
double X = model.X + (model.W / 2);
|
||
double Y = model.Y + 3;
|
||
return (X, Y);
|
||
}
|
||
#endregion
|
||
|
||
|
||
#region 执行节点逻辑
|
||
private void DoRunFlowchart()
|
||
{
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
|
||
this.Log("流程", "[开始]");
|
||
Task.Run(() =>
|
||
{
|
||
//Thread.Sleep(2000);
|
||
|
||
DoRunFirst();
|
||
|
||
this.Log("流程", "[结束]");
|
||
|
||
ReleaseIntPrt();
|
||
});
|
||
}
|
||
|
||
private void ReleaseIntPrt()
|
||
{
|
||
var args = this.ArgumentList.Where(a => a.ArgType == "IntPtr").ToList();
|
||
foreach (var item in args)
|
||
{
|
||
object v = item.Value ?? 0;
|
||
if (IntPtr.TryParse(v.ToString(), out IntPtr ptr))
|
||
{
|
||
DeleteObject(ptr);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void DoRunFirst()
|
||
{
|
||
// 开始按顺序执行每个节点中的逻辑
|
||
var node = this.NodeList.FirstOrDefault(n => n.IsStart);
|
||
if (node == null)
|
||
{
|
||
this.Log(node.NodeName, "流程异常,未发现起始节点!");
|
||
}
|
||
else
|
||
{
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
|
||
DoRun(node);
|
||
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
}
|
||
}
|
||
|
||
private void DoRun(NodeModelBase node)
|
||
{
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
|
||
//Thread.Sleep(2000);
|
||
|
||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||
|
||
// 这里是每个节点执行的逻辑
|
||
try
|
||
{
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
if (node is DecisionNodeModelBase dnmb)
|
||
{
|
||
// True / False
|
||
bool result = dnmb.Decision(this);
|
||
|
||
// 找线
|
||
var lm = this.LinkList.FirstOrDefault(l => l.StartId == node.NodeId && (l.Condition == "T") == result);
|
||
if (lm == null)
|
||
return;
|
||
|
||
// 找线另一端的节点
|
||
var next_node = this.NodeList.FirstOrDefault(n => n.NodeId == lm.EndId);
|
||
if (next_node != null)
|
||
this.DoRun(next_node);
|
||
}
|
||
else
|
||
{
|
||
if (!node.IsStart)
|
||
{
|
||
// 执行节点中对应的逻辑
|
||
node.IsRunning = true;
|
||
stopwatch.Restart();
|
||
this.Log(node.NodeName, "[执行]");
|
||
|
||
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
node.Execute(this);
|
||
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
|
||
|
||
Thread.Sleep(1000);
|
||
|
||
stopwatch.Stop();
|
||
node.Duration = stopwatch.ElapsedMilliseconds;
|
||
node.IsRunning = false;
|
||
}
|
||
|
||
if (cts != null && cts.IsCancellationRequested)
|
||
return;
|
||
|
||
// 执行完成后,继续下个节点
|
||
var ls = this.LinkList.Where(l => l.StartId == node.NodeId);
|
||
foreach (var l in ls)
|
||
{
|
||
var next_node = this.NodeList.FirstOrDefault(n => n.NodeId == l.EndId);
|
||
if (next_node != null)
|
||
this.DoRun(next_node);
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
stopwatch.Stop();
|
||
node.Duration = stopwatch.ElapsedMilliseconds;
|
||
node.IsRunning = false;
|
||
|
||
this.Log(node.NodeName, ex.Message);
|
||
}
|
||
}
|
||
|
||
CancellationTokenSource cts;
|
||
private void DoCircleExecute()
|
||
{
|
||
this.Log("流程", "[开始]");
|
||
cts = new CancellationTokenSource();
|
||
Task.Run(() =>
|
||
{
|
||
do
|
||
{
|
||
DoRunFirst();
|
||
} while (!cts.IsCancellationRequested);
|
||
|
||
|
||
this.Log("流程", "[结束]");
|
||
|
||
this.ReleaseIntPrt();
|
||
}, cts.Token);
|
||
}
|
||
|
||
private void DoStopExecute()
|
||
{
|
||
cts?.Cancel();
|
||
}
|
||
|
||
NodeModelBase _currentStepNode;
|
||
bool _decisionResult = false;
|
||
private void DoStepExecute()
|
||
{
|
||
|
||
//if (_currentStepNode == null)
|
||
//{
|
||
// var start = this.NodeList.First();
|
||
// var link = this.LinkList.FirstOrDefault(l => l.StartId == _currentStepNode.NodeId);
|
||
// _currentStepNode = this.NodeList.FirstOrDefault(n => n.NodeId == link.EndId);
|
||
//}
|
||
|
||
|
||
|
||
//if (_currentStepNode is DecisionNodeModelBase dnmb)
|
||
//{
|
||
// _decisionResult = dnmb.Decision(this);
|
||
//}
|
||
//else
|
||
//{
|
||
// _currentStepNode.Execute(this);
|
||
// var ls = this.LinkList.Where(l => l.StartId == _currentStepNode.NodeId).ToList();
|
||
// _currentStepNode = this.NodeList.FirstOrDefault(n => n.NodeId == ls[0].EndId);
|
||
//}
|
||
|
||
var ns = this.NodeList.Where(n => n.FlowLevel.Contains(_currentLevel)).ToList();
|
||
|
||
var ids = this.LinkList.ToList()
|
||
.Where(l => l.EndId == ns[_subIndex].NodeId &&
|
||
(l.Condition == "T") == _decisionResult).ToList()
|
||
.Select(ll => ll.EndId).ToList();
|
||
ns = ns.Where(n => ids.Contains(n.NodeId)).ToList();
|
||
|
||
//if (this.LinkList.ToList().Exists(l => l.EndId == ns[_subIndex].NodeId &&
|
||
// (l.Condition == "T") == _decisionResult))
|
||
{
|
||
if (ns[_subIndex] is DecisionNodeModelBase dnmb)
|
||
{
|
||
_decisionResult = dnmb.Decision(this);
|
||
}
|
||
else
|
||
{
|
||
ns[_subIndex].Execute(this);
|
||
}
|
||
}
|
||
|
||
_subIndex++;
|
||
if (_subIndex >= ns.Count)
|
||
{
|
||
_currentLevel = ns[_subIndex - 1].FlowLevel[0] + 1;
|
||
if (_currentLevel > this.NodeList.Max(n => n.FlowLevel.Max(fl => fl)))
|
||
_currentLevel = 1;
|
||
_subIndex = 0;
|
||
}
|
||
}
|
||
int _currentLevel = 1;
|
||
int _subIndex = 0;
|
||
#endregion
|
||
|
||
#region 添加参数
|
||
private void DoAddArgument()
|
||
{
|
||
ArgumentList.Add(new FlowArgModel());
|
||
}
|
||
private void DoDelArgument(object obj)
|
||
{
|
||
ArgumentList.Remove(obj as FlowArgModel);
|
||
}
|
||
|
||
private void DoSelectFolder(object obj)
|
||
{
|
||
var model = obj as NodeArgModel;
|
||
|
||
OpenFolderDialog dialog = new OpenFolderDialog();
|
||
if (dialog.ShowDialog() == true)
|
||
model.ArgValue = dialog.FolderName;
|
||
}
|
||
#endregion
|
||
|
||
|
||
// 这里内存一直增长 需要优化
|
||
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
|
||
public static extern bool DeleteObject(IntPtr hObject);
|
||
|
||
public void ShowImage(IntPtr img_handler)
|
||
{
|
||
BitmapImage bitmapImage = new BitmapImage();
|
||
using (var ms = new MemoryStream())
|
||
{
|
||
System.Drawing.Bitmap bitmap =
|
||
System.Drawing.Bitmap.FromHbitmap(img_handler);
|
||
|
||
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
|
||
ms.Position = 0;
|
||
|
||
bitmapImage.BeginInit();
|
||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||
bitmapImage.StreamSource = ms;
|
||
bitmapImage.EndInit();
|
||
bitmapImage.Freeze();
|
||
}
|
||
|
||
PreviewImage = bitmapImage;
|
||
//DeleteObject(img_handler);
|
||
}
|
||
|
||
|
||
public string FilePath { get; set; }
|
||
|
||
public void Save()
|
||
{
|
||
// 选择保存地址---再保存的进候需要选择?
|
||
if (string.IsNullOrEmpty(FilePath))
|
||
{
|
||
SaveFileDialog dialog = new SaveFileDialog();
|
||
dialog.Filter = "流程文件(*.flw)|*.flw";
|
||
if (dialog.ShowDialog() == true)
|
||
{
|
||
FilePath = dialog.FileName;
|
||
}
|
||
}
|
||
|
||
try
|
||
{
|
||
// Bug:简单的Json文件保存会导致实例丢失 无法执行实例中的方法
|
||
// 需要处理!!!!!
|
||
|
||
// 每个子项单独保存 记录类型名称
|
||
// 通信序列化对象进行多态对象的序列化与反序列,需要对基类进行配置
|
||
string node_json = System.Text.Json.JsonSerializer.Serialize(this.NodeList);
|
||
string link_json = System.Text.Json.JsonSerializer.Serialize(this.LinkList);
|
||
string arg_json = System.Text.Json.JsonSerializer.Serialize(this.ArgumentList);
|
||
|
||
string temp =
|
||
this.Title + "@#$#@" +
|
||
node_json + "@#$#@" +
|
||
link_json + "@#$#@" +
|
||
arg_json;
|
||
|
||
System.IO.File.WriteAllText(FilePath, temp);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
this.Log("流程保存", ex.Message);
|
||
}
|
||
}
|
||
|
||
|
||
#region 画布缩放
|
||
public void DoMainZoom(object sender, MouseWheelEventArgs e)
|
||
{
|
||
//e.GetPosition
|
||
this.MainZoom += e.Delta > 0 ? 0.05 : -0.05;
|
||
|
||
// 检查放缩放比, 在1.5和0.5之间缩放 倍数
|
||
if (MainZoom < 0.5)
|
||
MainZoom = 0.5;
|
||
if (MainZoom > 1.5)
|
||
MainZoom = 1.5;
|
||
|
||
|
||
var hwakeye = (sender as FrameworkElement).Tag;
|
||
this.CheckCanvasLocation(sender, hwakeye);
|
||
}
|
||
|
||
|
||
|
||
public void DoCanvasMouseMove(object? sender, MouseEventArgs e)
|
||
{
|
||
if (isCanvasDrag && !isLinking && !_is_moving)
|
||
{
|
||
Point p = e.GetPosition((IInputElement)e.Source);
|
||
//
|
||
double x = p.X - startCanvas.X;
|
||
double y = p.Y - startCanvas.Y;
|
||
|
||
DragX += x;
|
||
DragY += y;
|
||
|
||
var hwakeye = (sender as FrameworkElement).Tag;
|
||
CheckCanvasLocation(sender, hwakeye);
|
||
}
|
||
}
|
||
|
||
private void CheckCanvasLocation(object? sender, object hwakeye)
|
||
{
|
||
var canvas = sender as FrameworkElement;
|
||
|
||
var parent = canvas.Parent as FrameworkElement;
|
||
// -250 -200
|
||
Point left_top = canvas.TranslatePoint(new Point(0, 0), parent);
|
||
Point right_bottom = canvas.TranslatePoint(new Point(canvas.ActualWidth, canvas.ActualHeight), parent);
|
||
double trans_w = right_bottom.X - left_top.X;
|
||
double trans_h = right_bottom.Y - left_top.Y;
|
||
|
||
if (left_top.X > 0)
|
||
{
|
||
DragX = (trans_w - parent.ActualWidth) / 2;
|
||
}
|
||
if (left_top.Y > 0)
|
||
{
|
||
DragY = (trans_h - parent.ActualHeight) / 2;
|
||
}
|
||
if (right_bottom.X < parent.ActualWidth)
|
||
{
|
||
DragX = (trans_w - parent.ActualWidth) / 2 * -1;
|
||
}
|
||
if (right_bottom.Y < parent.ActualHeight)
|
||
{
|
||
DragY = (trans_h - parent.ActualHeight) / 2 * -1;
|
||
}
|
||
|
||
|
||
// 鹰眼缩放
|
||
this.HwakeyeZoom = parent.ActualWidth / trans_w / 0.5;
|
||
|
||
// 鹰眼位移
|
||
var fe = hwakeye as FrameworkElement;
|
||
this.HwakeyeDragX = (DragX * -1 / canvas.ActualWidth) * fe.ActualWidth;
|
||
this.HwakeyeDragY = (DragY * -1 / canvas.ActualHeight) * fe.ActualHeight;
|
||
}
|
||
|
||
private void DoCanvasMouseUp(object? obj)
|
||
{
|
||
isCanvasDrag = false;
|
||
}
|
||
|
||
bool isCanvasDrag = false;
|
||
Point startCanvas = new Point(0, 0);
|
||
private void DoCanvasMouseDown(object? obj)
|
||
{
|
||
var e = obj as MouseButtonEventArgs;
|
||
isCanvasDrag = true;
|
||
startCanvas = e.GetPosition((IInputElement)e.Source);
|
||
}
|
||
|
||
|
||
|
||
|
||
bool is_hwakeye_drag = false;
|
||
Point hwakeye_down_p = new Point(0, 0);
|
||
FrameworkElement fe_hwakeye_view = null;
|
||
public void HwakeyeViewMouseDown(object sender, MouseButtonEventArgs e)
|
||
{
|
||
is_hwakeye_drag = true;
|
||
hwakeye_down_p = e.GetPosition((IInputElement)sender);
|
||
fe_hwakeye_view = sender as FrameworkElement;
|
||
}
|
||
public void HwakeyeMouseMove(object sender, MouseEventArgs e)
|
||
{
|
||
if (is_hwakeye_drag)
|
||
{
|
||
Point p = e.GetPosition((IInputElement)e.Source);
|
||
|
||
double x = p.X - hwakeye_down_p.X;
|
||
double y = p.Y - hwakeye_down_p.Y;
|
||
|
||
HwakeyeDragX += x;
|
||
HwakeyeDragY += y;
|
||
|
||
// 边缘检测
|
||
var parent = sender as FrameworkElement;
|
||
Point left_top = fe_hwakeye_view.TranslatePoint(new Point(0, 0), parent);
|
||
Point right_bottom = fe_hwakeye_view.TranslatePoint(new Point(fe_hwakeye_view.ActualWidth, fe_hwakeye_view.ActualHeight), parent);
|
||
double trans_w = right_bottom.X - left_top.X;
|
||
double trans_h = right_bottom.Y - left_top.Y;
|
||
|
||
if (left_top.X < 0)
|
||
{
|
||
HwakeyeDragX = (trans_w - parent.ActualWidth) / 2;
|
||
}
|
||
if (left_top.Y < 0)
|
||
{
|
||
HwakeyeDragY = (trans_h - parent.ActualHeight) / 2;
|
||
}
|
||
if (right_bottom.X > parent.ActualWidth)
|
||
{
|
||
HwakeyeDragX = (trans_w - parent.ActualWidth) / 2 * -1;
|
||
}
|
||
if (right_bottom.Y > parent.ActualHeight)
|
||
{
|
||
HwakeyeDragY = (trans_h - parent.ActualHeight) / 2 * -1;
|
||
}
|
||
|
||
|
||
// 同步画布的位移
|
||
var canvas = (sender as FrameworkElement).Tag as FrameworkElement;
|
||
DragX = HwakeyeDragX * -1 / parent.ActualWidth * canvas.ActualWidth;
|
||
DragY = HwakeyeDragY * -1 / parent.ActualHeight * canvas.ActualHeight;
|
||
}
|
||
}
|
||
public void HwakeyeMouseUp(object sender, MouseButtonEventArgs e)
|
||
{
|
||
is_hwakeye_drag = false;
|
||
}
|
||
|
||
|
||
|
||
|
||
private void DoZoomIncrease(object? obj)
|
||
{
|
||
this.MainZoom += 0.05;
|
||
|
||
// 检查放缩放比, 在1.5和0.5之间缩放 倍数
|
||
if (MainZoom > 1.5)
|
||
MainZoom = 1.5;
|
||
|
||
var hwakeye = (obj as FrameworkElement).Tag;
|
||
this.CheckCanvasLocation(obj, hwakeye);
|
||
}
|
||
|
||
private void DoZoomReduce(object? obj)
|
||
{
|
||
this.MainZoom -= 0.05;
|
||
|
||
// 检查放缩放比, 在1.5和0.5之间缩放 倍数
|
||
if (MainZoom < 0.5)
|
||
MainZoom = 0.5;
|
||
|
||
var hwakeye = (obj as FrameworkElement).Tag;
|
||
this.CheckCanvasLocation(obj, hwakeye);
|
||
}
|
||
|
||
private void DoZoomReset(object? obj)
|
||
{
|
||
this.MainZoom = 1;
|
||
|
||
var hwakeye = (obj as FrameworkElement).Tag;
|
||
this.CheckCanvasLocation(obj, hwakeye);
|
||
}
|
||
#endregion
|
||
|
||
|
||
|
||
private void Log(string node_name, string message)
|
||
{
|
||
Application.Current.Dispatcher.Invoke(new Action(() =>
|
||
{
|
||
if (LogList.Count>1000)
|
||
{
|
||
LogList.RemoveAt(0);
|
||
}
|
||
// 数据量增大
|
||
this.LogList.Add(new LogModel
|
||
{
|
||
Time = DateTime.Now,
|
||
NodeName = node_name,
|
||
LogMessage = message,
|
||
});
|
||
}));
|
||
}
|
||
}
|
||
}
|