设计了流程接口节点,能够切换本节点数据、目标节点数据,目前还有数据来源相关操作没有实现

This commit is contained in:
fengjiayi
2025-05-28 23:19:00 +08:00
parent f7cae3493f
commit a5715be929
44 changed files with 1064 additions and 277 deletions

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;
using System.Diagnostics;
namespace Serein.Workbench.Converters
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Debug.WriteLine($"targetType:{targetType} value:{targetType} parameter:{parameter}");
if (value is bool b)
{
return b ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is Visibility v && v == Visibility.Visible;
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace Serein.Workbench.Converters
{
public class EnumToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null)
return false;
return value.ToString().Equals(parameter.ToString(), StringComparison.InvariantCultureIgnoreCase);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows;
namespace Serein.Workbench.Converters
{
/// <summary>
/// 根据bool类型控制可见性
/// </summary>
[ValueConversion(typeof(bool), typeof(Visibility))]
public class InvertableBooleanToVisibilityConverter : IValueConverter
{
enum Parameters
{
/// <summary>
/// True为可见False为不可见
/// </summary>
Normal,
/// <summary>
/// False为可见True为不可见
/// </summary>
Inverted
}
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var boolValue = (bool)value;
var direction = (Parameters)Enum.Parse(typeof(Parameters), (string)parameter);
if (direction == Parameters.Inverted)
return !boolValue ? Visibility.Visible : Visibility.Collapsed;
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
public object? ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace Serein.Workbench.Converters
{
public class MethodDetailsSelectorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool isShareParam = (bool)values[0];
var nodeDetails = values[1];
var selectNodeDetails = values[2];
return isShareParam ? nodeDetails : selectNodeDetails;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace Serein.Workbench.Converters
{
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class RightThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double width)
return width - 10; // Adjust for Thumb width
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class BottomThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double height)
return height - 10; // Adjust for Thumb height
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class VerticalCenterThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double height)
return height / 2 - 5; // Centering Thumb vertically
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 画布拉动范围距离计算器
/// </summary>
public class HorizontalCenterThumbPositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is double width)
return width / 2 - 5; // Centering Thumb horizontally
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,26 @@
using Serein.Library;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace Serein.Workbench.Converters
{
/// <summary>
/// 根据控件类型切换颜色
/// </summary>
public class TypeToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// 根据 ControlType 返回颜色
return value switch
{
NodeControlType.Action => Brushes.Blue,
NodeControlType.Flipflop => Brushes.Green,
_ => Brushes.Black,
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
}
}

View File

@@ -14,6 +14,7 @@ using System.Windows.Documents;
using System.Threading;
using Serein.Workbench.Services;
using Serein.Workbench.Tool;
using System.ComponentModel;
namespace Serein.Workbench.Node.View
{
@@ -169,15 +170,24 @@ namespace Serein.Workbench.Node.View
private readonly FlowNodeService flowNodeService;
protected JunctionControlBase()
{
flowNodeService = App.GetService<FlowNodeService>();
this.Width = 25;
this.Height = 20;
this.MouseDown += JunctionControlBase_MouseDown;
this.MouseMove += JunctionControlBase_MouseMove;
this.MouseLeave += JunctionControlBase_MouseLeave; ;
this.MouseLeave += JunctionControlBase_MouseLeave;
#if DEBUG
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
return;
#endif
flowNodeService = App.GetService<FlowNodeService>();
}
#region
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register(nameof(MyNode), typeof(NodeModelBase), typeof(JunctionControlBase), new PropertyMetadata(default(NodeModelBase)));
@@ -238,7 +248,11 @@ namespace Serein.Workbench.Node.View
{
if(_isMouseOver != value)
{
flowNodeService.ConnectingData.CurrentJunction = this;
if(flowNodeService is not null)
{
flowNodeService.ConnectingData.CurrentJunction = this;
}
_isMouseOver = value;
InvalidateVisual();
}
@@ -261,6 +275,10 @@ namespace Serein.Workbench.Node.View
/// <returns></returns>
protected Brush GetBackgrounp()
{
if(flowNodeService is null)
{
return Brushes.Transparent;
}
var cd = flowNodeService.ConnectingData;
if(!cd.IsCreateing)
{

View File

@@ -8,9 +8,6 @@ namespace Serein.Workbench.Node.View
{
public class ExecuteJunctionControl : JunctionControlBase
{
public ExecuteJunctionControl()
{
base.JunctionType = JunctionType.Execute;

View File

@@ -15,7 +15,7 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 节点控件基类(控件)
/// </summary>
public abstract class NodeControlBase : UserControl, IDynamicFlowNode
public abstract class NodeControlBase : UserControl //, IDynamicFlowNode
{
/// <summary>
/// 节点所在的画布(以后需要将画布封装出来,实现多画布的功能)

View File

@@ -4,10 +4,11 @@ using System.Runtime.CompilerServices;
using System.Windows.Controls;
using System.Windows.Data;
using System;
using CommunityToolkit.Mvvm.ComponentModel;
namespace Serein.Workbench.Node.ViewModel
{
public abstract class NodeControlViewModelBase
public abstract partial class NodeControlViewModelBase : ObservableObject
{
///// <summary>
@@ -21,30 +22,14 @@ namespace Serein.Workbench.Node.ViewModel
}
private bool isInterrupt;
private bool isReadonlyOnView = true;
///// <summary>
///// 控制中断状态的视觉效果
///// </summary>
public bool IsInterrupt
{
get => NodeModel.DebugSetting.IsInterrupt;
set
{
NodeModel.DebugSetting.IsInterrupt = value;
OnPropertyChanged();
}
}
/// <summary>
/// 工作台预览基本节点时,避免其中的文本框响应拖拽事件导致卡死
/// </summary>
public bool IsEnabledOnView { get => isReadonlyOnView; set
{
OnPropertyChanged(); isReadonlyOnView = value;
}
}
[ObservableProperty]
private bool isEnabledOnView = true;
public event PropertyChangedEventHandler? PropertyChanged;

View File

@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters"
xmlns:converter="clr-namespace:Serein.Workbench.Converters"
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
d:DataContext="{d:DesignInstance vm:ActionNodeControlViewModel}"
mc:Ignorable="d"
@@ -13,7 +13,7 @@
<UserControl.Resources>
<!--<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />-->
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<!--<ResourceDictionary Source="/Serein.Workbench;Node/View/NodeExecuteJunctionControl.xaml" x:Key="NodeExecuteJunctionControl"/>-->
</UserControl.Resources>
@@ -69,10 +69,13 @@
<local:NextStepJunctionControl Grid.Column="2" MyNode="{Binding NodeModel}" x:Name="NextStepJunctionControl" HorizontalAlignment="Right" Grid.RowSpan="2"/>
</Grid>
<themes:MethodDetailsControl Grid.Row="2" x:Name="MethodDetailsControl" MethodDetails="{Binding NodeModel.MethodDetails}"/>
<Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderThickness="0"
Visibility="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay,
Converter={StaticResource InvertedBoolConverter}, ConverterParameter=Normal}" />
<Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="#40508D" Opacity="0.5" BorderThickness="0"
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay,
Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=Normal}" />
<Grid Grid.Row="3" Background="#D5F0FC" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
@@ -105,7 +108,7 @@
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}"/>
<CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay}"/>
<TextBlock Text="参数保护"/>
</StackPanel>

View File

@@ -18,8 +18,7 @@ namespace Serein.Workbench.Node.View
InitializeComponent();
if(ExecuteJunctionControl.MyNode != null)
{
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
ExecuteJunctionControl.MyNode.Guid = viewModel.NodeModel.Guid;
}
}
@@ -38,46 +37,40 @@ namespace Serein.Workbench.Node.View
/// </summary>
JunctionControlBase INodeJunction.ReturnDataJunction => this.ResultJunctionControl;
/// <summary>
/// 方法入参控制点(可能有,可能没)
/// </summary>
JunctionControlBase[] INodeJunction.ArgDataJunction
{
get
{
// 获取 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>();
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction();
for (int i = 0; i < itemsControl.Items.Count; i++)
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 container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
if (container != null)
var argControl = FindVisualChild<ArgJunctionControl>(container);
if (argControl != null)
{
var argControl = FindVisualChild<ArgJunctionControl>(container);
if (argControl != null)
{
controls.Add(argControl); // 收集 ArgJunctionControl 实例
}
controls.Add(argControl); // 收集 ArgJunctionControl 实例
}
}
return argDataJunction = controls.ToArray();
}
else
{
return [];
}
return argDataJunction = controls.ToArray();
}
return [];
}
}
}

View File

@@ -1,4 +1,5 @@
using Serein.NodeFlow.Model;
using Serein.Library.Api;
using Serein.NodeFlow.Model;
using Serein.Workbench.Node.ViewModel;
namespace Serein.Workbench.Node.View
@@ -10,8 +11,10 @@ namespace Serein.Workbench.Node.View
{
public ConditionNodeControl() : base()
{
// 窗体初始化需要
base.ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode(null));
var env = App.GetService<IFlowEnvironment>();
base.ViewModel = new ConditionNodeControlViewModel (new SingleConditionNode(env));
base.ViewModel.IsEnabledOnView = false;
DataContext = ViewModel;

View File

@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
d:DataContext="{d:DesignInstance vm:ExpOpNodeViewModel}"
d:DataContext="{d:DesignInstance vm:ExpOpNodeControlViewModel}"
mc:Ignorable="d"
MaxWidth="300">
<Grid>

View File

@@ -1,4 +1,5 @@
using Serein.NodeFlow.Model;
using Serein.Library.Api;
using Serein.NodeFlow.Model;
using Serein.Workbench.Node.ViewModel;
namespace Serein.Workbench.Node.View
@@ -11,7 +12,8 @@ namespace Serein.Workbench.Node.View
public ExpOpNodeControl() : base()
{
// 窗体初始化需要
ViewModel = new ExpOpNodeControlViewModel(new SingleExpOpNode(null));
var env = App.GetService<IFlowEnvironment>();
ViewModel = new ExpOpNodeControlViewModel(new SingleExpOpNode(env));
base.ViewModel.IsEnabledOnView = false;
DataContext = ViewModel;
InitializeComponent();

View File

@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:Converters="clr-namespace:Serein.Workbench.Tool.Converters"
xmlns:converter="clr-namespace:Serein.Workbench.Converters"
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
@@ -14,12 +14,10 @@
<UserControl.Resources>
<vm:TypeToStringConverter x:Key="TypeToStringConverter"/>
<!--<themes:ConditionControl x:Key="ConditionControl"/>-->
<Converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
<converter:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
</UserControl.Resources>
<Border BorderBrush="#FCB334" BorderThickness="1">
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails, UpdateSourceTrigger=PropertyChanged}" />
@@ -53,17 +51,11 @@
</Grid>
<!--<StackPanel Grid.Row="0" Orientation="Horizontal" Background="#FCB334">
<CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsEnable, Mode=TwoWay}" VerticalContentAlignment="Center"/>
<CheckBox IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}" VerticalContentAlignment="Center"/>
<TextBlock Text="{Binding NodeModel.MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>-->
<!--方法描述-->
<themes:MethodDetailsControl x:Name="MethodDetailsControl" Grid.Row="1" MethodDetails="{Binding NodeModel.MethodDetails}" />
<Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="LightBlue" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
Visibility="{Binding NodeModel.MethodDetails.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
<Border Grid.Row="2" x:Name="ParameterProtectionMask" Background="#40508D" Opacity="0.5" BorderBrush="#0A4651" BorderThickness="0"
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Converter={StaticResource InvertedBoolConverter},ConverterParameter=Normal}" />
<!--<Border Grid.Row="0" Background="#FCB334" >
</Border>-->
@@ -94,7 +86,7 @@
<StackPanel Orientation="Horizontal" Margin="2,1,2,1">
<CheckBox IsChecked="{Binding NodeModel.MethodDetails.IsProtectionParameter, Mode=TwoWay}"/>
<CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay}"/>
<TextBlock Text="参数保护" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>

