GIT练习

This commit is contained in:
fengjiayi
2024-08-05 10:11:58 +08:00
parent 1b7d61c390
commit 75333e621f
84 changed files with 11677 additions and 0 deletions

16
WorkBench/App.xaml Normal file
View File

@@ -0,0 +1,16 @@
<Application x:Class="Serein.WorkBench.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Serein.WorkBench"
StartupUri="MainWindow.xaml"
Startup="Application_Startup">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--<ResourceDictionary Source="/Themes/ExplicitDataControl.xaml" />-->
<ResourceDictionary Source="/Themes/MethodDetailsControl.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

170
WorkBench/App.xaml.cs Normal file
View File

@@ -0,0 +1,170 @@
using Serein;
using Serein.DynamicFlow.SerinExpression;
using Serein.WorkBench.Themes;
using Newtonsoft.Json;
using SqlSugar;
using SqlSugar.Extensions;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Windows;
namespace Serein.WorkBench
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public class TestObject
{
public NestedObject Data { get; set; }
public class NestedObject
{
public int Code { get; set; }
public int Code2 { get; set; }
public string Tips { get; set; }
}
public string ToUpper(string input)
{
return input.ToUpper();
}
}
public App()
{
#if false //测试 操作表达式,条件表达式
#region
string expression = "";
var testObj = new TestObject
{
Data = new TestObject.NestedObject
{
Code = 15,
Code2 = 20,
Tips = "测试数据"
}
};
#endregion
#region
// 获取对象成员
var result = SerinExpressionEvaluator.Evaluate("get .Data.Code", testObj);
Debug.WriteLine(result); // 15
// 设置对象成员
SerinExpressionEvaluator.Evaluate("set .Data.Code = 20", testObj);
Debug.WriteLine(testObj.Data.Code); // 20
SerinExpressionEvaluator.Evaluate("set .Data.Tips = 123", testObj);
// 调用对象方法
result = SerinExpressionEvaluator.Evaluate($"invoke .ToUpper({SerinExpressionEvaluator.Evaluate("get .Data.Tips", testObj)})", testObj);
Debug.WriteLine(result); // HELLO
expression = "@number (@+1)/100";
result = SerinExpressionEvaluator.Evaluate(expression, 2);
Debug.WriteLine($"{expression} -> {result}"); // HELLO
#endregion
#region
expression = ".Data.Code == 15";
var pass = SerinConditionParser.To(testObj, expression);
Debug.WriteLine($"{expression} -> " + pass);
expression = ".Data.Code<int>[@*2] == 31";
//expression = ".Data.Tips<string> contains 数据";
pass = SerinConditionParser.To(testObj, expression);
Debug.WriteLine($"{expression} -> " + pass);
expression = ".Data.Code<int> < 20";
pass = SerinConditionParser.To(testObj, expression);
Debug.WriteLine($"{expression} -> " + pass);
int i = 43;
expression = "in 11-22";
pass = SerinConditionParser.To(i, expression);
Debug.WriteLine($"{i} {expression} -> " + pass);
expression = "== 43";
pass = SerinConditionParser.To(i, expression);
Debug.WriteLine($"{i} {expression} -> " + pass);
string str = "MY NAME IS COOOOL";
expression = "c NAME";
pass = SerinConditionParser.To(str, expression);
Debug.WriteLine($"{str} {expression} -> " + pass);
#endregion
#endif
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit/**/(e);
// 强制关闭所有窗口
foreach (Window window in Windows)
{
window.Close();
}
}
public static SereinOutputFileData? FData;
public static string FileDataPath = "";
private void Application_Startup(object sender, StartupEventArgs e)
{
// 示例:写入调试信息
Debug.WriteLine("应用程序启动");
// 检查是否传入了参数
if (e.Args.Length == 1)
{
// 获取文件路径
string filePath = e.Args[0];
// 检查文件是否存在
if (!System.IO.File.Exists(filePath))
{
MessageBox.Show($"文件未找到:{filePath}");
Shutdown(); // 关闭应用程序
return;
}
try
{
// 读取文件内容
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
FData = JsonConvert.DeserializeObject<SereinOutputFileData>(content);
FileDataPath = System.IO.Path.GetDirectoryName(filePath) ?? "";
}
catch (Exception ex)
{
MessageBox.Show($"读取文件时发生错误:{ex.Message}");
Shutdown(); // 关闭应用程序
}
}
else if(1 == 11)
{
string filePath =
@"D:\Project\C#\DynamicControl\DynamicControl\DynamicDemo\bin\Debug\net8.0-windows7.0\project 233.dnf";
//@"D:\Project\C#\DynamicControl\DynamicControl\DynamicDemo\bin\Debug\net8.0-windows7.0\demo project\node project.dnf";
string content = System.IO.File.ReadAllText(filePath); // 读取整个文件内容
FData = JsonConvert.DeserializeObject<SereinOutputFileData>(content);
App.FileDataPath = System.IO.Path.GetDirectoryName(filePath);
}
}
}
}

10
WorkBench/AssemblyInfo.cs Normal file
View File

@@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

22
WorkBench/LogWindow.xaml Normal file
View File

@@ -0,0 +1,22 @@
<Window x:Class="Serein.WorkBench.LogWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Serein.WorkBench"
mc:Ignorable="d"
Title="LogWindow" Height="600" Width="400"
Closing="Window_Closing">
<Grid>
<TextBox x:Name="LogTextBox"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
IsReadOnly="True"
TextWrapping="Wrap"/>
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Clear Log" Click="ClearLog_Click"/>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</Window>

View File

@@ -0,0 +1,33 @@
using System.Windows;
namespace Serein.WorkBench
{
/// <summary>
/// DebugWindow.xaml 的交互逻辑
/// </summary>
public partial class LogWindow : Window
{
public LogWindow()
{
InitializeComponent();
}
public void AppendText(string text)
{
Dispatcher.BeginInvoke(() =>
{
LogTextBox.AppendText(text);
LogTextBox.ScrollToEnd();
});
}
private void ClearLog_Click(object sender, RoutedEventArgs e)
{
LogTextBox.Clear();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true; // 取消关闭操作
this.Hide(); // 隐藏窗体而不是关闭
}
}
}

92
WorkBench/MainWindow.xaml Normal file
View File

