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(ref _isCurrent, value); if (!value) TitleEditVisible = Visibility.Hidden; } } #region Title与编辑 private string _title; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private Visibility _titleEditVisible = Visibility.Hidden; public Visibility TitleEditVisible { get { return _titleEditVisible; } set { SetProperty(ref _titleEditVisible, value); } } public ICommand SelectCommand { get; set; } public ICommand EditTitleCommand { get; set; } public ICommand AcceptTitleCommand { get; set; } #endregion #region 节点创建 public ObservableCollection NodeList { get; set; } = new ObservableCollection(); public ICommand DragDropCommand { get; set; } public ICommand DeleteElementCommand { get; set; } #endregion #region 连线集合 public ObservableCollection LinkList { get; set; } = new ObservableCollection(); #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 ArgumentList { get; set; } = new ObservableCollection(); public ICommand AddArgumentCommand { get; set; } public ICommand DelArgumentCommand { get; set; } public List ArgTypeList { get; set; } = new List { "Int32","IntPtr","Double","String","Boolean" }; // 参数处理相关命令 public ICommand SelectFolderCommand { get; set; } #endregion private ImageSource _previewImage; /// /// 预览图像 /// public ImageSource PreviewImage { get { return _previewImage; } set { SetProperty(ref _previewImage, value); } } public ObservableCollection LogList { get; set; } = new ObservableCollection(); //画布缩放 #region 画布缩放 private double _mainZoom = 1.0; public double MainZoom { get { return _mainZoom; } set { SetProperty(ref _mainZoom, value); } } private double _dragX = 0; public double DragX { get { return _dragX; } set { SetProperty(ref _dragX, value); } } private double _dragY = 0; public double DragY { get { return _dragY; } set { SetProperty(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(ref _hwakeyeZoom, value); } } private double _hwakeyeDragX; public double HwakeyeDragX { get { return _hwakeyeDragX; } set { SetProperty(ref _hwakeyeDragX, value); } } private double _hwakeyeDragY; public double HwakeyeDragY { get { return _hwakeyeDragY; } set { SetProperty(ref _hwakeyeDragY, value); } } #endregion public List Operator { get; set; } = new List { "=","<",">","<=",">=","!=" }; public FlowTabViewModel() { SelectCommand = new RelayCommand(() => { this.IsCurrent = true; }); DragDropCommand = new RelayCommand(OnDragDrop); DeleteElementCommand = new RelayCommand(DoElementDelete); #region Tab Title编辑动作 EditTitleCommand = new RelayCommand(() => { TitleEditVisible = Visibility.Visible; }); AcceptTitleCommand = new RelayCommand(() => { TitleEditVisible = Visibility.Hidden; }); #endregion #region 节点移动动作 NodeMouseDownCommand = new RelayCommand(OnNodeMouseDown); NodeMouseMoveCommand = new RelayCommand(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(OnAnchorDown); NodeList.Add(new StartNodeModel { IsStart = true, TargetNodeObject = node_name, X = 600, Y = 450, W = 100, H = 34, FlowLevel = new List { 0 } }); // 流程控制 RunCommand = new RelayCommand(DoRunFlowchart); CircleCommand = new RelayCommand(DoCircleExecute); StopCommand = new RelayCommand(DoStopExecute); StepCommand = new RelayCommand(DoStepExecute); // 添加参数 AddArgumentCommand = new RelayCommand(DoAddArgument); DelArgumentCommand = new RelayCommand(DoDelArgument); // 参数列表命令 SelectFolderCommand = new RelayCommand(DoSelectFolder); // 锚点控制 AnchorDownCommand = new RelayCommand(DoAnchorDown); AnchorUpCommand = new RelayCommand(DoAnchorUp); // 缩放操作 //MouseWheelCommand = new RelayCommand(DoMainZoom); CanvasMouseDownCommand = new RelayCommand(DoCanvasMouseDown); CanvasMouseUpCommand = new RelayCommand(DoCanvasMouseUp); //CanvasMouseMoveCommand = new RelayCommand(DoCanvasMouseMove); ZoomIncreaseCommand = new RelayCommand(DoZoomIncrease); ZoomReduceCommand = new RelayCommand(DoZoomReduce); ZoomResetCommand = new RelayCommand(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(OnAnchorDown); //(instance as INodeBase).AnchorUpCommand = // new RelayCommand(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, }); })); } } }