View File

@@ -34,37 +34,33 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 方法入参控制点(可能有,可能没)
/// </summary>
JunctionControlBase[] INodeJunction.ArgDataJunction
{
get
{
// 获取 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>();
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction();
for (int i = 0; i < itemsControl.Items.Count; i++)
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 container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
if (container != null)
var argControl = FindVisualChild<ArgJunctionControl>(container);
if (argControl != null)
{
var argControl = FindVisualChild<ArgJunctionControl>(container);
if (argControl != null)
{
controls.Add(argControl); // 收集 ArgJunctionControl 实例
}
controls.Add(argControl); // 收集 ArgJunctionControl 实例
}
}
return argDataJunction = controls.ToArray();
}
else
{
return [];
}
return argDataJunction = controls.ToArray();
}
return [];
}
}

View File

@@ -1,16 +1,152 @@
<local:NodeControlBase x:Class="Serein.Workbench.Node.View.FlowCallNodeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance vm:FlipflopNodeControlViewModel}">
<Grid>
<!--选择画布-->
<!--选择公开的节点-->
</Grid>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Node.View"
xmlns:vm="clr-namespace:Serein.Workbench.Node.ViewModel"
xmlns:converter="clr-namespace:Serein.Workbench.Converters"
xmlns:themes="clr-namespace:Serein.Workbench.Themes"
mc:Ignorable="d"
MaxWidth="300"
d:DataContext="{d:DesignInstance vm:FlowCallNodeControlViewModel}">
<UserControl.Resources>
<converter:CountToVisibilityConverter x:Key="CountToVisibilityConverter"/>
<converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<converter:MethodDetailsSelectorConverter x:Key="MethodDetailsSelector"/>
<converter:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
</UserControl.Resources>
<Border BorderBrush="#C7FFE7" BorderThickness="1">
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="#071042" Content="{Binding NodeModel.MethodDetails}" />
</Grid.ToolTip>
<!--<TextBlock Text="{Binding NodeModel.DebugSetting.IsInterrupt}}"></TextBlock>-->
<!--DataContext="{Binding}-->
<Border x:Name="InterruptBorder" Tag="{Binding NodeModel.DebugSetting.IsInterrupt}">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Value="True">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="2" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Value="False">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid Background="#C7FFE7" >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<local:ExecuteJunctionControl Grid.Column="0" MyNode="{Binding NodeModel}" x:Name="ExecuteJunctionControl" HorizontalAlignment="Left" Grid.RowSpan="2"/>
<StackPanel Grid.Column="1" Grid.RowSpan="2" Orientation="Horizontal">
<TextBlock Text="[流程接口]" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding NodeModel.DisplayName, Mode=TwoWay}" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
<Grid x:Name="MethodInfoGrid" Grid.Row="2" Margin="10,0,10,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="画布" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Width="40"/>
<ComboBox Grid.Row="0"
Grid.Column="1"
DisplayMemberPath="Model.Name"
SelectedItem="{Binding SelectCanvas}"
ItemsSource="{Binding Canvass}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsEnabled="{Binding IsEnabledOnView}"/>
<TextBlock Text="节点" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" Width="40" Visibility="{Binding SelectCanvas.Model.PublicNodes, Converter={StaticResource CountToVisibilityConverter}}"/>
<ComboBox DisplayMemberPath="DisplayName"
Grid.Row="1" Grid.Column="1"
SelectedItem="{Binding SelectNode}"
ItemsSource="{Binding SelectCanvas.Model.PublicNodes, Mode=TwoWay}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsEnabled="{Binding IsEnabledOnView}"
Visibility="{Binding SelectCanvas.Model.PublicNodes, Converter={StaticResource CountToVisibilityConverter}}">
</ComboBox>
<themes:MethodDetailsControl Grid.Row="2" Grid.ColumnSpan="2" x:Name="MethodDetailsControl">
<themes:MethodDetailsControl.MethodDetails>
<MultiBinding Converter="{StaticResource MethodDetailsSelector}">
<Binding Path="FlowCallNode.IsShareParam" UpdateSourceTrigger="PropertyChanged"/>
<Binding Path="SelectNode.MethodDetails" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
<Binding Path="FlowCallNode.MethodDetails" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</themes:MethodDetailsControl.MethodDetails>
</themes:MethodDetailsControl>
</Grid>
<Border Grid.Row="2" x:Name="ParameterProtectionMask"
Background="#40508D" Opacity="0.5" BorderThickness="0"
Visibility="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter }}" />
<StackPanel Grid.Row="3" Background="Azure" Orientation="Horizontal" Margin="3">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding FlowCallNode.IsShareParam, Mode=TwoWay}"/>
<TextBlock Text="共享参数"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsEnable, Mode=TwoWay}"/>
<TextBlock Text="是否使能"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsProtectionParameter, Mode=TwoWay}"/>
<TextBlock Text="参数保护"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding NodeModel.DebugSetting.IsInterrupt, Mode=TwoWay}"/>
<TextBlock Text="中断节点"/>
</StackPanel>
</StackPanel>
</Grid>
</Border>
</Grid>
</Border>
</local:NodeControlBase>