@@ -0,0 +1,92 @@
<Window x:Class="Serein.WorkBench.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Serein.WorkBench"
xmlns:custom="clr-namespace:Serein.WorkBench.Node.View"
Title="Dynamic Node Flow" Height="700" Width="1200"
AllowDrop="True" Drop="Window_Drop" DragOver="Window_DragOver"
Loaded="Window_Loaded"
Closing="Window_Closing">
<Window.InputBindings>
<KeyBinding Key="Escape" Command="{Binding CancelConnectionCommand}"/>
</Window.InputBindings>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0" Background="#F5F5F5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="2*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<!--<Button Grid.Row="0" Content="Button 1"></Button>
<Button Grid.Row="1" Content="Button 2"></Button>
<Button Grid.Row="2" Content="Button 3"></Button>
<Button Grid.Row="3" Content="Button 4"></Button>-->
<!--DockPanel.Dock="Top"-->
<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="UnloadAllButton_Click" HorizontalAlignment="Right" Margin="5,5,5,5"/>
</Grid>
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal">
<!--<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>-->
<custom:ExpOpNodeControl x:Name="ExpOpNodeControl" Margin="10" AllowDrop="True" Drop="ConditionRegionControl_Drop" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<custom:ConditionNodeControl x:Name="ConditionNodeControl" Margin="10" AllowDrop="True" Drop="ConditionNodeControl_Drop" PreviewMouseMove="BaseNodeControl_PreviewMouseMove"/>
<custom:ConditionRegionControl x:Name="ConditionRegionControl" Margin="10" AllowDrop="True" Drop="ConditionRegionControl_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"/>-->
<!--<custom:StateRegionControl x:Name="StateRegionControl" Grid.Column="2" Margin="10" AllowDrop="True" Drop="StateRegionControl_Drop" PreviewMouseMove="RegionControl_PreviewMouseMove"/>-->
<!--</Grid>-->
</StackPanel>
</ScrollViewer>
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="DllStackPanel" Margin="5"/>
</ScrollViewer>
</Grid>
</DockPanel>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ResizeBehavior="PreviousAndNext" Background="Gray"/>
<Grid Grid.Column="2" >
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Background="#F5F5F5" Orientation="Horizontal" >
<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>
</StackPanel>
<ScrollViewer Grid.Row="1"
x:Name="FlowChartScrollViewer"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
SizeChanged="FlowChartScrollViewer_SizeChanged">
<Canvas x:Name="FlowChartCanvas"
Background="#F2EEE8"
Width="1000" Height="1000"
AllowDrop="True"
MouseLeftButtonDown="FlowChartCanvas_MouseLeftButtonDown"
Drop="FlowChartCanvas_Drop"
DragOver="FlowChartCanvas_DragOver"/>
</ScrollViewer>
</Grid>
</Grid>
</Window>

2031
WorkBench/MainWindow.xaml.cs Normal file

File diff suppressed because it is too large Load Diff

270
WorkBench/Node/NodeBase.cs Normal file
View File

@@ -0,0 +1,270 @@
namespace DySerin;
/*public class ConditionNode : NodeBase, ICondition
{
private Func<bool> ConditionFunc { get; set; }
public ConditionNode(Func<bool> conditionFunc)
{
ConditionFunc = conditionFunc;
}
public override void Execute()
{
if (ConditionFunc())
{
EnterTrueBranch();
}
else
{
EnterFalseBranch();
}
}
// 实现条件接口的方法
public bool Evaluate(DynamicContext context)
{
Context = context; // 更新节点的上下文
return ConditionFunc();
}
}
public class ActionNode : NodeBase, IAction
{
private Action ActionMethod { get; set; }
public ActionNode(Action actionMethod)
{
ActionMethod = actionMethod;
}
public override void Execute()
{
try
{
ActionMethod();
EnterTrueBranch(); // 动作成功,进入真分支
}
catch (Exception ex)
{
// 可添加异常处理逻辑
Return(); // 动作失败,终止节点
}
}
// 实现动作接口的方法
public void Execute(DynamicContext context)
{
Context = context; // 更新节点的上下文
Execute();
}
}
*/
/*
/// <summary>
/// 根节点
/// </summary>
public abstract class NodeControl : UserControl
{
public string Id { get; set; }
public string Name { get; set; }
public abstract void Execute(NodeContext context);
}
/// <summary>
/// 条件节点
/// </summary>
public class ConditionNodeControl : NodeControl
{
public Func<NodeContext, bool> Condition { get; set; }
public NodeControl TrueNode { get; set; }
public NodeControl FalseNode { get; set; }
public ConditionNodeControl()
{
this.Content = new TextBlock { Text = "条件节点" };
this.Background = Brushes.LightBlue;
}
public override void Execute(NodeContext context)
{
if (Condition(context))
{
TrueNode?.Execute(context);
}
else
{
FalseNode?.Execute(context);
}
}
}
/// <summary>
/// 动作节点
/// </summary>
public class ActionNodeControl : NodeControl
{
public Action<NodeContext> Action { get; set; }
public ActionNodeControl()
{
this.Content = new TextBlock { Text = "动作节点" };
this.Background = Brushes.LightGreen;
}
public override void Execute(NodeContext context)
{
Action?.Invoke(context);
}
}
/// <summary>
/// 状态节点
/// </summary>
public class StateNodeControl : NodeControl
{
public Func<NodeContext, object> StateFunction { get; set; }
public StateNodeControl()
{
this.Content = new TextBlock { Text = "状态节点" };
this.Background = Brushes.LightYellow;
}
public override void Execute(NodeContext context)
{
var result = StateFunction(context);
context.Set("StateResult", result);
}
}
/// <summary>
/// 节点上下文
/// </summary>
public class NodeContext
{
private readonly Dictionary<string, object> _data = new Dictionary<string, object>();
public void Set<T>(string key, T value)
{
_data[key] = value;
}
public T Get<T>(string key)
{
return _data.ContainsKey(key) ? (T)_data[key] : default;
}
}
*/
/*
public class Context
{
public Dictionary<string, object> Data { get; set; } = new Dictionary<string, object>();
public void Set<T>(string key, T value)
{
Data[key] = value;
}
public T Get<T>(string key)
{
return Data.ContainsKey(key) ? (T)Data[key] : default;
}
}
public interface INode
{
Context Enter(Context context);
Context Exit(Context context);
}
public partial class ConditionNode : INode
{
public Func<Context, bool> Condition { get; set; }
public INode TrueBranch { get; set; }
public INode FalseBranch { get; set; }
public Context Enter(Context context)
{
if (Condition(context))
{
return TrueBranch?.Enter(context) ?? context;
}
else
{
return FalseBranch?.Enter(context) ?? context;
}
}
public Context Exit(Context context)
{
return context;
}
}
public partial class ActionNode : INode
{
public Action<Context> Action { get; set; }
public bool IsTask { get; set; }
public Context Enter(Context context)
{
if (IsTask)
{
Task.Run(() => Action(context));
}
else
{
Action(context);
}
return context;
}
public Context Exit(Context context)
{
return context;
}
}
public partial class StateNode : INode
{
public Context Enter(Context context)
{
return context;
}
public Context Exit(Context context)
{
return context;
}
}
*/

View File

@@ -0,0 +1,41 @@
<local:NodeControlBase x:Class="Serein.WorkBench.Node.View.ActionNodeControl"
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"
>
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ToolTip>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#FFCFDF" BorderBrush="#FFCFDF" BorderThickness="1">
<TextBlock Text="{Binding MethodDetails.MethodName, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />
<Grid Grid.Row="2" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#EAFFD0" BorderBrush="#EAFFD0" BorderThickness="1">
<TextBlock Text="result" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Grid.Column="1" Background="#EAFFD0" BorderBrush="#EAFFD0" BorderThickness="1">
<TextBlock Text="{Binding MethodDetails.ReturnType}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border>
</Grid>
</Grid>
</local:NodeControlBase>

View File

