mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-04-21 07:16:34 +08:00
修改了保存文件功能,使其能将依赖的dll保存到项目文件保存目录。在选取功能的基层上实现了节点的批量移动。节点右键菜单增加了对齐功能,可将当前选取的节点进行对齐(实验性)
This commit is contained in:
@@ -61,6 +61,7 @@ namespace Serein.Library.Framework.NodeFlow
|
|||||||
public FlipflopStateType State { get; set; }
|
public FlipflopStateType State { get; set; }
|
||||||
//public TResult? Data { get; set; }
|
//public TResult? Data { get; set; }
|
||||||
public TriggerData TriggerData { get; set; }
|
public TriggerData TriggerData { get; set; }
|
||||||
|
|
||||||
public FlipflopContext(FlipflopStateType ffState)
|
public FlipflopContext(FlipflopStateType ffState)
|
||||||
{
|
{
|
||||||
State = ffState;
|
State = ffState;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Library\Serein.Library.csproj">
|
<ProjectReference Include="..\Library\Serein.Library.csproj">
|
||||||
<Project>{9FCE93C2-2278-46F3-96AB-CDAAFF27A55F}</Project>
|
<Project>{5E19D0F2-913A-4D1C-A6F8-1E1227BAA0E3}</Project>
|
||||||
<Name>Serein.Library</Name>
|
<Name>Serein.Library</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -63,10 +63,6 @@ namespace Serein.Library.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
public string Versions { get; set; }
|
public string Versions { get; set; }
|
||||||
|
|
||||||
// 预览位置
|
|
||||||
|
|
||||||
// 缩放比例
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 画布
|
/// 画布
|
||||||
@@ -76,11 +72,31 @@ namespace Serein.Library.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 宽度
|
/// 宽度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float Width { get; set; }
|
public double Width { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 高度
|
/// 高度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float Lenght { get; set; }
|
public double Lenght { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览位置X
|
||||||
|
/// </summary>
|
||||||
|
public double ViewX { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 预览位置Y
|
||||||
|
/// </summary>
|
||||||
|
public double ViewY { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缩放比例X
|
||||||
|
/// </summary>
|
||||||
|
public double ScaleX { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缩放比例Y
|
||||||
|
/// </summary>
|
||||||
|
public double ScaleY { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ namespace Serein.WorkBench
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 成功加载的工程文件
|
/// 成功加载的工程文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static SereinProjectData? FData { get; set; }
|
public static SereinProjectData? FlowProjectData { get; set; }
|
||||||
public static string FileDataPath = "";
|
public static string FileDataPath = "";
|
||||||
private void Application_Startup(object sender, StartupEventArgs e)
|
private void Application_Startup(object sender, StartupEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -141,7 +141,7 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
// 读取文件内容
|
// 读取文件内容
|
||||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||||
FData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
FileDataPath = System.IO.Path.GetDirectoryName(filePath) ?? "";
|
FileDataPath = System.IO.Path.GetDirectoryName(filePath) ?? "";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -150,13 +150,16 @@ namespace Serein.WorkBench
|
|||||||
Shutdown(); // 关闭应用程序
|
Shutdown(); // 关闭应用程序
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (1 == 1)
|
else
|
||||||
{
|
{
|
||||||
string filePath = @"F:\临时\project\new project.dnf";
|
#if DEBUG
|
||||||
|
//string filePath = @"F:\临时\project\new project.dnf";
|
||||||
|
string filePath = @"F:\临时\project\tmp\project.dnf";
|
||||||
//string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
|
//string filePath = @"D:\Project\C#\DynamicControl\SereinFlow\.Output\Debug\net8.0-windows7.0\U9 project.dnf";
|
||||||
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
|
||||||
App.FData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
App.FlowProjectData = JsonConvert.DeserializeObject<SereinProjectData>(content);
|
||||||
App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
|
App.FileDataPath = filePath;//System.IO.Path.GetDirectoryName(filePath)!;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
<Window.InputBindings>
|
<Window.InputBindings>
|
||||||
<KeyBinding Key="Escape" Command="{Binding CancelConnectionCommand}"/>
|
<KeyBinding Key="Escape" Command="{Binding CancelConnectionCommand}"/>
|
||||||
|
|
||||||
|
|
||||||
</Window.InputBindings>
|
</Window.InputBindings>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@@ -46,12 +46,12 @@
|
|||||||
|
|
||||||
<Grid Margin="2,2,2,5">
|
<Grid Margin="2,2,2,5">
|
||||||
<Button Grid.Row="0" Content="保存项目" Click="ButtonSaveFile_Click" HorizontalAlignment="Left" Margin="5,5,5,5"/>
|
<Button Grid.Row="0" Content="保存项目" Click="ButtonSaveFile_Click" HorizontalAlignment="Left" Margin="5,5,5,5"/>
|
||||||
<Button Grid.Row="0" Content="卸载清空" Click="UnloadAllButton_Click" HorizontalAlignment="Right" Margin="5,5,5,5"/>
|
<!--<Button Grid.Row="0" Content="卸载清空" Click="UnloadAllButton_Click" HorizontalAlignment="Right" Margin="5,5,5,5"/>-->
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<!--<Grid>
|
<!--<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@@ -63,8 +63,8 @@
|
|||||||
<!--<custom:ActionRegionControl x:Name="ActionRegionControl" Grid.Column="1" Margin="10" AllowDrop="True" Drop="ActionRegionControl_Drop" PreviewMouseMove="RegionControl_PreviewMouseMove"/>-->
|
<!--<custom:ActionRegionControl x:Name="ActionRegionControl" Grid.Column="1" Margin="10" AllowDrop="True" Drop="ActionRegionControl_Drop" PreviewMouseMove="RegionControl_PreviewMouseMove"/>-->
|
||||||
<!--<TextBlock Text="触发器" Grid.Column="2"/>-->
|
<!--<TextBlock Text="触发器" Grid.Column="2"/>-->
|
||||||
<!--<custom:StateRegionControl x:Name="StateRegionControl" Grid.Column="2" Margin="10" AllowDrop="True" Drop="StateRegionControl_Drop" PreviewMouseMove="RegionControl_PreviewMouseMove"/>-->
|
<!--<custom:StateRegionControl x:Name="StateRegionControl" Grid.Column="2" Margin="10" AllowDrop="True" Drop="StateRegionControl_Drop" PreviewMouseMove="RegionControl_PreviewMouseMove"/>-->
|
||||||
<!--</Grid>-->
|
<!--</Grid>-->
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel x:Name="DllStackPanel" Margin="5"/>
|
<StackPanel x:Name="DllStackPanel" Margin="5"/>
|
||||||
@@ -86,6 +86,8 @@
|
|||||||
<StackPanel Grid.Row="0" Background="#F5F5F5" Orientation="Horizontal" >
|
<StackPanel Grid.Row="0" Background="#F5F5F5" Orientation="Horizontal" >
|
||||||
<Button x:Name="ButtonDebugRun" Content="运行" Width="100" Margin="10" Click="ButtonDebugRun_Click"></Button>
|
<Button x:Name="ButtonDebugRun" Content="运行" Width="100" Margin="10" Click="ButtonDebugRun_Click"></Button>
|
||||||
<Button x:Name="ButtonDebugFlipflopNode" Content="结束" Width="100" Margin="10" Click="ButtonDebugFlipflopNode_Click"></Button>
|
<Button x:Name="ButtonDebugFlipflopNode" Content="结束" Width="100" Margin="10" Click="ButtonDebugFlipflopNode_Click"></Button>
|
||||||
|
<!--<Button x:Name="ButtonReflushCanvasConfig" Content="重置画布设置" Width="100" Margin="10" Click="ButtonReflushCanvasConfig_Click"></Button>-->
|
||||||
|
<!--<Button x:Name="ButtonLoadCanvasConfig" Content="加载画布设置" Width="100" Margin="10" Click="ButtonLoadCanvasConfig_Click"></Button>-->
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Row="1"
|
<StackPanel Grid.Row="1"
|
||||||
@@ -112,7 +114,7 @@
|
|||||||
Fill="LightBlue"
|
Fill="LightBlue"
|
||||||
Opacity="0.2"
|
Opacity="0.2"
|
||||||
Panel.ZIndex="999999"
|
Panel.ZIndex="999999"
|
||||||
Visibility="Collapsed"/>
|
Visibility="Collapsed"/>
|
||||||
|
|
||||||
<!-- Top-Left Thumb -->
|
<!-- Top-Left Thumb -->
|
||||||
<!--<Thumb x:Name="TopLeftThumb"
|
<!--<Thumb x:Name="TopLeftThumb"
|
||||||
@@ -186,12 +188,12 @@ Canvas.Top="{Binding ActualHeight, ElementName=FlowChartCanvas, Mode=OneWay, Con
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ using System.Reflection;
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Controls.Primitives;
|
using System.Windows.Controls.Primitives;
|
||||||
|
using System.Windows.Documents;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Media.Media3D;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using DataObject = System.Windows.DataObject;
|
using DataObject = System.Windows.DataObject;
|
||||||
@@ -104,6 +106,7 @@ namespace Serein.WorkBench
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Point startSelectControolPoint;
|
private Point startSelectControolPoint;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录开始连接的文本块
|
/// 记录开始连接的文本块
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -148,12 +151,14 @@ namespace Serein.WorkBench
|
|||||||
|
|
||||||
InitUI();
|
InitUI();
|
||||||
|
|
||||||
var project = App.FData;
|
var project = App.FlowProjectData;
|
||||||
if (project == null)
|
if (project == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Lenght);// 设置画布大小
|
InitializeCanvas(project.Basic.Canvas.Width, project.Basic.Canvas.Lenght);// 设置画布大小
|
||||||
|
|
||||||
|
|
||||||
FlowEnvironment.LoadProject(project, App.FileDataPath); // 加载项目
|
FlowEnvironment.LoadProject(project, App.FileDataPath); // 加载项目
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,12 +175,14 @@ namespace Serein.WorkBench
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void InitUI()
|
private void InitUI()
|
||||||
{
|
{
|
||||||
canvasTransformGroup = new TransformGroup();
|
canvasTransformGroup = new TransformGroup();
|
||||||
scaleTransform = new ScaleTransform();
|
scaleTransform = new ScaleTransform();
|
||||||
translateTransform = new TranslateTransform();
|
translateTransform = new TranslateTransform();
|
||||||
|
|
||||||
canvasTransformGroup.Children.Add(scaleTransform);
|
canvasTransformGroup.Children.Add(scaleTransform);
|
||||||
canvasTransformGroup.Children.Add(translateTransform);
|
canvasTransformGroup.Children.Add(translateTransform);
|
||||||
|
|
||||||
@@ -183,7 +190,16 @@ namespace Serein.WorkBench
|
|||||||
//FlowChartCanvas.RenderTransformOrigin = new Point(0.5, 0.5);
|
//FlowChartCanvas.RenderTransformOrigin = new Point(0.5, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Main窗体加载方法
|
//private void ButtonReflushCanvasConfig_Click(object sender, RoutedEventArgs e)
|
||||||
|
//{
|
||||||
|
// scaleTransform.ScaleX = 1;
|
||||||
|
// scaleTransform.ScaleY = 1;
|
||||||
|
// translateTransform.X = 0;
|
||||||
|
// translateTransform.Y = 0;
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
#region 窗体加载方法
|
||||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -198,14 +214,36 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
connection.Refresh();
|
connection.Refresh();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
var canvasData = App.FlowProjectData?.Basic.Canvas;
|
||||||
|
if (canvasData != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
scaleTransform.ScaleX = 1;
|
||||||
|
scaleTransform.ScaleY = 1;
|
||||||
|
translateTransform.X = 0;
|
||||||
|
translateTransform.Y = 0;
|
||||||
|
scaleTransform.ScaleX = canvasData.ScaleX;
|
||||||
|
scaleTransform.ScaleY = canvasData.ScaleY;
|
||||||
|
translateTransform.X += canvasData.ViewX;
|
||||||
|
translateTransform.Y += canvasData.ViewY;
|
||||||
|
// 应用变换组
|
||||||
|
FlowChartCanvas.RenderTransform = canvasTransformGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public void WriteLog(string message)
|
public void WriteLog(string message)
|
||||||
{
|
{
|
||||||
logWindow.AppendText(message);
|
logWindow.AppendText(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 运行环境事件
|
#region 运行环境事件
|
||||||
|
/// <summary>
|
||||||
|
/// 加载完成
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="eventArgs"></param>
|
||||||
private void FlowEnvironment_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
private void FlowEnvironment_OnProjectLoaded(ProjectLoadedEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
//foreach(var connection in Connections)
|
//foreach(var connection in Connections)
|
||||||
@@ -467,7 +505,7 @@ namespace Serein.WorkBench
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 加载 DynamicNodeFlow 文件
|
#region 加载项目文件后触发事件相关方法
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 运行环节加载了项目文件,需要创建节点控件
|
/// 运行环节加载了项目文件,需要创建节点控件
|
||||||
@@ -590,7 +628,7 @@ namespace Serein.WorkBench
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 右键菜单事件
|
#region 配置右键菜单
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 配置节点右键菜单
|
/// 配置节点右键菜单
|
||||||
@@ -632,12 +670,30 @@ namespace Serein.WorkBench
|
|||||||
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => FlowEnvironment.RemoteNode(nodeGuid)));
|
contextMenu.Items.Add(CreateMenuItem("删除", (s, e) => FlowEnvironment.RemoteNode(nodeGuid)));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsSucceed)));
|
contextMenu.Items.Add(CreateMenuItem("添加 真分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsSucceed)));
|
||||||
contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsFail)));
|
contextMenu.Items.Add(CreateMenuItem("添加 假分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsFail)));
|
||||||
contextMenu.Items.Add(CreateMenuItem("添加 异常分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsError)));
|
contextMenu.Items.Add(CreateMenuItem("添加 异常分支", (s, e) => StartConnection(nodeControl, ConnectionType.IsError)));
|
||||||
contextMenu.Items.Add(CreateMenuItem("添加 上游分支", (s, e) => StartConnection(nodeControl, ConnectionType.Upstream)));
|
contextMenu.Items.Add(CreateMenuItem("添加 上游分支", (s, e) => StartConnection(nodeControl, ConnectionType.Upstream)));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var AvoidMenu = new MenuItem();
|
||||||
|
//AvoidMenu.Items.Add(CreateMenuItem("水平对齐", (s, e) => AlignHorizontallyAvoidOverlap(selectNodeControls)));
|
||||||
|
//AvoidMenu.Items.Add(CreateMenuItem("垂直对齐", (s, e) => VerticalAlignAvoidOverlap(selectNodeControls)));
|
||||||
|
AvoidMenu.Items.Add(CreateMenuItem("群组对齐", (s, e) => {
|
||||||
|
AlignControlsWithGrouping(selectNodeControls);
|
||||||
|
UpdateConnectedLines();
|
||||||
|
}));
|
||||||
|
AvoidMenu.Items.Add(CreateMenuItem("规划对齐", (s, e) =>
|
||||||
|
{
|
||||||
|
AlignControlsWithDynamicProgramming(selectNodeControls);
|
||||||
|
UpdateConnectedLines();
|
||||||
|
}));
|
||||||
|
AvoidMenu.Header = "对齐";
|
||||||
|
contextMenu.Items.Add(AvoidMenu);
|
||||||
|
|
||||||
nodeControl.ContextMenu = contextMenu;
|
nodeControl.ContextMenu = contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,7 +805,8 @@ namespace Serein.WorkBench
|
|||||||
currentLine.X2 = position.X;
|
currentLine.X2 = position.X;
|
||||||
currentLine.Y2 = position.Y;
|
currentLine.Y2 = position.Y;
|
||||||
}
|
}
|
||||||
if (IsCanvasDragging) // 正在移动画布
|
|
||||||
|
if (IsCanvasDragging && e.MiddleButton == MouseButtonState.Pressed) // 按住中键的同时进行画布的移动 IsCanvasDragging &&
|
||||||
{
|
{
|
||||||
Point currentMousePosition = e.GetPosition(this);
|
Point currentMousePosition = e.GetPosition(this);
|
||||||
double deltaX = currentMousePosition.X - startCanvasDragPoint.X;
|
double deltaX = currentMousePosition.X - startCanvasDragPoint.X;
|
||||||
@@ -766,7 +823,7 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSelectControl && e.LeftButton == MouseButtonState.Pressed) // 正在选取节点
|
if (IsSelectControl /*&& e.LeftButton == MouseButtonState.Pressed*/) // 正在选取节点
|
||||||
{
|
{
|
||||||
// 获取当前鼠标位置
|
// 获取当前鼠标位置
|
||||||
Point currentPoint = e.GetPosition(FlowChartCanvas);
|
Point currentPoint = e.GetPosition(FlowChartCanvas);
|
||||||
@@ -776,10 +833,6 @@ namespace Serein.WorkBench
|
|||||||
double y = Math.Min(currentPoint.Y, startSelectControolPoint.Y);
|
double y = Math.Min(currentPoint.Y, startSelectControolPoint.Y);
|
||||||
double width = Math.Abs(currentPoint.X - startSelectControolPoint.X);
|
double width = Math.Abs(currentPoint.X - startSelectControolPoint.X);
|
||||||
double height = Math.Abs(currentPoint.Y - startSelectControolPoint.Y);
|
double height = Math.Abs(currentPoint.Y - startSelectControolPoint.Y);
|
||||||
/*double x = Math.Min(currentPoint.X, startControlDragPoint.X);
|
|
||||||
double y = Math.Min(currentPoint.Y, startControlDragPoint.Y);
|
|
||||||
double width = Math.Abs(currentPoint.X - startControlDragPoint.X);
|
|
||||||
double height = Math.Abs(currentPoint.Y - startControlDragPoint.Y);*/
|
|
||||||
|
|
||||||
Canvas.SetLeft(SelectionRectangle, x);
|
Canvas.SetLeft(SelectionRectangle, x);
|
||||||
Canvas.SetTop(SelectionRectangle, y);
|
Canvas.SetTop(SelectionRectangle, y);
|
||||||
@@ -922,7 +975,7 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 控件的鼠标移动事件,根据鼠标拖动更新控件的位置。
|
/// 控件的鼠标移动事件,根据鼠标拖动更新控件的位置。批量移动计算移动逻辑。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void Block_MouseMove(object sender, MouseEventArgs e)
|
private void Block_MouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
@@ -933,36 +986,88 @@ namespace Serein.WorkBench
|
|||||||
if (IsSelectControl)
|
if (IsSelectControl)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var IsSelect = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
|
if (IsControlDragging) // 如果正在拖动控件
|
||||||
if (!IsSelect && IsControlDragging) // 如果正在拖动控件
|
|
||||||
{
|
{
|
||||||
Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置
|
Point currentPosition = e.GetPosition(FlowChartCanvas); // 获取当前鼠标位置
|
||||||
// 获取引发事件的控件
|
// 批量移动 与 单个节点控件移动
|
||||||
if (sender is not UserControl block)
|
if (selectNodeControls.Count > 0 && sender is NodeControlBase element && selectNodeControls.Contains(element))
|
||||||
{
|
{
|
||||||
return;
|
// 获取element控件的旧位置
|
||||||
|
double oldLeft = Canvas.GetLeft(element);
|
||||||
|
double oldTop = Canvas.GetTop(element);
|
||||||
|
|
||||||
|
// 计算被选择控件的偏移量
|
||||||
|
double deltaX = (int)(currentPosition.X - startControlDragPoint.X);
|
||||||
|
double deltaY = (int)(currentPosition.Y - startControlDragPoint.Y);
|
||||||
|
|
||||||
|
// 移动被选择的控件
|
||||||
|
double newLeft = oldLeft + deltaX;
|
||||||
|
double newTop = oldTop + deltaY;
|
||||||
|
|
||||||
|
// 限制控件不超出FlowChartCanvas的边界
|
||||||
|
if (newLeft >= 0 && newLeft + element.ActualWidth <= FlowChartCanvas.ActualWidth)
|
||||||
|
{
|
||||||
|
Canvas.SetLeft(element, newLeft);
|
||||||
|
}
|
||||||
|
if (newTop >= 0 && newTop + element.ActualHeight <= FlowChartCanvas.ActualHeight)
|
||||||
|
{
|
||||||
|
Canvas.SetTop(element, newTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算element实际移动的距离
|
||||||
|
double actualDeltaX = newLeft - oldLeft;
|
||||||
|
double actualDeltaY = newTop - oldTop;
|
||||||
|
// 移动其它选中的控件
|
||||||
|
foreach (var nodeControl in selectNodeControls)
|
||||||
|
{
|
||||||
|
if (nodeControl != element) // 跳过已经移动的控件
|
||||||
|
{
|
||||||
|
double otherNewLeft = Canvas.GetLeft(nodeControl) + actualDeltaX;
|
||||||
|
double otherNewTop = Canvas.GetTop(nodeControl) + actualDeltaY;
|
||||||
|
|
||||||
|
// 限制控件不超出FlowChartCanvas的边界
|
||||||
|
if (otherNewLeft >= 0 && otherNewLeft + nodeControl.ActualWidth <= FlowChartCanvas.ActualWidth)
|
||||||
|
{
|
||||||
|
Canvas.SetLeft(nodeControl, otherNewLeft);
|
||||||
|
}
|
||||||
|
if (otherNewTop >= 0 && otherNewTop + nodeControl.ActualHeight <= FlowChartCanvas.ActualHeight)
|
||||||
|
{
|
||||||
|
Canvas.SetTop(nodeControl, otherNewTop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var nodeControl in selectNodeControls)
|
||||||
|
{
|
||||||
|
UpdateConnections(nodeControl);
|
||||||
|
}
|
||||||
|
startControlDragPoint = currentPosition; // 更新起始点位置
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{ // 获取引发事件的控件
|
||||||
|
if (sender is not UserControl block)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量
|
double deltaX = currentPosition.X - startControlDragPoint.X; // 计算X轴方向的偏移量
|
||||||
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
|
double deltaY = currentPosition.Y - startControlDragPoint.Y; // 计算Y轴方向的偏移量
|
||||||
|
|
||||||
double newLeft = Canvas.GetLeft(block) + deltaX; // 新的左边距
|
double newLeft = Canvas.GetLeft(block) + deltaX; // 新的左边距
|
||||||
double newTop = Canvas.GetTop(block) + deltaY; // 新的上边距
|
double newTop = Canvas.GetTop(block) + deltaY; // 新的上边距
|
||||||
|
|
||||||
// 限制控件不超出FlowChartCanvas的边界
|
// 限制控件不超出FlowChartCanvas的边界
|
||||||
if (newLeft >= 0 && newLeft + block.ActualWidth <= FlowChartCanvas.ActualWidth)
|
if (newLeft >= 0 && newLeft + block.ActualWidth <= FlowChartCanvas.ActualWidth)
|
||||||
{
|
{
|
||||||
Canvas.SetLeft(block, newLeft);
|
Canvas.SetLeft(block, newLeft);
|
||||||
|
}
|
||||||
|
if (newTop >= 0 && newTop + block.ActualHeight <= FlowChartCanvas.ActualHeight)
|
||||||
|
{
|
||||||
|
Canvas.SetTop(block, newTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateConnections(block);
|
||||||
}
|
}
|
||||||
if (newTop >= 0 && newTop + block.ActualHeight <= FlowChartCanvas.ActualHeight)
|
|
||||||
{
|
|
||||||
Canvas.SetTop(block, newTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateConnections(block);
|
|
||||||
|
|
||||||
startControlDragPoint = currentPosition; // 更新起始点位置
|
startControlDragPoint = currentPosition; // 更新起始点位置
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -978,7 +1083,8 @@ namespace Serein.WorkBench
|
|||||||
IsControlDragging = false;
|
IsControlDragging = false;
|
||||||
((UIElement)sender).ReleaseMouseCapture(); // 释放鼠标捕获
|
((UIElement)sender).ReleaseMouseCapture(); // 释放鼠标捕获
|
||||||
}
|
}
|
||||||
else if (IsConnecting)
|
|
||||||
|
if (IsConnecting)
|
||||||
{
|
{
|
||||||
var formNodeGuid = startConnectNodeControl?.ViewModel.Node.Guid;
|
var formNodeGuid = startConnectNodeControl?.ViewModel.Node.Guid;
|
||||||
var toNodeGuid = (sender as NodeControlBase)?.ViewModel.Node.Guid;
|
var toNodeGuid = (sender as NodeControlBase)?.ViewModel.Node.Guid;
|
||||||
@@ -1112,10 +1218,6 @@ namespace Serein.WorkBench
|
|||||||
startCanvasDragPoint = e.GetPosition(this);
|
startCanvasDragPoint = e.GetPosition(this);
|
||||||
FlowChartCanvas.CaptureMouse();
|
FlowChartCanvas.CaptureMouse();
|
||||||
e.Handled = true; // 防止事件传播影响其他控件
|
e.Handled = true; // 防止事件传播影响其他控件
|
||||||
//if (e.MiddleButton == MouseButtonState.Pressed)
|
|
||||||
//{
|
|
||||||
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FlowChartCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
private void FlowChartCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
@@ -1305,29 +1407,64 @@ namespace Serein.WorkBench
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
private void FlowChartCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
IsSelectControl = true;
|
// 如果正在选取状态,再次点击画布时自动确定选取范围,否则进入选取状态
|
||||||
|
if (IsSelectControl)
|
||||||
|
{
|
||||||
|
IsSelectControl = false;
|
||||||
|
// 释放鼠标捕获
|
||||||
|
FlowChartCanvas.ReleaseMouseCapture();
|
||||||
|
|
||||||
// 开始选取时,记录鼠标起始点
|
// 隐藏选取矩形(如果需要保持选取状态显示,可以删除此行)
|
||||||
startSelectControolPoint = e.GetPosition(FlowChartCanvas);
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
// 初始化选取矩形的位置和大小
|
// 处理选取区域内的元素(例如,获取选取范围内的控件)
|
||||||
Canvas.SetLeft(SelectionRectangle, startSelectControolPoint.X);
|
Rect selectionArea = new Rect(Canvas.GetLeft(SelectionRectangle),
|
||||||
Canvas.SetTop(SelectionRectangle, startSelectControolPoint.Y);
|
Canvas.GetTop(SelectionRectangle),
|
||||||
SelectionRectangle.Width = 0;
|
SelectionRectangle.Width,
|
||||||
SelectionRectangle.Height = 0;
|
SelectionRectangle.Height);
|
||||||
|
|
||||||
// 显示选取矩形
|
|
||||||
SelectionRectangle.Visibility = Visibility.Visible;
|
|
||||||
SelectionRectangle.ContextMenu ??= ConfiguerSelectionRectangle();
|
|
||||||
|
|
||||||
// 捕获鼠标,以便在鼠标移动到Canvas外部时仍能处理事件
|
// 在此处处理选取的逻辑
|
||||||
FlowChartCanvas.CaptureMouse();
|
foreach (UIElement element in FlowChartCanvas.Children)
|
||||||
|
{
|
||||||
|
Rect elementBounds = new Rect(Canvas.GetLeft(element), Canvas.GetTop(element),
|
||||||
|
element.RenderSize.Width, element.RenderSize.Height);
|
||||||
|
|
||||||
//if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
|
if (selectionArea.Contains(elementBounds))
|
||||||
//{
|
{
|
||||||
|
// 选中元素,执行相应操作
|
||||||
//}
|
if (element is NodeControlBase control)
|
||||||
|
{
|
||||||
|
selectNodeControls.Add(control);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SelectedNode();// 选择之后需要执行的操作
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 进入选取状态
|
||||||
|
IsSelectControl = true;
|
||||||
|
|
||||||
|
// 开始选取时,记录鼠标起始点
|
||||||
|
startSelectControolPoint = e.GetPosition(FlowChartCanvas);
|
||||||
|
|
||||||
|
// 初始化选取矩形的位置和大小
|
||||||
|
Canvas.SetLeft(SelectionRectangle, startSelectControolPoint.X);
|
||||||
|
Canvas.SetTop(SelectionRectangle, startSelectControolPoint.Y);
|
||||||
|
SelectionRectangle.Width = 0;
|
||||||
|
SelectionRectangle.Height = 0;
|
||||||
|
|
||||||
|
// 显示选取矩形
|
||||||
|
SelectionRectangle.Visibility = Visibility.Visible;
|
||||||
|
SelectionRectangle.ContextMenu ??= ConfiguerSelectionRectangle();
|
||||||
|
|
||||||
|
// 捕获鼠标,以便在鼠标移动到Canvas外部时仍能处理事件
|
||||||
|
FlowChartCanvas.CaptureMouse();
|
||||||
|
|
||||||
|
}
|
||||||
e.Handled = true; // 防止事件传播影响其他控件
|
e.Handled = true; // 防止事件传播影响其他控件
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContextMenu ConfiguerSelectionRectangle()
|
private ContextMenu ConfiguerSelectionRectangle()
|
||||||
@@ -1361,38 +1498,7 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
if (IsSelectControl)
|
if (IsSelectControl)
|
||||||
{
|
{
|
||||||
CancelSelectNode(); // 取消之前选择的控件
|
|
||||||
IsSelectControl = false;
|
|
||||||
// 释放鼠标捕获
|
|
||||||
FlowChartCanvas.ReleaseMouseCapture();
|
|
||||||
|
|
||||||
// 隐藏选取矩形(如果需要保持选取状态显示,可以删除此行)
|
|
||||||
// SelectionRectangle.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
// 处理选取区域内的元素(例如,获取选取范围内的控件)
|
|
||||||
Rect selectionArea = new Rect(Canvas.GetLeft(SelectionRectangle),
|
|
||||||
Canvas.GetTop(SelectionRectangle),
|
|
||||||
SelectionRectangle.Width,
|
|
||||||
SelectionRectangle.Height);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 在此处处理选取的逻辑
|
|
||||||
foreach (UIElement element in FlowChartCanvas.Children)
|
|
||||||
{
|
|
||||||
Rect elementBounds = new Rect(Canvas.GetLeft(element), Canvas.GetTop(element),
|
|
||||||
element.RenderSize.Width, element.RenderSize.Height);
|
|
||||||
|
|
||||||
if (selectionArea.Contains(elementBounds))
|
|
||||||
{
|
|
||||||
// 选中元素,执行相应操作
|
|
||||||
if (element is NodeControlBase control)
|
|
||||||
{
|
|
||||||
selectNodeControls.Add(control);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SelectedNode();// 选择之后需要执行的操作
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,7 +1510,7 @@ namespace Serein.WorkBench
|
|||||||
SelectionRectangle.Visibility = Visibility.Collapsed;
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件");
|
//Console.WriteLine($"一共选取了{selectNodeControls.Count}个控件");
|
||||||
foreach (var node in selectNodeControls)
|
foreach (var node in selectNodeControls)
|
||||||
{
|
{
|
||||||
node.ViewModel.Selected();
|
node.ViewModel.Selected();
|
||||||
@@ -1415,16 +1521,199 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
private void CancelSelectNode()
|
private void CancelSelectNode()
|
||||||
{
|
{
|
||||||
foreach (var node in selectNodeControls)
|
IsSelectControl = false;
|
||||||
|
foreach (var nodeControl in selectNodeControls)
|
||||||
{
|
{
|
||||||
node.ViewModel.CancelSelect();
|
nodeControl.ViewModel.CancelSelect();
|
||||||
node.BorderBrush = Brushes.Black;
|
nodeControl.BorderBrush = Brushes.Black;
|
||||||
node.BorderThickness = new Thickness(0);
|
nodeControl.BorderThickness = new Thickness(0);
|
||||||
|
if (nodeControl.ViewModel.Node.IsStart)
|
||||||
|
{
|
||||||
|
nodeControl.BorderBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#04FC10"));
|
||||||
|
nodeControl.BorderThickness = new Thickness(2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
selectNodeControls.Clear();
|
selectNodeControls.Clear();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region 节点对齐 (有些小瑕疵)
|
||||||
|
|
||||||
|
public void UpdateConnectedLines()
|
||||||
|
{
|
||||||
|
//foreach (var nodeControl in selectNodeControls)
|
||||||
|
//{
|
||||||
|
// UpdateConnections(nodeControl);
|
||||||
|
//}
|
||||||
|
foreach (var line in Connections)
|
||||||
|
{
|
||||||
|
line.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region Plan A 群组对齐
|
||||||
|
|
||||||
|
public void AlignControlsWithGrouping(List<NodeControlBase> selectNodeControls, double proximityThreshold = 50, double spacing = 10)
|
||||||
|
{
|
||||||
|
if (selectNodeControls == null || selectNodeControls.Count < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 按照控件的相对位置进行分组
|
||||||
|
var horizontalGroups = GroupByProximity(selectNodeControls, proximityThreshold, isHorizontal: true);
|
||||||
|
var verticalGroups = GroupByProximity(selectNodeControls, proximityThreshold, isHorizontal: false);
|
||||||
|
|
||||||
|
// 对每个水平群组进行垂直对齐
|
||||||
|
foreach (var group in horizontalGroups)
|
||||||
|
{
|
||||||
|
double avgY = group.Average(c => Canvas.GetTop(c)); // 计算Y坐标平均值
|
||||||
|
foreach (var control in group)
|
||||||
|
{
|
||||||
|
Canvas.SetTop(control, avgY); // 对齐Y坐标
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对每个垂直群组进行水平对齐
|
||||||
|
foreach (var group in verticalGroups)
|
||||||
|
{
|
||||||
|
double avgX = group.Average(c => Canvas.GetLeft(c)); // 计算X坐标平均值
|
||||||
|
foreach (var control in group)
|
||||||
|
{
|
||||||
|
Canvas.SetLeft(control, avgX); // 对齐X坐标
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基于控件间的距离来分组,按水平或垂直方向
|
||||||
|
private List<List<NodeControlBase>> GroupByProximity(List<NodeControlBase> controls, double proximityThreshold, bool isHorizontal)
|
||||||
|
{
|
||||||
|
var groups = new List<List<NodeControlBase>>();
|
||||||
|
|
||||||
|
foreach (var control in controls)
|
||||||
|
{
|
||||||
|
bool addedToGroup = false;
|
||||||
|
|
||||||
|
// 尝试将控件加入现有的群组
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
if (IsInProximity(group, control, proximityThreshold, isHorizontal))
|
||||||
|
{
|
||||||
|
group.Add(control);
|
||||||
|
addedToGroup = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有加入任何群组,创建新群组
|
||||||
|
if (!addedToGroup)
|
||||||
|
{
|
||||||
|
groups.Add(new List<NodeControlBase> { control });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断控件是否接近某个群组
|
||||||
|
private bool IsInProximity(List<NodeControlBase> group, NodeControlBase control, double proximityThreshold, bool isHorizontal)
|
||||||
|
{
|
||||||
|
foreach (var existingControl in group)
|
||||||
|
{
|
||||||
|
double distance = isHorizontal
|
||||||
|
? Math.Abs(Canvas.GetTop(existingControl) - Canvas.GetTop(control)) // 垂直方向的距离
|
||||||
|
: Math.Abs(Canvas.GetLeft(existingControl) - Canvas.GetLeft(control)); // 水平方向的距离
|
||||||
|
|
||||||
|
if (distance <= proximityThreshold)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Plan B 规划对齐
|
||||||
|
public void AlignControlsWithDynamicProgramming(List<NodeControlBase> selectNodeControls, double spacing = 10)
|
||||||
|
{
|
||||||
|
if (selectNodeControls == null || selectNodeControls.Count < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int n = selectNodeControls.Count;
|
||||||
|
double[] dp = new double[n];
|
||||||
|
int[] split = new int[n];
|
||||||
|
|
||||||
|
// 初始化动态规划数组
|
||||||
|
for (int i = 1; i < n; i++)
|
||||||
|
{
|
||||||
|
dp[i] = double.MaxValue;
|
||||||
|
for (int j = 0; j < i; j++)
|
||||||
|
{
|
||||||
|
double cost = CalculateAlignmentCost(selectNodeControls, j, i, spacing);
|
||||||
|
if (dp[j] + cost < dp[i])
|
||||||
|
{
|
||||||
|
dp[i] = dp[j] + cost;
|
||||||
|
split[i] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回溯找到最优的对齐方式
|
||||||
|
AlignWithSplit(selectNodeControls, split, n - 1, spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算从控件[j]到控件[i]的对齐代价,并考虑控件的大小和间距
|
||||||
|
private double CalculateAlignmentCost(List<NodeControlBase> controls, int start, int end, double spacing)
|
||||||
|
{
|
||||||
|
double totalWidth = 0;
|
||||||
|
double totalHeight = 0;
|
||||||
|
|
||||||
|
for (int i = start; i <= end; i++)
|
||||||
|
{
|
||||||
|
totalWidth += controls[i].ActualWidth;
|
||||||
|
totalHeight += controls[i].ActualHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 水平和垂直方向代价计算,包括控件大小和间距
|
||||||
|
double widthCost = totalWidth + (end - start) * spacing;
|
||||||
|
double heightCost = totalHeight + (end - start) * spacing;
|
||||||
|
|
||||||
|
// 返回较小的代价,表示更优的对齐方式
|
||||||
|
return Math.Min(widthCost, heightCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据split数组调整控件位置,确保控件不重叠
|
||||||
|
private void AlignWithSplit(List<NodeControlBase> controls, int[] split, int end, double spacing)
|
||||||
|
{
|
||||||
|
if (end <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AlignWithSplit(controls, split, split[end], spacing);
|
||||||
|
|
||||||
|
// 从split[end]到end的控件进行对齐操作
|
||||||
|
double currentX = Canvas.GetLeft(controls[split[end]]);
|
||||||
|
double currentY = Canvas.GetTop(controls[split[end]]);
|
||||||
|
|
||||||
|
for (int i = split[end] + 1; i <= end; i++)
|
||||||
|
{
|
||||||
|
// 水平或垂直对齐,确保控件之间有间距
|
||||||
|
if (currentX + controls[i].ActualWidth + spacing <= Canvas.GetLeft(controls[end]))
|
||||||
|
{
|
||||||
|
Canvas.SetLeft(controls[i], currentX + controls[i].ActualWidth + spacing);
|
||||||
|
currentX += controls[i].ActualWidth + spacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Canvas.SetTop(controls[i], currentY + controls[i].ActualHeight + spacing);
|
||||||
|
currentY += controls[i].ActualHeight + spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 窗体静态方法
|
#region 窗体静态方法
|
||||||
|
|
||||||
|
|
||||||
@@ -1575,21 +1864,24 @@ namespace Serein.WorkBench
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存为项目文件 (正在重写)
|
/// 保存为项目文件
|
||||||
/// JsonConvert.SerializeObject 对象序列化字符串
|
|
||||||
/// JArray.FromObject 数组序列化
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
private void ButtonSaveFile_Click(object sender, RoutedEventArgs e)
|
private void ButtonSaveFile_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var projectData = FlowEnvironment.SaveProject();
|
var projectData = FlowEnvironment.SaveProject();
|
||||||
|
|
||||||
projectData.Basic = new Basic
|
projectData.Basic = new Basic
|
||||||
{
|
{
|
||||||
Canvas = new FlowCanvas
|
Canvas = new FlowCanvas
|
||||||
{
|
{
|
||||||
Lenght = (float)FlowChartCanvas.Width,
|
Lenght = FlowChartCanvas.Width,
|
||||||
Width = (float)FlowChartCanvas.Height,
|
Width = FlowChartCanvas.Height,
|
||||||
|
ViewX = translateTransform.X,
|
||||||
|
ViewY = translateTransform.Y,
|
||||||
|
ScaleX = scaleTransform.ScaleX,
|
||||||
|
ScaleY = scaleTransform.ScaleY,
|
||||||
},
|
},
|
||||||
Versions = "1",
|
Versions = "1",
|
||||||
};
|
};
|
||||||
@@ -1603,39 +1895,50 @@ namespace Serein.WorkBench
|
|||||||
node.Position = new Position(positionRelativeToParent.X, positionRelativeToParent.Y);
|
node.Position = new Position(positionRelativeToParent.X, positionRelativeToParent.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var projectJsonData = JObject.FromObject(projectData);
|
var isPass = SaveContentToFile(out string savePath, out Action<string,string>? savaProjectFile);
|
||||||
var savePath = SaveContentToFile(projectJsonData.ToString());
|
if(!isPass)
|
||||||
savePath = System.IO.Path.GetDirectoryName(savePath);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 复制dll文件
|
string librarySavePath = System.IO.Path.GetDirectoryName(savePath);
|
||||||
//if (string.IsNullOrEmpty(savePath))
|
Console.WriteLine(savePath);
|
||||||
//{
|
for (int index = 0; index < projectData.Librarys.Length; index++)
|
||||||
// return;
|
{
|
||||||
//}
|
Library.Entity.Library? library = projectData.Librarys[index];
|
||||||
//foreach (var dll in loadedAssemblies)
|
try
|
||||||
//{
|
{
|
||||||
// try
|
string targetPath = System.IO.Path.Combine(librarySavePath, System.IO.Path.GetFileName(library.Path));
|
||||||
// {
|
//Console.WriteLine("targetPath:" + targetPath);
|
||||||
// string targetPath = System.IO.Path.Combine(savePath, System.IO.Path.GetFileName(dll.CodeBase));
|
|
||||||
// // 确保目标目录存在
|
string sourceFile = new Uri(library.Path).LocalPath;
|
||||||
// Directory.CreateDirectory(savePath);
|
//Console.WriteLine("sourceFile:" + sourceFile);
|
||||||
// var sourceFile = new Uri(dll.CodeBase).LocalPath;
|
|
||||||
// // 复制文件到目标目录
|
// 复制文件到目标目录
|
||||||
// File.Copy(sourceFile, targetPath, true);
|
File.Copy(sourceFile, targetPath, true);
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
// 获取相对路径
|
||||||
// {
|
string relativePath = System.IO.Path.GetRelativePath(savePath, targetPath);
|
||||||
// WriteLog($"DLL复制失败:{dll.CodeBase} \r\n错误:{ex}\r\n");
|
//Console.WriteLine("Relative Path: " + relativePath);
|
||||||
// }
|
projectData.Librarys[index].Path = relativePath;
|
||||||
//}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
//WriteLog($"DLL复制失败:{dll.CodeBase} \r\n错误:{ex}\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject projectJsonData = JObject.FromObject(projectData);
|
||||||
|
savaProjectFile?.Invoke(savePath, projectJsonData.ToString());
|
||||||
}
|
}
|
||||||
public static string? SaveContentToFile(string content)
|
public static bool SaveContentToFile(out string savePath, out Action<string, string>? savaProjectFile)
|
||||||
{
|
{
|
||||||
// 创建一个新的保存文件对话框
|
// 创建一个新的保存文件对话框
|
||||||
SaveFileDialog saveFileDialog = new()
|
SaveFileDialog saveFileDialog = new()
|
||||||
{
|
{
|
||||||
Filter = "NF Files (*.dnf)|*.dnf",
|
Filter = "DynamicNodeFlow Files (*.dnf)|*.dnf",
|
||||||
DefaultExt = "nf",
|
DefaultExt = "dnf",
|
||||||
FileName = "project.dnf"
|
FileName = "project.dnf"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1645,23 +1948,13 @@ namespace Serein.WorkBench
|
|||||||
// 如果用户选择了文件并点击了保存按钮
|
// 如果用户选择了文件并点击了保存按钮
|
||||||
if (result == true)
|
if (result == true)
|
||||||
{
|
{
|
||||||
string filePath = saveFileDialog.FileName;
|
savePath = saveFileDialog.FileName;
|
||||||
|
savaProjectFile = File.WriteAllText;
|
||||||
try
|
return true;
|
||||||
{
|
|
||||||
// 将文本内容写入文件
|
|
||||||
File.WriteAllText(filePath, content);
|
|
||||||
MessageBox.Show($"文本已成功保存到文件: {filePath}", "保存成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
return filePath;
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
MessageBox.Show($"保存文件时出现错误: {ex.Message}", "保存错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
savePath = string.Empty;
|
||||||
|
savaProjectFile = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
public static string GetRelativePath(string baseDirectory, string fullPath)
|
public static string GetRelativePath(string baseDirectory, string fullPath)
|
||||||
{
|
{
|
||||||
@@ -1675,15 +1968,26 @@ namespace Serein.WorkBench
|
|||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 按键监听。esc取消操作
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
|
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
//if (e.KeyStates == Keyboard.GetKeyStates(Key.D8) && Keyboard.Modifiers == ModifierKeys.Shift)
|
if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape))
|
||||||
//if (Keyboard.Modifiers == ModifierKeys.Shift)
|
//if (Keyboard.Modifiers == ModifierKeys.Shift)
|
||||||
//{
|
{
|
||||||
// startSelectControolPoint = e.GetPosition(FlowChartCanvas);
|
IsConnecting = false;
|
||||||
//}
|
IsControlDragging = false;
|
||||||
|
IsCanvasDragging = false;
|
||||||
|
EndConnection();
|
||||||
|
SelectionRectangle.Visibility = Visibility.Collapsed;
|
||||||
|
CancelSelectNode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
|
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
|
||||||
|
|||||||
Reference in New Issue
Block a user