View File

@@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serein.Library;
using Serein.Library.Api;
using Serein.NodeFlow.Model;
using Serein.Workbench.Node.ViewModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Serein.Workbench.Node.View
{
@@ -20,17 +12,79 @@ namespace Serein.Workbench.Node.View
/// </summary>
public partial class FlowCallNodeControl : NodeControlBase, INodeJunction
{
private new FlowCallNodeControlViewModel ViewModel { get; set; }
public FlowCallNodeControl()
{
var env = App.GetService<IFlowEnvironment>();
base.ViewModel = new FlowCallNodeControlViewModel(new SingleFlowCallNode(env));
base.ViewModel.IsEnabledOnView = false;
DataContext = base.ViewModel;
InitializeComponent();
}
public FlowCallNodeControl(FlowCallNodeControlViewModel viewModel) : base(viewModel)
{
DataContext = viewModel;
ViewModel = viewModel;
InitializeComponent();
ViewModel.UploadMethodDetailsControl = UploadMethodDetailsControl;
public JunctionControlBase ExecuteJunction => throw new NotImplementedException();
}
public JunctionControlBase NextStepJunction => throw new NotImplementedException();
private void UploadMethodDetailsControl(MethodDetails methodDetails)
{
//MethodDetailsControl.MethodDetails = methodDetails;
}
/// <summary>
/// 入参控制点(可能有,可能没)
/// </summary>
JunctionControlBase INodeJunction.ExecuteJunction => this.ExecuteJunctionControl;
/// <summary>
/// 下一个调用方法控制点(可能有,可能没)
/// </summary>
JunctionControlBase INodeJunction.NextStepJunction => throw new NotImplementedException("不存在下一个调用控制点");
/// <summary>
/// 返回值控制点(可能有,可能没)
/// </summary>
JunctionControlBase INodeJunction.ReturnDataJunction => throw new NotImplementedException("不存在返回值控制点");
/// <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 [];
}
public JunctionControlBase[] ArgDataJunction => throw new NotImplementedException();
public JunctionControlBase ReturnDataJunction => throw new NotImplementedException();
}
}