@@ -0,0 +1,22 @@
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.ViewModel;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// ActionNode.xaml 的交互逻辑
/// </summary>
public partial class ActionNodeControl : NodeControlBase
{
private readonly ActionNodeControlViewModel actionNodeControlViewModel;
public ActionNodeControl(SingleActionNode node) : base(node)
{
Node = node;
actionNodeControlViewModel = new ActionNodeControlViewModel(node);
DataContext = actionNodeControlViewModel;
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,30 @@
<local:NodeControlBase x:Class="Serein.WorkBench.Node.View.ActionRegionControl"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Border BorderBrush="Black" BorderThickness="1" Padding="10">
<StackPanel>
<Grid Margin="2,2,2,5">
<TextBlock Text="动作区域" FontWeight="Bold" HorizontalAlignment="Left" FontSize="14" Margin="0,1,0,0"/>
<Button Content="编辑" FontWeight="Bold" HorizontalAlignment="Right"/>
</Grid>
<ListBox x:Name="ActionsListBox" AllowDrop="True" Drop="ActionsListBox_Drop" />
</StackPanel>
</Border>
<Thumb x:Name="ResizeTop" Cursor="SizeNS" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Top"
DragDelta="ResizeTop_DragDelta"/>
<Thumb x:Name="ResizeBottom" Cursor="SizeNS" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
DragDelta="ResizeBottom_DragDelta"/>
<Thumb x:Name="ResizeLeft" Cursor="SizeWE" Width="4" HorizontalAlignment="Left" VerticalAlignment="Stretch"
DragDelta="ResizeLeft_DragDelta"/>
<Thumb x:Name="ResizeRight" Cursor="SizeWE" Width="4" HorizontalAlignment="Right" VerticalAlignment="Stretch"
DragDelta="ResizeRight_DragDelta"/>
</Grid>
</local:NodeControlBase>

View File

@@ -0,0 +1,147 @@
using Serein.DynamicFlow.NodeModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using static Serein.WorkBench.MainWindow;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// ActionRegion.xaml 的交互逻辑
/// </summary>
public partial class ActionRegionControl : NodeControlBase
{
private Point _dragStartPoint;
private new readonly CompositeActionNode Node;
public ActionRegionControl() : base()
{
InitializeComponent();
}
public ActionRegionControl(CompositeActionNode node) : base(node)
{
InitializeComponent();
Node = node;
base.Name = "动作组合节点";
}
#region
private void ResizeTop_DragDelta(object sender, DragDeltaEventArgs e)
{
double oldHeight = Height;
double newHeight = Math.Max(MinHeight, oldHeight - e.VerticalChange);
Height = newHeight;
Canvas.SetTop(this, Canvas.GetTop(this) + (oldHeight - newHeight));
}
private void ResizeBottom_DragDelta(object sender, DragDeltaEventArgs e)
{
double newHeight = Math.Max(MinHeight, Height + e.VerticalChange);
Height = newHeight;
}
private void ResizeLeft_DragDelta(object sender, DragDeltaEventArgs e)
{
double oldWidth = Width;
double newWidth = Math.Max(MinWidth, oldWidth - e.HorizontalChange);
Width = newWidth;
Canvas.SetLeft(this, Canvas.GetLeft(this) + (oldWidth - newWidth));
}
private void ResizeRight_DragDelta(object sender, DragDeltaEventArgs e)
{
double newWidth = Math.Max(MinWidth, Width + e.HorizontalChange);
Width = newWidth;
}
#endregion
public void AddAction(NodeControlBase node, bool isTask = false)
{
/*TextBlock actionText = new TextBlock
{
Text = node.MethodDetails.MethodName + (isTask ? " (Task)" : ""),
Margin = new Thickness(10, 2, 0, 0),
Tag = node.MethodDetails,
};*/
Node?.AddNode((SingleActionNode)node.Node);
ActionsListBox.Items.Add(node);
}
/* public async Task ExecuteActions(DynamicContext context)
{
foreach (TextBlock item in ActionsListBox.Items)
{
dynamic tag = item.Tag;
IAction action = tag.Action;
bool isTask = tag.IsTask;
if (isTask)
{
await Task.Run(() => action.Execute(Node.MethodDetails, context));
}
else
{
action.Execute(Node.MethodDetails, context);
}
}
}*/
private void ActionsListBox_Drop(object sender, DragEventArgs e)
{
/*if (e.Data.GetDataPresent("Type"))
{
Type droppedType = e.Data.GetData("Type") as Type;
if (droppedType != null && typeof(ICondition).IsAssignableFrom(droppedType) && droppedType.IsClass)
{
// 创建一个新的 TextBlock 并设置其属性
TextBlock conditionText = new TextBlock
{
Text = droppedType.Name,
Margin = new Thickness(10, 2, 0, 0),
Tag = droppedType
};
// 为 TextBlock 添加鼠标左键按下事件处理程序
// conditionText.MouseLeftButtonDown += TypeText_MouseLeftButtonDown;
// 为 TextBlock 添加鼠标移动事件处理程序
// conditionText.MouseMove += TypeText_MouseMove;
// 将 TextBlock 添加到 ActionsListBox 中
ActionsListBox.Items.Add(conditionText);
}
}*/
e.Handled = true;
}
// 用于拖动的鼠标事件处理程序
private void TypeText_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_dragStartPoint = e.GetPosition(null);
}
private void TypeText_MouseMove(object sender, MouseEventArgs e)
{
Point mousePos = e.GetPosition(null);
Vector diff = _dragStartPoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
if (sender is TextBlock typeText)
{
var dragData = new DataObject(MouseNodeType.RegionType, typeText.Tag);
DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move);
}
}
}
}
}

View File

@@ -0,0 +1,75 @@
<local:NodeControlBase x:Class="Serein.WorkBench.Node.View.ConditionNodeControl"
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 Type=vm:ConditionNodeControlViewModel}"-->
<UserControl.Resources>
<!--<vm:TypeToStringConverter x:Key="TypeToStringConverter"/>-->
<BooleanToVisibilityConverter x:Key="BoolToVis" />
</UserControl.Resources>
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ToolTip>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#A8D8EA" BorderBrush="#A8D8EA" BorderThickness="1" HorizontalAlignment="Stretch">
<TextBlock Text="条件节点" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Grid Grid.Row="1" Background="#F1FFDF" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" IsChecked="{Binding IsCustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> <!--Converter={StaticResource BoolToVis}-->
<TextBox Grid.Column="1" MinWidth="50" Text="{Binding CustomData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" VerticalAlignment="Center">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCustomData}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBlock Grid.Column="1" MinWidth="50" Text="上一节点数据" HorizontalAlignment="Stretch" VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCustomData}" Value="False">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
<TextBox Grid.Row="2" Background="#f1F66F" MinWidth="100" Text="{Binding Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<!--<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />
<Border Grid.Row="2" Background="#EAFFD0" BorderBrush="#EAFFD0" BorderThickness="1">
<TextBlock Text="{Binding MethodDetails.MethodTips, Converter={StaticResource TypeToStringConverter}, StringFormat=return:{0}, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>-->
</Grid>
</local:NodeControlBase>

View File

