mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-02 15:50:47 +08:00
解决了接口节点的参数共享,UI控件的Menu菜单事件穿透问题,同时优化了工作台画布流程相关事件的部分代码
This commit is contained in:
@@ -61,6 +61,7 @@ namespace Serein.Workbench
|
||||
{
|
||||
getSyncContext = () => uiContext;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
UIContextOperation? uIContextOperation = null;
|
||||
@@ -84,6 +85,12 @@ namespace Serein.Workbench
|
||||
public partial class App : Application
|
||||
{
|
||||
private static IServiceProvider? ServiceProvider;
|
||||
|
||||
/// <summary>
|
||||
/// UI线程
|
||||
/// </summary>
|
||||
public static UIContextOperation UIContextOperation => App.GetService<UIContextOperation>() ?? throw new NullReferenceException();
|
||||
|
||||
public static T GetService<T>() where T : class
|
||||
{
|
||||
return ServiceProvider?.GetService<T>() ?? throw new NullReferenceException();
|
||||
@@ -111,7 +118,7 @@ namespace Serein.Workbench
|
||||
{
|
||||
await Task.Delay(500);
|
||||
#if DEBUG
|
||||
if (1 ==1)
|
||||
if (1 == 1)
|
||||
{
|
||||
// 这里是测试代码,可以删除
|
||||
string filePath;
|
||||
|
||||
@@ -60,7 +60,15 @@ namespace Serein.Workbench.Node.View
|
||||
endPoint = end;
|
||||
this.strokeThickness = 4;
|
||||
InitElementPoint(isDotted, isTop);
|
||||
InvalidateVisual(); // 触发重绘
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await App.UIContextOperation.InvokeAsync(() =>
|
||||
{
|
||||
InvalidateVisual(); // 触发重绘
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Serein.Library;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.Workbench.Api;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.Themes;
|
||||
using Serein.Workbench.Views;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -146,7 +148,7 @@ namespace Serein.Workbench.Node.View
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="parent"></param>
|
||||
/// <returns></returns>
|
||||
protected T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
|
||||
protected static T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
||||
{
|
||||
@@ -165,13 +167,58 @@ namespace Serein.Workbench.Node.View
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static JunctionControlBase[] GetArgJunction(NodeControlBase nodeControl, MethodDetailsControl methodDetailsControl)
|
||||
{
|
||||
// 获取 MethodDetailsControl 实例
|
||||
try
|
||||
{
|
||||
var itemsControl = FindVisualChild<ItemsControl>(methodDetailsControl); // 查找 ItemsControl
|
||||
if (itemsControl != null)
|
||||
{
|
||||
var md = nodeControl.ViewModel.NodeModel.MethodDetails;
|
||||
if (md is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
if(md.ParameterDetailss is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
var argDataJunction = new JunctionControlBase[md.ParameterDetailss.Length];
|
||||
var controls = new List<JunctionControlBase>();
|
||||
|
||||
for (int i = 0; i < itemsControl.Items.Count; i++)
|
||||
{
|
||||
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
|
||||
if (container != null)
|
||||
{
|
||||
var argControl = FindVisualChild<ArgJunctionControl>(container);
|
||||
if (argControl != null)
|
||||
{
|
||||
controls.Add(argControl); // 收集 ArgJunctionControl 实例
|
||||
}
|
||||
}
|
||||
}
|
||||
return argDataJunction = controls.ToArray();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
SereinEnv.WriteLine(InfoType.ERROR,$"节点获取入参控制点时发生异常{Environment.NewLine}节点:{nodeControl.ViewModel.NodeModel.Guid}");
|
||||
SereinEnv.WriteLine(ex);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//public class FLowNodeObObservableCollection<T> : ObservableCollection<T>
|
||||
//{
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.Library;
|
||||
using Serein.NodeFlow.Model;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.Themes;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
@@ -42,35 +44,7 @@ namespace Serein.Workbench.Node.View
|
||||
/// <summary>
|
||||
/// 方法入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction();
|
||||
|
||||
private JunctionControlBase[] GetArgJunction()
|
||||
{
|
||||
// 获取 MethodDetailsControl 实例
|
||||
var methodDetailsControl = this.MethodDetailsControl;
|
||||
var itemsControl = FindVisualChild<ItemsControl>(methodDetailsControl); // 查找 ItemsControl
|
||||
if (itemsControl != null)
|
||||
{
|
||||
var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length];
|
||||
var controls = new List<JunctionControlBase>();
|
||||
|
||||
for (int i = 0; i < itemsControl.Items.Count; i++)
|
||||
{
|
||||
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
|
||||
if (container != null)
|
||||
{
|
||||
var argControl = FindVisualChild<ArgJunctionControl>(container);
|
||||
if (argControl != null)
|
||||
{
|
||||
controls.Add(argControl); // 收集 ArgJunctionControl 实例
|
||||
}
|
||||
}
|
||||
}
|
||||
return argDataJunction = controls.ToArray();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction(this, MethodDetailsControl);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace Serein.Workbench.Node.View
|
||||
{
|
||||
leftCenterOfEndLocation = Start.MyCenterPoint;
|
||||
rightCenterOfStartLocation = End.MyCenterPoint;
|
||||
|
||||
|
||||
(Point startPoint, Point endPoint) = RefreshPoint(Canvas, Start, End);
|
||||
var connectionType = Start.JunctionType.ToConnectyionType();
|
||||
bool isDotted;
|
||||
@@ -214,7 +214,7 @@ namespace Serein.Workbench.Node.View
|
||||
BezierLine = new ConnectionLineShape(LineType, startPoint, endPoint, brush, isDotted);
|
||||
Grid.SetZIndex(BezierLine, -9999999); // 置底
|
||||
Canvas.Children.Add(BezierLine);
|
||||
|
||||
|
||||
ConfigureLineContextMenu(); //配置右键菜单
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace Serein.Workbench.Node.View
|
||||
/// 方法入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
private JunctionControlBase[] argDataJunction;
|
||||
|
||||
/// <summary>
|
||||
/// 方法入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
|
||||
@@ -34,34 +34,7 @@ namespace Serein.Workbench.Node.View
|
||||
/// <summary>
|
||||
/// 方法入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction();
|
||||
|
||||
private JunctionControlBase[] GetArgJunction()
|
||||
{
|
||||
// 获取 MethodDetailsControl 实例
|
||||
var methodDetailsControl = this.MethodDetailsControl;
|
||||
var itemsControl = FindVisualChild<ItemsControl>(methodDetailsControl); // 查找 ItemsControl
|
||||
if (itemsControl != null)
|
||||
{
|
||||
var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length];
|
||||
var controls = new List<JunctionControlBase>();
|
||||
|
||||
for (int i = 0; i < itemsControl.Items.Count; i++)
|
||||
{
|
||||
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
|
||||
if (container != null)
|
||||
{
|
||||
var argControl = FindVisualChild<ArgJunctionControl>(container);
|
||||
if (argControl != null)
|
||||
{
|
||||
controls.Add(argControl); // 收集 ArgJunctionControl 实例
|
||||
}
|
||||
}
|
||||
}
|
||||
return argDataJunction = controls.ToArray();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction(this, MethodDetailsControl);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,36 +55,9 @@ namespace Serein.Workbench.Node.View
|
||||
/// <summary>
|
||||
/// 方法入参控制点(可能有,可能没)
|
||||
/// </summary>
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction();
|
||||
|
||||
private JunctionControlBase[] GetArgJunction()
|
||||
{
|
||||
// 获取 MethodDetailsControl 实例
|
||||
//var methodDetailsControl = ViewModel.NodeModel.IsShareParam ? this.SelectMethodDetailsControl : this.MyMethodDetailsControl;
|
||||
var methodDetailsControl = this.MethodDetailsControl;
|
||||
var itemsControl = FindVisualChild<ItemsControl>(methodDetailsControl); // 查找 ItemsControl
|
||||
if (itemsControl != null)
|
||||
{
|
||||
var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length];
|
||||
var controls = new List<JunctionControlBase>();
|
||||
|
||||
for (int i = 0; i < itemsControl.Items.Count; i++)
|
||||
{
|
||||
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
|
||||
if (container != null)
|
||||
{
|
||||
var argControl = FindVisualChild<ArgJunctionControl>(container);
|
||||
if (argControl != null)
|
||||
{
|
||||
controls.Add(argControl); // 收集 ArgJunctionControl 实例
|
||||
}
|
||||
}
|
||||
}
|
||||
return argDataJunction = controls.ToArray();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction(this,MethodDetailsControl);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,9 @@
|
||||
|
||||
</Grid>
|
||||
|
||||
<Border Grid.Row="1" x:Name="EmbedContainer" BorderBrush="Black" BorderThickness="1"
|
||||
Width="500" Height="400"/>
|
||||
<Border x:Name="EmbedContainer" Width="200" Height="200" Grid.Row="1" BorderBrush="Black" BorderThickness="1">
|
||||
<!--<ContentControl />-->
|
||||
</Border>
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Serein.Workbench.Node.View
|
||||
/// </summary>
|
||||
public partial class UINodeControl : NodeControlBase, INodeJunction
|
||||
{
|
||||
private new UINodeControlViewModel ViewModel { get; }
|
||||
public UINodeControl()
|
||||
{
|
||||
base.ViewModel.IsEnabledOnView = true;
|
||||
@@ -30,6 +31,7 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
public UINodeControl(UINodeControlViewModel viewModel) : base(viewModel)
|
||||
{
|
||||
ViewModel = viewModel;
|
||||
DataContext = viewModel;
|
||||
InitializeComponent();
|
||||
|
||||
@@ -49,8 +51,8 @@ namespace Serein.Workbench.Node.View
|
||||
|
||||
private void NodeControlBase_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UINodeControlViewModel vm = (UINodeControlViewModel)DataContext;
|
||||
vm.InitAdapter(userControl => {
|
||||
//ViewModel.InitAdapter();
|
||||
ViewModel.InitAdapter(userControl => {
|
||||
EmbedContainer.Child = userControl;
|
||||
});
|
||||
|
||||
|
||||
@@ -68,10 +68,9 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (targetNodeControl.FlowCanvas is FlowCanvasView view
|
||||
&& view.DataContext is FlowCanvasViewModel viewModel)
|
||||
if (targetNodeControl.FlowCanvas is FlowCanvasView view )
|
||||
{
|
||||
SelectCanvas = viewModel;
|
||||
SelectCanvas = view.ViewModel;
|
||||
SelectNode = targetNodeControl.ViewModel.NodeModel;
|
||||
}
|
||||
}
|
||||
@@ -80,8 +79,10 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
flowEEForwardingService.OnCanvasCreate += (e) => RershCanvass(); // 画布创建了
|
||||
flowEEForwardingService.OnCanvasRemove += (e) => RershCanvass(); // 画布移除了
|
||||
|
||||
}
|
||||
|
||||
|
||||
partial void OnSelectCanvasChanged(FlowCanvasViewModel value)
|
||||
{
|
||||
FlowCallNode.ResetTargetNode();
|
||||
@@ -89,7 +90,12 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
|
||||
partial void OnSelectNodeChanged(NodeModelBase value)
|
||||
{
|
||||
FlowCallNode.SetTargetNode(value);
|
||||
if(value is null)
|
||||
{
|
||||
FlowCallNode.ResetTargetNode();
|
||||
return;
|
||||
}
|
||||
FlowCallNode.SetTargetNode(value.Guid);
|
||||
}
|
||||
|
||||
private void RershCanvass()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Serein.Library;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Serein.Library;
|
||||
using Serein.Library.Api;
|
||||
using Serein.NodeFlow.Model;
|
||||
using System;
|
||||
@@ -10,17 +11,24 @@ using System.Windows.Controls;
|
||||
|
||||
namespace Serein.Workbench.Node.ViewModel
|
||||
{
|
||||
public class UINodeControlViewModel : NodeControlViewModelBase
|
||||
public partial class UINodeControlViewModel : NodeControlViewModelBase
|
||||
{
|
||||
private SingleUINode NodeModel => (SingleUINode)base.NodeModel;
|
||||
//public IEmbeddedContent Adapter => NodeModel.Adapter;
|
||||
|
||||
/// <summary>
|
||||
/// 节点UI的对应内容
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private UserControl _nodeUIContent;
|
||||
|
||||
|
||||
public UINodeControlViewModel(NodeModelBase nodeModel) : base(nodeModel)
|
||||
{
|
||||
//NodeModel.Adapter.GetWindowHandle();
|
||||
|
||||
}
|
||||
|
||||
public void InitAdapter(Action<UserControl> setUIDisplayHandle)
|
||||
public void InitAdapter()
|
||||
{
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
@@ -32,11 +40,32 @@ namespace Serein.Workbench.Node.ViewModel
|
||||
&& NodeModel.Adapter.GetUserControl() is UserControl userControl)
|
||||
{
|
||||
NodeModel.Env.UIContextOperation.Invoke(() =>
|
||||
{
|
||||
NodeUIContent = userControl;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void InitAdapter(Action<UserControl> setUIDisplayHandle)
|
||||
{
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
var context = new DynamicContext(NodeModel.Env);
|
||||
var cts = new CancellationTokenSource();
|
||||
var result = await NodeModel.ExecutingAsync(context, cts.Token);
|
||||
cts?.Dispose();
|
||||
if (context.NextOrientation == ConnectionInvokeType.IsSucceed
|
||||
&& NodeModel.Adapter.GetUserControl() is UserControl userControl)
|
||||
{
|
||||
NodeModel.Env.UIContextOperation.Invoke(() =>
|
||||
{
|
||||
setUIDisplayHandle.Invoke(userControl);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using Serein.Library;
|
||||
using Serein.Library.Utils;
|
||||
using Serein.Workbench.Avalonia.Api;
|
||||
using Serein.Workbench.Api;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Serein.Workbench.Services
|
||||
{
|
||||
|
||||
@@ -8,7 +8,9 @@ using Serein.Workbench.Node.View;
|
||||
using Serein.Workbench.Node.ViewModel;
|
||||
using Serein.Workbench.ViewModels;
|
||||
using Serein.Workbench.Views;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
@@ -210,7 +212,9 @@ namespace Serein.Workbench.Services
|
||||
(JunctionOfConnectionType.Arg, NodeConnectChangeEventArgs.ConnectChangeType.Remove) => () => flow.RemoveArgConnection(fromNode, toNode, e.ArgIndex), // 移除节点之间的参数传递关系
|
||||
_ => null
|
||||
};
|
||||
|
||||
action?.Invoke();
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
@@ -32,10 +32,7 @@ namespace Serein.Workbench.ViewModels
|
||||
/// <param name="flowCanvas"></param>
|
||||
private void OnViewCanvasChanged(FlowCanvasView flowCanvas)
|
||||
{
|
||||
if (flowCanvas.DataContext is FlowCanvasViewModel vm)
|
||||
{
|
||||
Model = vm.Model;
|
||||
}
|
||||
Model = flowCanvas.ViewModel.Model;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace Serein.Workbench.ViewModels
|
||||
{
|
||||
public partial class FlowCanvasViewModel : ObservableObject
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 画布当前的节点
|
||||
/// </summary>
|
||||
|
||||
@@ -43,16 +43,16 @@ namespace Serein.Workbench.ViewModels
|
||||
|
||||
flowNodeService.OnCreateFlowCanvasView += OnCreateFlowCanvasView; // 创建了画布
|
||||
flowNodeService.OnRemoveFlowCanvasView += OnRemoveFlowCanvasView; // 移除了画布
|
||||
this.PropertyChanged += OnPropertyChanged;
|
||||
//this.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
}
|
||||
|
||||
private void OnPropertyChanged(object? value, PropertyChangedEventArgs e)
|
||||
partial void OnSelectedTabChanged(FlowEditorTabModel value)
|
||||
{
|
||||
if (this.SelectedTab is null) return;
|
||||
flowNodeService.CurrentSelectCanvas = this.SelectedTab.Content;
|
||||
flowNodeService.CurrentSelectCanvas = value.Content;
|
||||
}
|
||||
|
||||
|
||||
#region 响应环境事件
|
||||
private void OnCreateFlowCanvasView(FlowCanvasView canvas)
|
||||
{
|
||||
|
||||
@@ -52,187 +52,17 @@ namespace Serein.Workbench.Views
|
||||
private readonly IFlowEnvironment flowEnvironment;
|
||||
private readonly IKeyEventService keyEventService;
|
||||
private readonly FlowNodeService flowNodeService;
|
||||
private readonly IFlowEEForwardingService flowEEForwardingService;
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有的连接。考虑集成在运行环境中。
|
||||
/// </summary>
|
||||
private List<ConnectionControl> Connections { get; } = [];
|
||||
/// <summary>
|
||||
/// 画布模型
|
||||
/// </summary>
|
||||
public FlowCanvasViewModel ViewModel => this.DataContext as FlowCanvasViewModel ?? throw new ArgumentNullException();
|
||||
|
||||
private FlowCanvasViewModel ViewModel => this.DataContext as FlowCanvasViewModel ?? throw new ArgumentNullException();
|
||||
|
||||
#region 画布接口实现
|
||||
private IFlowCanvas Api => this;
|
||||
|
||||
public string Guid
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewModel.Model.Guid;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name => ViewModel.Model.Name;
|
||||
FlowCanvasDetails IFlowCanvas.Model => ViewModel.Model;
|
||||
void IFlowCanvas.Remove(NodeControlBase nodeControl)
|
||||
{
|
||||
ViewModel.NodeControls.Remove(nodeControl.ViewModel.NodeModel.Guid);
|
||||
FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
{
|
||||
FlowChartCanvas.Children.Remove(nodeControl);
|
||||
});
|
||||
}
|
||||
void IFlowCanvas.Add(NodeControlBase nodeControl)
|
||||
{
|
||||
ViewModel.NodeControls.TryAdd(nodeControl.ViewModel.NodeModel.Guid, nodeControl);
|
||||
FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
{
|
||||
FlowChartCanvas.Children.Add(nodeControl);
|
||||
if(nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.UI)
|
||||
{
|
||||
// 需要切换到对应画布,尽可能让UI线程获取到适配器
|
||||
var edit = App.GetService<Locator>().FlowEditViewModel;
|
||||
var tab = edit.CanvasTabs.First(tab => tab.Content == this);
|
||||
App.GetService<Locator>().FlowEditViewModel.SelectedTab = tab;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
ConfigureNodeEvents(nodeControl); // 配置相关事件
|
||||
ConfigureContextMenu(nodeControl); // 添加右键菜单
|
||||
|
||||
}
|
||||
|
||||
void IFlowCanvas.CreateInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, ConnectionInvokeType type)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
var connection = new ConnectionControl(
|
||||
FlowChartCanvas,
|
||||
type,
|
||||
startJunction,
|
||||
endJunction
|
||||
);
|
||||
|
||||
//if (toNodeControl is FlipflopNodeControl flipflopControl
|
||||
// && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
|
||||
//{
|
||||
// NodeTreeViewer.RemoveGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
||||
//}
|
||||
Connections.Add(connection);
|
||||
fromNodeControl.AddCnnection(connection);
|
||||
toNodeControl.AddCnnection(connection);
|
||||
EndConnection(); // 环境触发了创建节点连接事件
|
||||
|
||||
|
||||
}
|
||||
void IFlowCanvas.RemoveInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
var removeConnections = Connections.Where(c =>
|
||||
c.Start.Equals(startJunction)
|
||||
&& c.End.Equals(endJunction)
|
||||
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
|
||||
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
|
||||
.ToList();
|
||||
|
||||
|
||||
foreach (var connection in removeConnections)
|
||||
{
|
||||
Connections.Remove(connection);
|
||||
fromNodeControl.RemoveConnection(connection); // 移除连接
|
||||
toNodeControl.RemoveConnection(connection); // 移除连接
|
||||
|
||||
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||
//{
|
||||
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||
//}
|
||||
}
|
||||
}
|
||||
void IFlowCanvas.CreateArgConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl,ConnectionArgSourceType type, int index)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的情况");
|
||||
return;
|
||||
}
|
||||
|
||||
JunctionControlBase startJunction = type switch
|
||||
{
|
||||
ConnectionArgSourceType.GetPreviousNodeData => IFormJunction.ReturnDataJunction, // 自身节点
|
||||
ConnectionArgSourceType.GetOtherNodeData => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||
ConnectionArgSourceType.GetOtherNodeDataOfInvoke => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||
_ => throw new Exception("窗体事件 FlowEnvironment_NodeConnectChangeEvemt 创建/删除节点之间的参数传递关系 JunctionControlBase 枚举值错误 。非预期的枚举值。") // 应该不会触发
|
||||
};
|
||||
|
||||
if (IToJunction.ArgDataJunction.Length <= index)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(500);
|
||||
Api.CreateArgConnection(fromNodeControl, toNodeControl, type, index);
|
||||
});
|
||||
return; // // 尝试重新连接
|
||||
}
|
||||
JunctionControlBase endJunction = IToJunction.ArgDataJunction[index];
|
||||
LineType lineType = LineType.Bezier;
|
||||
// 添加连接
|
||||
var connection = new ConnectionControl(
|
||||
lineType,
|
||||
FlowChartCanvas,
|
||||
index,
|
||||
type,
|
||||
startJunction,
|
||||
endJunction,
|
||||
IToJunction
|
||||
);
|
||||
Connections.Add(connection);
|
||||
fromNodeControl.AddCnnection(connection);
|
||||
toNodeControl.AddCnnection(connection);
|
||||
EndConnection(); // 环境触发了创建节点连接事件
|
||||
}
|
||||
void IFlowCanvas.RemoveArgConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, int index)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
var removeConnections = Connections.Where(c =>
|
||||
c.Start.Equals(startJunction)
|
||||
&& c.End.Equals(endJunction)
|
||||
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
|
||||
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
|
||||
.ToList();
|
||||
|
||||
|
||||
foreach (var connection in removeConnections)
|
||||
{
|
||||
Connections.Remove(connection);
|
||||
fromNodeControl.RemoveConnection(connection); // 移除连接
|
||||
toNodeControl.RemoveConnection(connection); // 移除连接
|
||||
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||
//{
|
||||
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 与画布相关的字段
|
||||
|
||||
@@ -301,8 +131,10 @@ namespace Serein.Workbench.Views
|
||||
flowEnvironment = App.GetService<IFlowEnvironment>();
|
||||
flowNodeService = App.GetService<FlowNodeService>();
|
||||
keyEventService = App.GetService<IKeyEventService>();
|
||||
flowEEForwardingService = App.GetService<IFlowEEForwardingService>();
|
||||
flowNodeService.OnCreateNode += OnCreateNode;
|
||||
keyEventService.OnKeyDown += KeyEventService_OnKeyDown;
|
||||
keyEventService.OnKeyDown += KeyEventService_OnKeyDown;
|
||||
//flowEEForwardingService.OnProjectLoaded += FlowEEForwardingService_OnProjectLoaded;
|
||||
|
||||
// 缩放平移容器
|
||||
canvasTransformGroup = new TransformGroup();
|
||||
@@ -313,6 +145,13 @@ namespace Serein.Workbench.Views
|
||||
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
||||
SetBinding(model);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void FlowEEForwardingService_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
||||
{
|
||||
RefreshAllLine();
|
||||
}
|
||||
|
||||
|
||||
@@ -336,16 +175,18 @@ namespace Serein.Workbench.Views
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当前画布创建了节点
|
||||
/// </summary>
|
||||
/// <param name="nodeControl"></param>
|
||||
private void OnCreateNode(NodeControlBase nodeControl)
|
||||
{
|
||||
if (!nodeControl.FlowCanvas.Guid.Equals(Guid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!nodeControl.FlowCanvas.Guid.Equals(Guid))
|
||||
{
|
||||
// 防止事件传播到其它画布
|
||||
return;
|
||||
}
|
||||
var p = nodeControl.ViewModel.NodeModel.Position;
|
||||
PositionOfUI position = new PositionOfUI(p.X, p.Y);
|
||||
if (TryPlaceNodeInRegion(nodeControl, position, out var regionControl)) // 判断添加到区域容器
|
||||
@@ -409,6 +250,188 @@ namespace Serein.Workbench.Views
|
||||
|
||||
#endregion
|
||||
|
||||
#region 画布接口实现
|
||||
private IFlowCanvas Api => this;
|
||||
|
||||
public string Guid
|
||||
{
|
||||
get
|
||||
{
|
||||
return ViewModel.Model.Guid;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name => ViewModel.Model.Name;
|
||||
FlowCanvasDetails IFlowCanvas.Model => ViewModel.Model;
|
||||
void IFlowCanvas.Remove(NodeControlBase nodeControl)
|
||||
{
|
||||
ViewModel.NodeControls.Remove(nodeControl.ViewModel.NodeModel.Guid);
|
||||
FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
{
|
||||
FlowChartCanvas.Children.Remove(nodeControl);
|
||||
});
|
||||
}
|
||||
void IFlowCanvas.Add(NodeControlBase nodeControl)
|
||||
{
|
||||
|
||||
ViewModel.NodeControls.TryAdd(nodeControl.ViewModel.NodeModel.Guid, nodeControl);
|
||||
|
||||
FlowChartCanvas.Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
||||
FlowChartCanvas.Children.Add(nodeControl);
|
||||
|
||||
if (nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.UI)
|
||||
{
|
||||
// 需要切换到对应画布,尽可能让UI线程获取到适配器
|
||||
var edit = App.GetService<Locator>().FlowEditViewModel;
|
||||
var tab = edit.CanvasTabs.First(tab => tab.Content == this);
|
||||
App.GetService<Locator>().FlowEditViewModel.SelectedTab = tab;
|
||||
|
||||
}
|
||||
});
|
||||
ConfigureNodeEvents(nodeControl); // 配置相关事件
|
||||
ConfigureContextMenu(nodeControl); // 添加右键菜单
|
||||
|
||||
}
|
||||
|
||||
void IFlowCanvas.CreateInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, ConnectionInvokeType type)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
|
||||
var connection = new ConnectionControl(
|
||||
FlowChartCanvas,
|
||||
type,
|
||||
startJunction,
|
||||
endJunction
|
||||
);
|
||||
|
||||
//if (toNodeControl is FlipflopNodeControl flipflopControl
|
||||
// && flipflopControl?.ViewModel?.NodeModel is NodeModelBase nodeModel) // 某个节点连接到了触发器,尝试从全局触发器视图中移除该触发器
|
||||
//{
|
||||
// NodeTreeViewer.RemoveGlobalFlipFlop(nodeModel); // 从全局触发器树树视图中移除
|
||||
//}
|
||||
|
||||
Connections.Add(connection);
|
||||
fromNodeControl.AddCnnection(connection);
|
||||
toNodeControl.AddCnnection(connection);
|
||||
EndConnection(); // 环境触发了创建节点连接事件
|
||||
|
||||
|
||||
}
|
||||
void IFlowCanvas.RemoveInvokeConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
var removeConnections = Connections.Where(c =>
|
||||
c.Start.Equals(startJunction)
|
||||
&& c.End.Equals(endJunction)
|
||||
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
|
||||
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
|
||||
.ToList();
|
||||
|
||||
|
||||
foreach (var connection in removeConnections)
|
||||
{
|
||||
Connections.Remove(connection);
|
||||
fromNodeControl.RemoveConnection(connection); // 移除连接
|
||||
toNodeControl.RemoveConnection(connection); // 移除连接
|
||||
|
||||
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||
//{
|
||||
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||
//}
|
||||
}
|
||||
}
|
||||
void IFlowCanvas.CreateArgConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl,ConnectionArgSourceType type, int index)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的情况");
|
||||
return;
|
||||
}
|
||||
|
||||
JunctionControlBase startJunction = type switch
|
||||
{
|
||||
ConnectionArgSourceType.GetPreviousNodeData => IFormJunction.ReturnDataJunction, // 自身节点
|
||||
ConnectionArgSourceType.GetOtherNodeData => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||
ConnectionArgSourceType.GetOtherNodeDataOfInvoke => IFormJunction.ReturnDataJunction, // 其它节点的返回值控制点
|
||||
_ => throw new Exception("窗体事件 FlowEnvironment_NodeConnectChangeEvemt 创建/删除节点之间的参数传递关系 JunctionControlBase 枚举值错误 。非预期的枚举值。") // 应该不会触发
|
||||
};
|
||||
|
||||
if (IToJunction.ArgDataJunction.Length <= index)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(100);
|
||||
await App.UIContextOperation.InvokeAsync(() => {
|
||||
Api.CreateArgConnection(fromNodeControl, toNodeControl, type, index);
|
||||
});
|
||||
});
|
||||
return; // // 尝试重新连接
|
||||
}
|
||||
JunctionControlBase endJunction = IToJunction.ArgDataJunction[index];
|
||||
LineType lineType = LineType.Bezier;
|
||||
// 添加连接
|
||||
var connection = new ConnectionControl(
|
||||
lineType,
|
||||
FlowChartCanvas,
|
||||
index,
|
||||
type,
|
||||
startJunction,
|
||||
endJunction,
|
||||
IToJunction
|
||||
);
|
||||
Connections.Add(connection);
|
||||
fromNodeControl.AddCnnection(connection);
|
||||
toNodeControl.AddCnnection(connection);
|
||||
EndConnection(); // 环境触发了创建节点连接事件
|
||||
}
|
||||
void IFlowCanvas.RemoveArgConnection(NodeControlBase fromNodeControl, NodeControlBase toNodeControl, int index)
|
||||
{
|
||||
if (fromNodeControl is not INodeJunction IFormJunction || toNodeControl is not INodeJunction IToJunction)
|
||||
{
|
||||
SereinEnv.WriteLine(InfoType.INFO, "非预期的连接");
|
||||
return;
|
||||
}
|
||||
JunctionControlBase startJunction = IFormJunction.NextStepJunction;
|
||||
JunctionControlBase endJunction = IToJunction.ExecuteJunction;
|
||||
|
||||
var removeConnections = Connections.Where(c =>
|
||||
c.Start.Equals(startJunction)
|
||||
&& c.End.Equals(endJunction)
|
||||
&& (c.Start.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke
|
||||
|| c.End.JunctionType.ToConnectyionType() == JunctionOfConnectionType.Invoke))
|
||||
.ToList();
|
||||
|
||||
|
||||
foreach (var connection in removeConnections)
|
||||
{
|
||||
Connections.Remove(connection);
|
||||
fromNodeControl.RemoveConnection(connection); // 移除连接
|
||||
toNodeControl.RemoveConnection(connection); // 移除连接
|
||||
//if (NodeControls.TryGetValue(connection.End.MyNode.Guid, out var control))
|
||||
//{
|
||||
// JudgmentFlipFlopNode(control); // 连接关系变更时判断
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 画布键盘操作
|
||||
/// <summary>
|
||||
/// 监听按键事件
|
||||
@@ -449,7 +472,7 @@ namespace Serein.Workbench.Views
|
||||
IsCanvasDragging = false;
|
||||
SelectionRectangle.Visibility = Visibility.Collapsed;
|
||||
CancelSelectNode();
|
||||
EndConnection();
|
||||
EndConnection(); // Esc 按键 退出连线状态
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -464,7 +487,6 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
catch
|
||||
{
|
||||
Clipboard.SetText(text);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -590,10 +612,7 @@ namespace Serein.Workbench.Views
|
||||
|
||||
startCanvasDragPoint = currentMousePosition;
|
||||
|
||||
foreach (var line in Connections)
|
||||
{
|
||||
line.RefreshLine(); // 画布移动时刷新所有连接线
|
||||
}
|
||||
RefreshAllLine();
|
||||
}
|
||||
|
||||
if (IsSelectControl) // 正在选取节点
|
||||
@@ -807,7 +826,7 @@ namespace Serein.Workbench.Views
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
EndConnection();
|
||||
EndConnection(); // 完成创建连线请求后取消连线
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1012,6 +1031,17 @@ namespace Serein.Workbench.Views
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 刷新画布所有连线
|
||||
/// </summary>
|
||||
public void RefreshAllLine()
|
||||
{
|
||||
foreach (var line in Connections)
|
||||
{
|
||||
line.RefreshLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 完成选取操作
|
||||
/// </summary>
|
||||
@@ -1088,9 +1118,9 @@ namespace Serein.Workbench.Views
|
||||
nodeControl.BorderBrush = Brushes.Black;
|
||||
nodeControl.BorderThickness = new Thickness(0);
|
||||
|
||||
var startNodeGuid = ViewModel.Model.StartNode;
|
||||
var nodeGuid = nodeControl.ViewModel.NodeModel.Guid;
|
||||
if (startNodeGuid.Equals(nodeGuid))
|
||||
var startNode = ViewModel.Model.StartNode;
|
||||
var canvasStartNode = nodeControl.ViewModel.NodeModel;
|
||||
if (canvasStartNode.Equals(startNode))
|
||||
{
|
||||
nodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
||||
nodeControl.BorderThickness = new Thickness(2);
|
||||
@@ -1300,6 +1330,10 @@ namespace Serein.Workbench.Views
|
||||
/// </param>
|
||||
private void ConfigureContextMenu(NodeControlBase nodeControl)
|
||||
{
|
||||
/*if(nodeControl.ViewModel.NodeModel.ControlType == NodeControlType.UI)
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
var canvasGuid = Guid;
|
||||
var contextMenu = new ContextMenu();
|
||||
var nodeGuid = nodeControl.ViewModel?.NodeModel?.Guid;
|
||||
@@ -1412,21 +1446,7 @@ namespace Serein.Workbench.Views
|
||||
|
||||
#region 节点对齐 (有些小瑕疵)
|
||||
|
||||
//public void UpdateConnectedLines()
|
||||
//{
|
||||
// //foreach (var nodeControl in selectNodeControls)
|
||||
// //{
|
||||
// // UpdateConnections(nodeControl);
|
||||
// //}
|
||||
// this.Dispatcher.Invoke(() =>
|
||||
// {
|
||||
// foreach (var line in Connections)
|
||||
// {
|
||||
// line.AddOrRefreshLine(); // 节点完成对齐
|
||||
// }
|
||||
// });
|
||||
|
||||
//}
|
||||
|
||||
|
||||
#region Plan A 群组对齐
|
||||
|
||||
Reference in New Issue
Block a user