View File

@@ -1,4 +1,5 @@
using Serein.NodeFlow.Model;
using Serein.Library.Api;
using Serein.NodeFlow.Model;
using Serein.Workbench.Api;
using Serein.Workbench.Node.ViewModel;
@@ -12,7 +13,8 @@ namespace Serein.Workbench.Node.View
public GlobalDataControl() : base()
{
// 窗体初始化需要
base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(null));
var env = App.GetService<IFlowEnvironment>();
base.ViewModel = new GlobalDataNodeControlViewModel(new SingleGlobalDataNode(env));
base.ViewModel.IsEnabledOnView = false;
DataContext = ViewModel;
InitializeComponent();

View File

@@ -1,4 +1,5 @@
using Serein.NodeFlow.Model;
using Serein.Library.Api;
using Serein.NodeFlow.Model;
using Serein.Workbench.Node.ViewModel;
using System;
using System.Collections.Generic;
@@ -24,7 +25,9 @@ namespace Serein.Workbench.Node.View
{
public NetScriptNodeControl()
{
base.ViewModel = new NetScriptNodeControlViewModel(new SingleNetScriptNode(null));
var env = App.GetService<IFlowEnvironment>();
base.ViewModel = new NetScriptNodeControlViewModel(new SingleNetScriptNode(env));
base.ViewModel.IsEnabledOnView = false;
base.DataContext = ViewModel;
InitializeComponent();

View File

@@ -1,4 +1,5 @@
using Serein.NodeFlow.Model;
using Serein.Library.Api;
using Serein.NodeFlow.Model;
using Serein.Workbench.Node.ViewModel;
using System;
using System.Collections.Generic;
@@ -29,7 +30,9 @@ namespace Serein.Workbench.Node.View
public ScriptNodeControl()
{
base.ViewModel = new ScriptNodeControlViewModel(null);
var env = App.GetService<IFlowEnvironment>();
base.ViewModel = new ScriptNodeControlViewModel(new SingleScriptNode(env));
base.ViewModel.IsEnabledOnView = false;
base.DataContext = viewModel;
InitializeComponent();
@@ -68,39 +71,33 @@ namespace Serein.Workbench.Node.View
/// <summary>
/// 方法入参控制点(可能有,可能没)
/// </summary>
JunctionControlBase[] INodeJunction.ArgDataJunction
{
get
{
// 获取 MethodDetailsControl 实例
var methodDetailsControl = this.MethodDetailsControl;
var itemsControl = FindVisualChild<ItemsControl>(methodDetailsControl); // 查找 ItemsControl
if (itemsControl != null && base.ViewModel.NodeModel.MethodDetails.ParameterDetailss != null)
{
var argDataJunction = new JunctionControlBase[base.ViewModel.NodeModel.MethodDetails.ParameterDetailss.Length];
var controls = new List<JunctionControlBase>();
JunctionControlBase[] INodeJunction.ArgDataJunction => GetArgJunction();
for (int i = 0; i < itemsControl.Items.Count; i++)
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 container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as FrameworkElement;
if (container != null)
var argControl = FindVisualChild<ArgJunctionControl>(container);
if (argControl != null)
{
var argControl = FindVisualChild<ArgJunctionControl>(container);
if (argControl != null)
{
controls.Add(argControl); // 收集 ArgJunctionControl 实例
}
controls.Add(argControl); // 收集 ArgJunctionControl 实例
}
}
return argDataJunction = controls.ToArray();
}
else
{
return [];
}
return argDataJunction = controls.ToArray();
}
return [];
}

View File

@@ -1,7 +1,16 @@
using Serein.NodeFlow.Model;
using CommunityToolkit.Mvvm.ComponentModel;
using Serein.Library;
using Serein.NodeFlow.Model;
using Serein.Workbench.Api;
using Serein.Workbench.Services;
using Serein.Workbench.ViewModels;
using Serein.Workbench.Views;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
@@ -9,10 +18,101 @@ namespace Serein.Workbench.Node.ViewModel
{
public partial class FlowCallNodeControlViewModel : NodeControlViewModelBase
{
public new SingleFlowCallNode NodelModel { get; }
/// <summary>
/// 刷新方法控件
/// </summary>
public Action<MethodDetails> UploadMethodDetailsControl;
[ObservableProperty]
private SingleFlowCallNode flowCallNode;
/// <summary>
/// 当前所选画布
/// </summary>
[ObservableProperty]
private FlowCanvasViewModel _selectCanvas;
/// <summary>
/// 当前所选节点
/// </summary>
[ObservableProperty]
private NodeModelBase _selectNode;
[ObservableProperty]
private FlowCanvasViewModel[] canvass;
private readonly FlowNodeService flowNodeService;
private readonly IFlowEEForwardingService flowEEForwardingService;
public FlowCallNodeControlViewModel(SingleFlowCallNode node) : base(node)
{
this.NodelModel = node;
this.FlowCallNode = node;
flowNodeService = App.GetService<FlowNodeService>();
flowEEForwardingService = App.GetService<IFlowEEForwardingService>();
RershCanvass(); // 首次加载
InitNodeData();
InitEvent();
}
private void InitNodeData()
{
if (string.IsNullOrEmpty(FlowCallNode.TargetNodeGuid))
{
return;
}
var targetNodeControl = flowNodeService.FlowNodeControls.FirstOrDefault(n => n.ViewModel.NodeModel.Guid.Equals(FlowCallNode.TargetNodeGuid));
if (targetNodeControl is null)
{
return;
}
if (targetNodeControl.FlowCanvas is FlowCanvasView view
&& view.DataContext is FlowCanvasViewModel viewModel)
{
SelectCanvas = viewModel;
SelectNode = targetNodeControl.ViewModel.NodeModel;
}
}
private void InitEvent()
{
flowEEForwardingService.OnCanvasCreate += (e) => RershCanvass(); // 画布创建了
flowEEForwardingService.OnCanvasRemove += (e) => RershCanvass(); // 画布移除了
}
partial void OnSelectCanvasChanged(FlowCanvasViewModel value)
{
FlowCallNode.ResetTargetNode();
}
partial void OnSelectNodeChanged(NodeModelBase value)
{
FlowCallNode.SetTargetNode(value);
}
private void RershCanvass()
{
var canvass = flowNodeService.FlowCanvass.Select(f => (FlowCanvasViewModel)f.DataContext).ToArray(); // .Where(f => f.Model.PublicNodes.Count > 0)
Canvass = canvass;
}
/*private void RershMds()
{
if (NodeModel.IsShareParam && SelectNode is not null)
{
UploadMethodDetailsControl?.Invoke(SelectNode.MethodDetails);
}
else
{
UploadMethodDetailsControl?.Invoke(base.NodeModel.MethodDetails);
}
}
*/
}
}

View File

@@ -15,12 +15,16 @@
<ItemGroup>
<Compile Remove="Node\NodeModel\**" />
<Compile Remove="Themes\Condition\**" />
<Compile Remove="Tool\Converters\**" />
<EmbeddedResource Remove="Node\NodeModel\**" />
<EmbeddedResource Remove="Themes\Condition\**" />
<EmbeddedResource Remove="Tool\Converters\**" />
<None Remove="Node\NodeModel\**" />
<None Remove="Themes\Condition\**" />
<None Remove="Tool\Converters\**" />
<Page Remove="Node\NodeModel\**" />
<Page Remove="Themes\Condition\**" />
<Page Remove="Tool\Converters\**" />
</ItemGroup>
<ItemGroup>
@@ -30,6 +34,7 @@
<Compile Remove="Node\INodeContainerControl.cs" />
<Compile Remove="Node\Junction\NodeJunctionViewBase.cs" />
<Compile Remove="Node\NodeBase.cs" />
<Compile Remove="Node\ViewModel\ConditionRegionNodeControlViewModel.cs" />
<Compile Remove="Node\View\ActionRegionControl.xaml.cs" />
<Compile Remove="Node\View\ConditionRegionControl.xaml.cs" />
<Compile Remove="Node\View\DllControlControl.xaml.cs" />

View File

@@ -102,6 +102,7 @@ namespace Serein.Workbench.Services
/// 当前所有画布
/// </summary>
public FlowCanvasView[] FlowCanvass => Canvass.Select(c => c.Value).ToArray();
public NodeControlBase[] FlowNodeControls => NodeControls.Select(c => c.Value).ToArray();
/// <summary>
/// 记录流程画布
@@ -145,10 +146,10 @@ namespace Serein.Workbench.Services
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Flipflop, typeof(FlipflopNodeControl), typeof(FlipflopNodeControlViewModel));
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpOp, typeof(ExpOpNodeControl), typeof(ExpOpNodeControlViewModel));
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ExpCondition, typeof(ConditionNodeControl), typeof(ConditionNodeControlViewModel));
//flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.ConditionRegion, typeof(ConditionRegionControl), typeof(ConditionRegionNodeControlViewModel));
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.GlobalData, typeof(GlobalDataControl), typeof(GlobalDataNodeControlViewModel));
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.Script, typeof(ScriptNodeControl), typeof(ScriptNodeControlViewModel));
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.NetScript, typeof(NetScriptNodeControl), typeof(NetScriptNodeControlViewModel));
flowEnvironment.NodeMVVMManagement.RegisterUI(NodeControlType.FlowCall, typeof(FlowCallNodeControl), typeof(FlowCallNodeControlViewModel));
}
/// <summary>
@@ -301,6 +302,11 @@ namespace Serein.Workbench.Services
}
#endregion
//if (nodeModel.ControlType == NodeControlType.FlowCall)
//{
// Console.WriteLine("test");
//}
#region
NodeControlBase nodeControl;
@@ -335,6 +341,7 @@ namespace Serein.Workbench.Services
SereinEnv.WriteLine(InfoType.INFO, $"无法移除画布,画布不存在。");
return;
}
Canvass.Remove(eventArgs.CanvasGuid);
OnRemoveFlowCanvasView.Invoke(nodeCanvas);
}