@@ -0,0 +1,37 @@
using Serein.DynamicFlow;
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.ViewModel;
using static Serein.WorkBench.MainWindow;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows;
using static Dm.net.buffer.ByteArrayBuffer;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// ConditionNode.xaml 的交互逻辑
/// </summary>
public partial class ConditionNodeControl : NodeControlBase
{
private readonly ConditionNodeControlViewModel viewModel;
public ConditionNodeControl() : base()
{
viewModel = new (new ());
DataContext = viewModel;
InitializeComponent();
}
public ConditionNodeControl(SingleConditionNode node) : base(node)
{
Node = node;
viewModel = new ConditionNodeControlViewModel(node);
DataContext = viewModel;
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,34 @@
<local:NodeControlBase x:Class="Serein.WorkBench.Node.View.ConditionRegionControl"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Border BorderBrush="Black" BorderThickness="1" Padding="10">
<StackPanel>
<DockPanel Margin="2,2,2,5">
<!--<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>-->
<TextBlock Text="条件区域" FontWeight="Bold" HorizontalAlignment="Left" FontSize="14" Margin="0,1,0,0"/>
<Button Content="编辑" FontWeight="Bold" HorizontalAlignment="Right"/>
</DockPanel>
<ListBox x:Name="ConditionsListBox" AllowDrop="True" Drop="ConditionsListBox_Drop"/>
</StackPanel>
</Border>
<Thumb x:Name="ResizeTop" Cursor="SizeNS" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Top"
DragDelta="ResizeTop_DragDelta"/>
<Thumb x:Name="ResizeBottom" Cursor="SizeNS" Height="4" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
DragDelta="ResizeBottom_DragDelta"/>
<Thumb x:Name="ResizeLeft" Cursor="SizeWE" Width="4" HorizontalAlignment="Left" VerticalAlignment="Stretch"
DragDelta="ResizeLeft_DragDelta"/>
<Thumb x:Name="ResizeRight" Cursor="SizeWE" Width="4" HorizontalAlignment="Right" VerticalAlignment="Stretch"
DragDelta="ResizeRight_DragDelta"/>
</Grid>
</local:NodeControlBase>

View File

@@ -0,0 +1,125 @@
using Serein.DynamicFlow;
using Serein.DynamicFlow.NodeModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using static Serein.WorkBench.MainWindow;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// ConditionRegion.xaml 的交互逻辑
/// </summary>
public partial class ConditionRegionControl : NodeControlBase
{
private Point _dragStartPoint;
public ConditionRegionControl() : base()
{
InitializeComponent();
}
public ConditionRegionControl(CompositeConditionNode node) : base(node)
{
Node = node;
InitializeComponent();
}
#region
private void ResizeTop_DragDelta(object sender, DragDeltaEventArgs e)
{
double oldHeight = Height;
double newHeight = Math.Max(MinHeight, oldHeight - e.VerticalChange);
Height = newHeight;
Canvas.SetTop(this, Canvas.GetTop(this) + (oldHeight - newHeight));
}
private void ResizeBottom_DragDelta(object sender, DragDeltaEventArgs e)
{
double newHeight = Math.Max(MinHeight, Height + e.VerticalChange);
Height = newHeight;
}
private void ResizeLeft_DragDelta(object sender, DragDeltaEventArgs e)
{
double oldWidth = Width;
double newWidth = Math.Max(MinWidth, oldWidth - e.HorizontalChange);
Width = newWidth;
Canvas.SetLeft(this, Canvas.GetLeft(this) + (oldWidth - newWidth));
}
private void ResizeRight_DragDelta(object sender, DragDeltaEventArgs e)
{
double newWidth = Math.Max(MinWidth, Width + e.HorizontalChange);
Width = newWidth;
}
#endregion
/// <summary>
/// 添加条件控件
/// </summary>
/// <param name="condition"></param>
public void AddCondition(NodeControlBase node)
{
((CompositeConditionNode)Node).AddNode((SingleConditionNode)node.Node);
this.Width += node.Width;
this.Height += node.Height;
ConditionsListBox.Items.Add(node);
}
private void ConditionsListBox_Drop(object sender, DragEventArgs e)
{
e.Handled = true;
}
// Mouse event handlers for dragging
private void TypeText_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_dragStartPoint = e.GetPosition(null);
}
private void TypeText_MouseMove(object sender, MouseEventArgs e)
{
Point mousePos = e.GetPosition(null);
Vector diff = _dragStartPoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
if (sender is TextBlock typeText)
{
var dragData = new DataObject(MouseNodeType.RegionType, typeText.Tag);
DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move);
}
}
}
/*private void TypeText_MouseMove(object sender, MouseEventArgs e)
{
Point mousePos = e.GetPosition(null);
Vector diff = _dragStartPoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
TextBlock typeText = sender as TextBlock;
if (typeText != null)
{
DataObject dragData = new DataObject("Type", typeText.Tag);
DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move);
}
}
}
*/
}
}

View File

@@ -0,0 +1,41 @@
<UserControl x:Class="Serein.WorkBench.Node.View.DllControl"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
>
<DockPanel>
<StackPanel DockPanel.Dock="Top" >
<TextBlock Text="{Binding Path=Header, RelativeSource={RelativeSource AncestorType=UserControl}}"
FontWeight="Bold" FontSize="14" Margin="5" Background="#dbe2ef"/>
</StackPanel>
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<!--<ColumnDefinition Width="*" />-->
</Grid.ColumnDefinitions>
<GroupBox Grid.Row="0" Header="条件" Margin="5">
<ListBox x:Name="ConditionsListBox" Background="#A8D8EA"/>
</GroupBox>
<GroupBox Grid.Row="1" Header="动作" Margin="5">
<ListBox x:Name="ActionsListBox" Background="#FFCFDF"/>
</GroupBox>
<GroupBox Grid.Row="2" Header="触发器" Margin="5">
<ListBox x:Name="FlipflopsListBox" Background="#FFFFD2"/>
</GroupBox>
</Grid>
</DockPanel>
</DockPanel>
</UserControl>

View File

