Files
wpf-visual-process-framework/VisionFrame/ViewModels/FlowTabViewModel.cs
2025-07-14 21:08:46 +08:00

1114 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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(() =>
{
// 数据量增大
this.LogList.Add(new LogModel
{
Time = DateTime.Now,
NodeName = node_name,
LogMessage = message,
});
}));
}
}
}