View File

@@ -11,6 +11,7 @@ using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Serein.Workbench.Services
{
@@ -56,16 +57,25 @@ namespace Serein.Workbench.Services
private readonly IFlowEnvironment flowEnvironment;
private readonly IFlowEEForwardingService flowEEForwardingService;
private readonly IKeyEventService keyEventService;
private readonly FlowNodeService flowNodeService;
/// <summary>
/// 管理工作台的事件
/// </summary>
/// <param name="flowEnvironment"></param>
/// <param name="flowEEForwardingService"></param>
public WorkbenchEventService(IFlowEnvironment flowEnvironment, IFlowEEForwardingService flowEEForwardingService)
/// <param name="keyEventService"></param>
/// <param name="flowNodeService"></param>
public WorkbenchEventService(IFlowEnvironment flowEnvironment,
IFlowEEForwardingService flowEEForwardingService,
IKeyEventService keyEventService,
FlowNodeService flowNodeService)
{
this.flowEnvironment = flowEnvironment;
this.flowEEForwardingService = flowEEForwardingService;
this.keyEventService = keyEventService;
this.flowNodeService = flowNodeService;
InitEvents();
}
@@ -73,6 +83,12 @@ namespace Serein.Workbench.Services
{
flowEEForwardingService.OnProjectSaving += SaveProjectToLocalFile;
flowEEForwardingService.OnEnvOut += FlowEEForwardingService_OnEnvOut;
keyEventService.OnKeyDown += KeyEventService_OnKeyDown; ;
}
private void KeyEventService_OnKeyDown(System.Windows.Input.Key key)
{
}
private void FlowEEForwardingService_OnEnvOut(InfoType type, string value)

View File

@@ -5,17 +5,17 @@
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:serein="clr-namespace:Serein.Library;assembly=Serein.Library"
xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters">
xmlns:converter="clr-namespace:Serein.Workbench.Converters">
<ResourceDictionary.MergedDictionaries>
</ResourceDictionary.MergedDictionaries>
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
<converters:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
<converter:InvertableBooleanToVisibilityConverter x:Key="InvertedBoolConverter"/>
<converter:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
<local:DescriptionOrNameConverter x:Key="DescOrNameConverter"/>
<Style TargetType="{x:Type local:MethodDetailsControl}">
<Setter Property="Template">
<Setter.Value>
@@ -112,6 +112,29 @@
</Setter.Value>
</Setter>
</MultiDataTrigger>
<!--显示FlowCall节点方法入参名称-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding NodeModel.ControlType}" Value="{x:Static serein:NodeControlType.FlowCall}"/>
</MultiDataTrigger.Conditions>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Grid.Column="0" MinWidth="50">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource DescOrNameConverter}">
<Binding Path="Description"/>
<Binding Path="Name"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>