@@ -0,0 +1,146 @@
using Serein.DynamicFlow;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using static Serein.WorkBench.MainWindow;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// UserControl1.xaml 的交互逻辑
/// </summary>
public partial class DllControl : UserControl
{
public DllControl()
{
Header = "DLL文件"; // 设置初始值
InitializeComponent();
}
/// <summary>
/// Header 依赖属性,用于绑定标题
/// </summary>
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(DllControl), new PropertyMetadata(string.Empty));
/// <summary>
/// 向条件面板添加类型的文本块
/// </summary>
/// <param name="type">要添加的类型</param>
public void AddCondition(MethodDetails md)
{
AddTypeToListBox(md, ConditionsListBox);
}
/// <summary>
/// 向动作面板添加类型的文本块
/// </summary>
/// <param name="type">要添加的类型</param>
public void AddAction(MethodDetails md)
{
AddTypeToListBox(md, ActionsListBox);
}
/// <summary>
/// 向状态面板添加类型的文本块
/// </summary>
/// <param name="type">要添加的类型</param>
public void AddFlipflop(MethodDetails md)
{
AddTypeToListBox(md, FlipflopsListBox);
}
/// <summary>
/// 向指定面板添加类型的文本块
/// </summary>
/// <param name="type">要添加的类型</param>
/// <param name="panel">要添加到的面板</param>
private void AddTypeToListBox(MethodDetails md, ListBox listBox)
{
// 创建一个新的 TextBlock 并设置其属性
TextBlock typeText = new TextBlock
{
Text = $"{md.MethodName}",
Margin = new Thickness(10, 2, 0, 0),
Tag = md
};
// 为 TextBlock 添加鼠标左键按下事件处理程序
typeText.MouseLeftButtonDown += TypeText_MouseLeftButtonDown;
// 为 TextBlock 添加鼠标移动事件处理程序
typeText.MouseMove += TypeText_MouseMove;
// 将 TextBlock 添加到指定的面板
listBox.Items.Add(typeText);
}
/// <summary>
/// 存储拖拽开始时的鼠标位置
/// </summary>
private Point _dragStartPoint;
/// <summary>
/// 处理 TextBlock 的鼠标左键按下事件
/// </summary>
/// <param name="sender">事件源</param>
/// <param name="e">事件参数</param>
private void TypeText_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// 记录鼠标按下时的位置
_dragStartPoint = e.GetPosition(null);
}
/// <summary>
/// 处理 TextBlock 的鼠标移动事件
/// </summary>
/// <param name="sender">事件源</param>
/// <param name="e">事件参数</param>
private void TypeText_MouseMove(object sender, MouseEventArgs e)
{
// 获取当前鼠标位置
Point mousePos = e.GetPosition(null);
// 计算鼠标移动的距离
Vector diff = _dragStartPoint - mousePos;
// 判断是否符合拖拽的最小距离要求
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
// 获取触发事件的 TextBlock
TextBlock typeText = sender as TextBlock;
if (typeText != null)
{
// 创建一个 DataObject 用于拖拽操作,并设置拖拽效果
DataObject dragData = new DataObject(MouseNodeType.DllNodeType, typeText.Tag);
DragDrop.DoDragDrop(typeText, dragData, DragDropEffects.Move);
}
}
}
}
}

View File

@@ -0,0 +1,20 @@
<local:NodeControlBase x:Class="Serein.WorkBench.Node.View.ExpOpNodeControl"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--<TextBlock Grid.Row="0" Text=""></TextBlock>-->
<StackPanel Grid.Row="0" Orientation="Vertical" Background="LightSteelBlue">
<TextBlock Grid.Row="2" Text="表达式"></TextBlock>
<TextBox Text="{Binding Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch"></TextBox>
</StackPanel>
</Grid>
</local:NodeControlBase>

View File