View File

@@ -12,10 +12,11 @@
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal">
<!--<nodeView:NetScriptNodeControl x:Name="NetScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
<nodeView:ScriptNodeControl x:Name="ScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:GlobalDataControl x:Name="GlobalDataControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ExpOpNodeControl x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ConditionNodeControl x:Name="ConditionNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:FlowCallNodeControl MaxWidth="250" MaxHeight="100" x:Name="FlowCallNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ScriptNodeControl MaxWidth="250" MaxHeight="100" x:Name="ScriptNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:GlobalDataControl MaxWidth="250" MaxHeight="100" x:Name="GlobalDataControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ExpOpNodeControl MaxWidth="250" MaxHeight="100" x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<nodeView:ConditionNodeControl MaxWidth="250" MaxHeight="100" x:Name="ConditionNodeControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<!--<nodeView:ConditionRegionControl x:Name="ConditionRegionControl" Margin="10" AllowDrop="True" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>-->
</StackPanel>
</ScrollViewer>

View File

@@ -4,7 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Views"
xmlns:tool="clr-namespace:Serein.Workbench.Tool.Converters"
xmlns:converter="clr-namespace:Serein.Workbench.Converters"
xmlns:vm="clr-namespace:Serein.Workbench.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450"
@@ -12,10 +12,10 @@
d:DataContext="{d:DesignInstance vm:FlowCanvasViewModel}">
<UserControl.Resources>
<tool:RightThumbPositionConverter x:Key="RightThumbPositionConverter" />
<tool:BottomThumbPositionConverter x:Key="BottomThumbPositionConverter" />
<tool:VerticalCenterThumbPositionConverter x:Key="VerticalCenterThumbPositionConverter" />
<tool:HorizontalCenterThumbPositionConverter x:Key="HorizontalCenterThumbPositionConverter" />
<converter:RightThumbPositionConverter x:Key="RightThumbPositionConverter" />
<converter:BottomThumbPositionConverter x:Key="BottomThumbPositionConverter" />
<converter:VerticalCenterThumbPositionConverter x:Key="VerticalCenterThumbPositionConverter" />
<converter:HorizontalCenterThumbPositionConverter x:Key="HorizontalCenterThumbPositionConverter" />
</UserControl.Resources>
<DockPanel x:Name="FlowChartStackPanel"

View File

@@ -87,6 +87,14 @@ namespace Serein.Workbench.Views
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); // 配置相关事件
@@ -294,7 +302,7 @@ namespace Serein.Workbench.Views
flowNodeService = App.GetService<FlowNodeService>();
keyEventService = App.GetService<IKeyEventService>();
flowNodeService.OnCreateNode += OnCreateNode;
keyEventService.OnKeyDown += KeyEventService_OnKeyDown; ;
keyEventService.OnKeyDown += KeyEventService_OnKeyDown;
// 缩放平移容器
canvasTransformGroup = new TransformGroup();
@@ -413,14 +421,25 @@ namespace Serein.Workbench.Views
{
return;
}
if (key == Key.F5)
{
// F5 调试当前流程
_ = flowEnvironment.StartFlowAsync([Guid]);
}
if (keyEventService.GetKeyState(Key.LeftCtrl) || keyEventService.GetKeyState(Key.RightCtrl))
{
// Ctrl + F5 调试当前流程
_ = flowEnvironment.StartFlowAsync([flowNodeService.CurrentSelectCanvas.Guid]);
}
else if (selectNodeControls.Count == 1 )
{
// F5 调试当前选定节点
var nodeModel = selectNodeControls[0].ViewModel.NodeModel;
SereinEnv.WriteLine(InfoType.INFO, $"调试运行当前节点:{nodeModel.Guid}");
_ = nodeModel.StartFlowAsync(new DynamicContext(flowEnvironment), new CancellationToken());
}
}
if (key == Key.Escape)
@@ -630,6 +649,7 @@ namespace Serein.Workbench.Views
Type when typeof(GlobalDataControl).IsAssignableFrom(droppedType) => NodeControlType.GlobalData,
Type when typeof(ScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.Script,
Type when typeof(NetScriptNodeControl).IsAssignableFrom(droppedType) => NodeControlType.NetScript,
Type when typeof(FlowCallNodeControl).IsAssignableFrom(droppedType) => NodeControlType.FlowCall,
_ => NodeControlType.None,
};
if (nodeControlType != NodeControlType.None)
@@ -1146,7 +1166,7 @@ namespace Serein.Workbench.Views
if (sender is NodeControlBase nodeControl)
{
//ChangeViewerObjOfNode(nodeControl); // 对象树
if (nodeControl?.ViewModel?.NodeModel?.MethodDetails?.IsProtectionParameter == true) return;
//if (nodeControl?.ViewModel?.NodeModel?.DebugSetting.IsProtectionParameter == true) return;
IsControlDragging = true;
startControlDragPoint = e.GetPosition(FlowChartCanvas); // 记录鼠标按下时的位置
((UIElement)sender).CaptureMouse(); // 捕获鼠标

View File

@@ -4,14 +4,14 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Serein.Workbench.Views"
xmlns:converters="clr-namespace:Serein.Workbench.Tool.Converters"
xmlns:converter="clr-namespace:Serein.Workbench.Converters"
xmlns:vm="clr-namespace:Serein.Workbench.ViewModels"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance vm:FlowEditViewModel}"
Background="#E7F0F6">
<UserControl.Resources>
<converters:InvertableBooleanToVisibilityConverter x:Key="InvertableBooleanToVisibilityConverter"/>
<converter:InvertableBooleanToVisibilityConverter x:Key="InvertableBooleanToVisibilityConverter"/>
</UserControl.Resources>
<Grid>