@@ -0,0 +1,43 @@
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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
{
/// <summary>
/// ExprOpNodeControl.xaml 的交互逻辑
/// </summary>
public partial class ExpOpNodeControl : NodeControlBase
{
private readonly ExpOpNodeViewModel viewModel;
public ExpOpNodeControl()
{
viewModel = new (new());
DataContext = viewModel;
InitializeComponent();
}
public ExpOpNodeControl(SingleExpOpNode node):base(node)
{
Node = node;
viewModel = new(node);
DataContext = viewModel;
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,34 @@
<local:NodeControlBase x:Class="Serein.WorkBench.Node.View.FlipflopNodeControl"
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="1400">
<UserControl.Resources>
<vm:TypeToStringConverter x:Key="TypeToStringConverter"/>
<!--<themes:ConditionControl x:Key="ConditionControl"/>-->
</UserControl.Resources>
<Grid>
<Grid.ToolTip>
<ToolTip Background="LightYellow" Foreground="Black" Content="{Binding MethodDetails.MethodTips, UpdateSourceTrigger=PropertyChanged}" />
</Grid.ToolTip>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#FFFFD2" BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding MethodDetails.MethodName, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<!--<themes:ExplicitDataControl Grid.Row="1" ExplicitDatas="{Binding ExplicitDatas}" />-->
<themes:MethodDetailsControl Grid.Row="1" MethodDetails="{Binding MethodDetails}" />
<!--<themes:ConditionControl Grid.Row="2" ></themes:ConditionControl>-->
</Grid>
</local:NodeControlBase>

View File

@@ -0,0 +1,41 @@
using Serein.DynamicFlow;
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.ViewModel;
using System.Windows;
using System.Windows.Controls;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// StateNode.xaml 的交互逻辑
/// </summary>
public partial class FlipflopNodeControl : NodeControlBase
{
private readonly FlipflopNodeControlViewModel viewModel;
public FlipflopNodeControl(SingleFlipflopNode node) : base(node)
{
Node = node;
viewModel = new FlipflopNodeControlViewModel(node);
DataContext = viewModel;
InitializeComponent();
}
//private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
//{
// var comboBox = sender as ComboBox;
// if (comboBox == null)
// {
// return;
// }
// var selectedExplicitData = comboBox.DataContext as ExplicitData;
// if (selectedExplicitData == null)
// {
// return;
// }
// Console.WriteLine (selectedExplicitData.DataValue, "Selected Value");
//}
}
}

View File

@@ -0,0 +1,77 @@
using Serein.DynamicFlow;
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Themes;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;
using System.Windows.Media;
namespace Serein.WorkBench.Node.View
{
/// <summary>
/// 节点控件基类(控件)
/// </summary>
public abstract class NodeControlBase : UserControl, IDynamicFlowNode
{
public NodeBase Node { get; set; }
protected NodeControlBase()
{
this.Background = Brushes.Transparent;
}
protected NodeControlBase(NodeBase node)
{
Node = node;
}
}
public abstract class NodeControlViewModel : INotifyPropertyChanged
{
public MethodDetails methodDetails;
public MethodDetails MethodDetails
{
get => methodDetails;
set
{
methodDetails = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class FLowNodeObObservableCollection<T> : ObservableCollection<T>
{
public void AddRange(IEnumerable<T> items)
{
foreach (var item in items)
{
this.Items.Add(item);
}
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
}
}

View File

@@ -0,0 +1,33 @@
using Serein.DynamicFlow;
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.View;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Serein.WorkBench.Node.ViewModel
{
public class ActionNodeControlViewModel : NodeControlViewModel
{
private readonly SingleActionNode node;
public ActionNodeControlViewModel(SingleActionNode node)
{
this.node = node;
MethodDetails = node.MethodDetails;
//if (node.MethodDetails.ExplicitDatas.Length == 0)
//{
// // 没有显式项
// IsExistExplicitData = false;
// ExplicitDatas = [];
//}
//else
//{
// explicitDatas = node.MethodDetails.ExplicitDatas;
// //ExplicitDatas = node.MethodDetails.ExplicitDatas;
// IsExistExplicitData = true;
//}
}
}
}

View File

@@ -0,0 +1,49 @@
using Serein.DynamicFlow;
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.View;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using static Dm.net.buffer.ByteArrayBuffer;
namespace Serein.WorkBench.Node.ViewModel
{
public class ConditionNodeControlViewModel : NodeControlViewModel
{
private readonly SingleConditionNode singleConditionNode;
/// <summary>
/// 是否为自定义参数
/// </summary>
public bool IsCustomData
{
get => singleConditionNode.IsCustomData;
set { singleConditionNode.IsCustomData= value; OnPropertyChanged(); }
}
/// <summary>
/// 自定义参数值
/// </summary>
public object? CustomData
{
get => singleConditionNode.CustomData;
set { singleConditionNode.CustomData = value ; OnPropertyChanged(); }
}
/// <summary>
/// 表达式
/// </summary>
public string Expression
{
get => singleConditionNode.Expression;
set { singleConditionNode.Expression = value; OnPropertyChanged(); }
}
public ConditionNodeControlViewModel(SingleConditionNode node)
{
this.singleConditionNode = node;
MethodDetails = node.MethodDetails;
IsCustomData = false;
CustomData = "";
Expression = "PASS";
}
}
}

View File

@@ -0,0 +1,31 @@
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.WorkBench.Node.ViewModel
{
public class ExpOpNodeViewModel: NodeControlViewModel
{
public readonly SingleExpOpNode node;
public string Expression
{
get => node.Expression;
set
{
node.Expression = value;
OnPropertyChanged();
}
}
public ExpOpNodeViewModel(SingleExpOpNode node)
{
this.node = node;
}
}
}

View File

@@ -0,0 +1,15 @@
using Serein.DynamicFlow.NodeModel;
using Serein.WorkBench.Node.View;
namespace Serein.WorkBench.Node.ViewModel
{
public class FlipflopNodeControlViewModel : NodeControlViewModel
{
private readonly SingleFlipflopNode node;
public FlipflopNodeControlViewModel(SingleFlipflopNode node)
{
this.node = node;
MethodDetails = node.MethodDetails;
}
}
}

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.Node.ViewModel
{
public class TypeToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Type type)
{
return type.ToString();
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>True</UseWPF>
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Node\NodeModel\**" />
<Compile Remove="Themes\Condition\**" />
<EmbeddedResource Remove="Node\NodeModel\**" />
<EmbeddedResource Remove="Themes\Condition\**" />
<None Remove="Node\NodeModel\**" />
<None Remove="Themes\Condition\**" />
<Page Remove="Node\NodeModel\**" />
<Page Remove="Themes\Condition\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Node\FlipflopRegionControl.xaml.cs" />
<Compile Remove="Node\NodeBase.cs" />
<Compile Remove="Themes\ConditionControl.xaml.cs" />
<Compile Remove="Themes\ConditionControlModel.cs" />
<Compile Remove="Themes\ExplicitDataControl.xaml.cs" />
</ItemGroup>
<ItemGroup>
<Page Remove="Node\FlipflopRegionControl.xaml" />
<Page Remove="Themes\ConditionControl.xaml" />
<Page Remove="Themes\ExplicitDataControl.xaml" />
</ItemGroup>
<ItemGroup>
<!--<ProjectReference Include="..\DynamicControl\DynamicControl.csproj" />-->
<ProjectReference Include="..\Library\Serein.Library.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Compile Update="Themes\MethodDetailsControl.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.WorkBench
{
public class SereinOutputFileData
{
/// <summary>
/// 基础
/// </summary>
public Basic basic { get; set; }
/// <summary>
/// 依赖的DLL
/// </summary>
public Library[] library { get; set; }
/// <summary>
/// 起始节点GUID
/// </summary>
public string startNode { get; set; }
/// <summary>
/// 节点信息集合
/// </summary>
public NodeInfo[] nodes { get; set; }
/// <summary>
/// 区域集合
/// </summary>
public Region[] regions { get; set; }
}
/// <summary>
/// 基础
/// </summary>
public class Basic
{
/// <summary>
/// 画布
/// </summary>
public FlowCanvas canvas { get; set; }
/// <summary>
/// 版本
/// </summary>
public string versions { get; set; }
}
/// <summary>
/// 画布
/// </summary>
public class FlowCanvas
{
/// <summary>
/// 宽度
/// </summary>
public float width { get; set; }
/// <summary>
/// 高度
/// </summary>
public float lenght { get; set; }
}
/// <summary>
/// DLL
/// </summary>
public class Library
{
/// <summary>
/// DLL名称
/// </summary>
public string name { get; set; }
/// <summary>
/// 路径
/// </summary>
public string path { get; set; }
/// <summary>
/// 提示
/// </summary>
public string tips { get; set; }
}
/// <summary>
/// 节点
/// </summary>
public class NodeInfo
{
/// <summary>
/// GUID
/// </summary>
public string guid { get; set; }
/// <summary>
/// 名称
/// </summary>
public string name { get; set; }
/// <summary>
/// 显示标签
/// </summary>
public string label { get; set; }
/// <summary>
/// 类型
/// </summary>
public string type { get; set; }
/// <summary>
/// 于画布中的位置
/// </summary>
public Position position { get; set; }
/// <summary>
/// 真分支节点GUID
/// </summary>
public string[] trueNodes { get; set; }
/// <summary>
/// 假分支节点
/// </summary>
public string[] falseNodes { get; set; }
}
/// <summary>
/// 节点于画布中的位置
/// </summary>
public class Position
{
public float x { get; set; }
public float y { get; set; }
}
/// <summary>
/// 区域
/// </summary>
public class Region
{
public string guid { get; set; }
public NodeInfo[] childNodes { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
<UserControl x:Class="DynamicDemo.Themes.Condition.BoolConditionControl"
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:DynamicDemo.Themes.Condition"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ComboBox x:Name="ConditionComboBox"
SelectedValue="{Binding Condition, Mode=TwoWay}">
<ComboBoxItem Content="Is True" Tag="IsTrue" />
<ComboBoxItem Content="Is False" Tag="IsFalse" />
</ComboBox>
</Grid>
</UserControl>

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 DynamicDemo.Themes.Condition
{
/// <summary>
/// BoolConditionControl.xaml 的交互逻辑
/// </summary>
public partial class BoolConditionControl : UserControl
{
public BoolConditionControl()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,21 @@
<UserControl x:Class="DynamicDemo.Themes.Condition.IntConditionControl"
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:DynamicDemo.Themes.Condition"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ComboBox x:Name="ConditionComboBox"
SelectedValue="{Binding Condition, Mode=TwoWay}">
<ComboBoxItem Content="Greater Than" Tag="GreaterThan" />
<ComboBoxItem Content="Less Than" Tag="LessThan" />
<ComboBoxItem Content="Equal To" Tag="EqualTo" />
<ComboBoxItem Content="Between" Tag="Between" />
<ComboBoxItem Content="Not Between" Tag="NotBetween" />
<ComboBoxItem Content="Not In Range" Tag="NotInRange" />
</ComboBox>
<TextBox x:Name="ValueTextBox" Text="{Binding Value, Mode=TwoWay}" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 DynamicDemo.Themes.Condition
{
/// <summary>
/// IntConditionControl.xaml 的交互逻辑
/// </summary>
public partial class IntConditionControl : UserControl
{
public IntConditionControl()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DynamicDemo.Themes.Condition
{
//public class IntConditionNode : ConditionNode
//{
// public int Value { get; set; }
// public int MinValue { get; set; }
// public int MaxValue { get; set; }
// public List<int> ExcludeValues { get; set; }
// public override bool Evaluate(object value)
// {
// if (value is int intValue)
// {
// switch (Condition)
// {
// case ConditionType.GreaterThan:
// return intValue > Value;
// case ConditionType.LessThan:
// return intValue < Value;
// case ConditionType.EqualTo:
// return intValue == Value;
// case ConditionType.Between:
// return intValue >= MinValue && intValue <= MaxValue;
// case ConditionType.NotBetween:
// return intValue < MinValue || intValue > MaxValue;
// case ConditionType.NotInRange:
// return !ExcludeValues.Contains(intValue);
// default:
// return false;
// }
// }
// return false;
// }
//}
//public class BoolConditionNode : ConditionNode
//{
// public override bool Evaluate(object value)
// {
// if (value is bool boolValue)
// {
// switch (Condition)
// {
// case ConditionType.IsTrue:
// return boolValue;
// case ConditionType.IsFalse:
// return !boolValue;
// default:
// return false;
// }
// }
// return false;
// }
//}
//public class StringConditionNode : ConditionNode
//{
// public string Substring { get; set; }
// public override bool Evaluate(object value)
// {
// if (value is string stringValue)
// {
// switch (Condition)
// {
// case ConditionType.Contains:
// return stringValue.Contains(Substring);
// case ConditionType.DoesNotContain:
// return !stringValue.Contains(Substring);
// case ConditionType.IsNotEmpty:
// return !string.IsNullOrEmpty(stringValue);
// default:
// return false;
// }
// }
// return false;
// }
//}
}

View File

@@ -0,0 +1,18 @@
<UserControl x:Class="DynamicDemo.Themes.Condition.StringConditionControl"
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:DynamicDemo.Themes.Condition"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ComboBox x:Name="ConditionComboBox"
SelectedValue="{Binding Condition, Mode=TwoWay}">
<ComboBoxItem Content="Contains" Tag="Contains" />
<ComboBoxItem Content="Does Not Contain" Tag="DoesNotContain" />
<ComboBoxItem Content="Is Not Empty" Tag="IsNotEmpty" />
</ComboBox>
<TextBox x:Name="SubstringTextBox" Text="{Binding Substring, Mode=TwoWay}" />
</Grid>
</UserControl>

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 DynamicDemo.Themes.Condition
{
/// <summary>
/// StringConditionControl.xaml 的交互逻辑
/// </summary>
public partial class StringConditionControl : UserControl
{
public StringConditionControl()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,35 @@
<UserControl x:Class="DynamicDemo.Themes.ConditionControl"
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:DynamicDemo.Themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--<ComboBox x:Name="ConditionTypeComboBox" SelectionChanged="ConditionTypeComboBox_SelectionChanged">
<ComboBoxItem Content="GreaterThan" Tag="{x:Static local:ConditionType.GreaterThan}"/>
<ComboBoxItem Content="LessThan" Tag="{x:Static local:ConditionType.LessThan}"/>
<ComboBoxItem Content="EqualTo" Tag="{x:Static local:ConditionType.EqualTo}"/>
<ComboBoxItem Content="InRange" Tag="{x:Static local:ConditionType.InRange}"/>
<ComboBoxItem Content="NotInRange" Tag="{x:Static local:ConditionType.NotInRange}"/>
<ComboBoxItem Content="NotInSpecificRange" Tag="{x:Static local:ConditionType.NotInSpecificRange}"/>
<ComboBoxItem Content="IsTrue" Tag="{x:Static local:ConditionType.IsTrue}"/>
<ComboBoxItem Content="IsFalse" Tag="{x:Static local:ConditionType.IsFalse}"/>
<ComboBoxItem Content="Contains" Tag="{x:Static local:ConditionType.Contains}"/>
<ComboBoxItem Content="DoesNotContain" Tag="{x:Static local:ConditionType.DoesNotContain}"/>
<ComboBoxItem Content="IsNotEmpty" Tag="{x:Static local:ConditionType.IsNotEmpty}"/>
</ComboBox>
<TextBox x:Name="ValueTextBox" Visibility="Collapsed"/>
<TextBox x:Name="Value2TextBox" Visibility="Collapsed"/>-->
<StackPanel Grid.Row="0" x:Name="ConditionsPanel" Orientation="Vertical" Height="400"/>
<Button Grid.Row="1" Content="Add Condition" Click="OnAddConditionClicked" />
<!-- 其他控件 -->
</Grid>
</UserControl>

View File

@@ -0,0 +1,85 @@
using DynamicDemo.Themes.Condition;
using System.Windows;
using System.Windows.Controls;
namespace DynamicDemo.Themes
{
/// <summary>
/// ConditionControl.xaml 的交互逻辑
/// </summary>
public partial class ConditionControl : UserControl
{
public ConditionControl()
{
InitializeComponent();
}
//private void ConditionTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
//{
// var selectedType = (ConditionType)((ComboBoxItem)ConditionTypeComboBox.SelectedItem).Tag;
// UpdateInputVisibility(selectedType);
//}
//private void UpdateInputVisibility(ConditionType type)
//{
// ValueTextBox.Visibility = Visibility.Collapsed;
// Value2TextBox.Visibility = Visibility.Collapsed;
// switch (type)
// {
// case ConditionType.GreaterThan:
// case ConditionType.LessThan:
// case ConditionType.EqualTo:
// case ConditionType.Contains:
// case ConditionType.DoesNotContain:
// ValueTextBox.Visibility = Visibility.Visible;
// break;
// case ConditionType.InRange:
// case ConditionType.NotInRange:
// ValueTextBox.Visibility = Visibility.Visible;
// Value2TextBox.Visibility = Visibility.Visible;
// break;
// case ConditionType.IsTrue:
// case ConditionType.IsFalse:
// case ConditionType.IsNotEmpty:
// // No additional input needed
// break;
// case ConditionType.NotInSpecificRange:
// // Handle specific range input, possibly with a different control
// break;
// }
//}
private void OnAddConditionClicked(object sender, RoutedEventArgs e)
{
// 示例添加一个IntConditionNode
var intConditionNode = new IntConditionNode { Condition = ConditionType.GreaterThan, Value = 10 };
AddConditionNode(intConditionNode);
}
public void AddConditionNode(ConditionNode node)
{
UserControl control = null;
if (node is IntConditionNode)
{
control = new IntConditionControl { DataContext = node };
}
else if (node is BoolConditionNode)
{
control = new BoolConditionControl { DataContext = node };
}
else if (node is StringConditionNode)
{
control = new StringConditionControl { DataContext = node };
}
if (control != null)
{
ConditionsPanel.Children.Add(control);
}
}
}
}

View File

@@ -0,0 +1,99 @@
namespace DynamicDemo.Themes;
public enum ConditionType
{
GreaterThan,
LessThan,
EqualTo,
Between,
NotBetween,
NotInRange,
IsTrue,
IsFalse,
Contains,
DoesNotContain,
IsNotEmpty
}
public abstract class ConditionNode
{
public ConditionType Condition { get; set; }
public abstract bool Evaluate(object value);
}
public class IntConditionNode : ConditionNode
{
public int Value { get; set; }
public int MinValue { get; set; }
public int MaxValue { get; set; }
public List<int> ExcludeValues { get; set; }
public override bool Evaluate(object value)
{
if (value is int intValue)
{
switch (Condition)
{
case ConditionType.GreaterThan:
return intValue > Value;
case ConditionType.LessThan:
return intValue < Value;
case ConditionType.EqualTo:
return intValue == Value;
case ConditionType.Between:
return intValue >= MinValue && intValue <= MaxValue;
case ConditionType.NotBetween:
return intValue < MinValue || intValue > MaxValue;
case ConditionType.NotInRange:
return !ExcludeValues.Contains(intValue);
default:
return false;
}
}
return false;
}
}
public class BoolConditionNode : ConditionNode
{
public override bool Evaluate(object value)
{
if (value is bool boolValue)
{
switch (Condition)
{
case ConditionType.IsTrue:
return boolValue;
case ConditionType.IsFalse:
return !boolValue;
default:
return false;
}
}
return false;
}
}
public class StringConditionNode : ConditionNode
{
public string Substring { get; set; }
public override bool Evaluate(object value)
{
if (value is string stringValue)
{
switch (Condition)
{
case ConditionType.Contains:
return stringValue.Contains(Substring);
case ConditionType.DoesNotContain:
return !stringValue.Contains(Substring);
case ConditionType.IsNotEmpty:
return !string.IsNullOrEmpty(stringValue);
default:
return false;
}
}
return false;
}
}

View File

@@ -0,0 +1,115 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Serein.WorkBench.Themes"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type local:MethodDetailsControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MethodDetailsControl}">
<ItemsControl ItemsSource="{Binding MethodDetails.ExplicitDatas, RelativeSource={RelativeSource TemplatedParent}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsExplicitData}" Value="false" />
</MultiDataTrigger.Conditions>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid Background="#E3FDFD">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Index,StringFormat=agr{0}}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<CheckBox Grid.Column="1" IsChecked="{Binding IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
<TextBlock Grid.Column="2" MinWidth="50" Text="{Binding ParameterName}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Grid.Column="3" MinWidth="50" Text="无须指定参数"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsExplicitData}" Value="true" />
<Condition Binding="{Binding ExplicitTypeName}" Value="Select" />
</MultiDataTrigger.Conditions>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid Background="#E3FDFD">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Index,StringFormat=agr{0}}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<CheckBox Grid.Column="1" IsChecked="{Binding IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
<TextBlock Grid.Column="2" MinWidth="50" Text="{Binding ParameterName}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<ComboBox Grid.Column="3"
MinWidth="50"
ItemsSource="{Binding Items}"
SelectedItem="{Binding DataValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsExplicitData}" Value="true" />
<Condition Binding="{Binding ExplicitTypeName}" Value="Value" />
<!--<Condition Binding="{Binding ExplicitTypeName}" Value="{x:Type sys:String}" />
<Condition Binding="{Binding ExplicitTypeName}" Value="{x:Type sys:Double}" />-->
</MultiDataTrigger.Conditions>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid Background="#E3FDFD">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Index,StringFormat=agr{0}}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<CheckBox Grid.Column="1" IsChecked="{Binding IsExplicitData, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></CheckBox>
<TextBlock Grid.Column="2" MinWidth="50" Text="{Binding ParameterName}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBox Grid.Column="3" MinWidth="50" Text="{Binding DataValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,74 @@
using Serein.DynamicFlow;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Themes
{
public class MultiConditionConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is Type valueType && values[1] is bool isEnabled)
{
if (isEnabled)
{
if (valueType == typeof(string) || valueType == typeof(int) || valueType == typeof(double))
{
return "TextBoxTemplate";
}
else if (typeof(IEnumerable).IsAssignableFrom(valueType))
{
return "ComboBoxTemplate";
}
}
}
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public partial class MethodDetailsControl : UserControl//,ItemsControl
{
static MethodDetailsControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MethodDetailsControl), new FrameworkPropertyMetadata(typeof(MethodDetailsControl)));
}
public MethodDetails MethodDetails
{
get { return (MethodDetails)GetValue(MethodDetailsProperty); }
set { SetValue(MethodDetailsProperty, value); }
}
public static readonly DependencyProperty MethodDetailsProperty = DependencyProperty.Register("MethodDetails", typeof(MethodDetails),
typeof(MethodDetailsControl), new PropertyMetadata(null, new PropertyChangedCallback(OnPropertyChange)));
static void OnPropertyChange(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var MethodDetails = (MethodDetails)args.NewValue;
//MethodDetails.ExplicitDatas[0].
}
}
}

View File

@@ -0,0 +1,4 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</ResourceDictionary>

View File

@@ -0,0 +1,15 @@
<Window x:Class="Serein.WorkBench.Themes.TypeViewerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Serein.WorkBench.Themes"
mc:Ignorable="d"
Topmost="True"
Title="TypeViewerWindow" Height="300" Width="300">
<Grid>
<Grid>
<TreeView x:Name="TypeTreeView"/>
</Grid>
</Grid>
</Window>

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
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.Shapes;
namespace Serein.WorkBench.Themes
{
/// <summary>
/// TypeViewerWindow.xaml 的交互逻辑
/// </summary>
public partial class TypeViewerWindow : Window
{
public TypeViewerWindow()
{
InitializeComponent();
}
public Type Type { get; set; }
public void LoadTypeInformation()
{
if (Type == null)
return;
var rootNode = new TreeViewItem { Header = Type.Name };
AddMembersToTreeNode(rootNode, Type);
TypeTreeView.Items.Clear();
TypeTreeView.Items.Add(rootNode);
}
private void AddMembersToTreeNode(TreeViewItem node, Type type)
{
var members = type.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var member in members)
{
var memberNode = new TreeViewItem { Header = member.Name };
if (member is PropertyInfo property)
{
var propertyType = property.PropertyType;
memberNode.Header = $"{member.Name} : {propertyType.Name}";
if (!propertyType.IsPrimitive && propertyType != typeof(string))
{
AddMembersToTreeNode(memberNode, propertyType);
}
}
else if (member is MethodInfo method)
{
var parameters = method.GetParameters();
var paramStr = string.Join(", ", parameters.Select(p => $"{p.ParameterType.Name} {p.Name}"));
memberNode.Header = $"{member.Name}({paramStr})";
}
else if (member is FieldInfo field)
{
memberNode.Header = $"{member.Name} : {field.FieldType.Name}";
}
node.Items.Add(memberNode);
}
}
}
}

View File

@@ -0,0 +1,45 @@
using System.IO;
using System.Text;
namespace Serein.WorkBench.tool
{
/// <summary>
/// 可以捕获类库输出的打印输出
/// </summary>
public class LogTextWriter(Action<string> logAction) : TextWriter
{
private readonly Action<string> logAction = logAction;
private readonly StringWriter stringWriter = new();
public override Encoding Encoding => Encoding.UTF8;
public override void Write(char value)
{
stringWriter.Write(value);
if (value == '\n')
{
logAction(stringWriter.ToString());
stringWriter.GetStringBuilder().Clear();
}
}
public override void Write(string? value)
{
if(string.IsNullOrWhiteSpace(value)) { return; }
stringWriter.Write(value);
if (value.Contains('\n'))
{
logAction(stringWriter.ToString());
stringWriter.GetStringBuilder().Clear();
}
}
public override void WriteLine(string? value)
{
if (string.IsNullOrWhiteSpace(value)) { return; }
stringWriter.WriteLine(value);
logAction(stringWriter.ToString());
stringWriter.GetStringBuilder().Clear();
}
}
}