移植命令树,命令管理,日志管理
This commit is contained in:
parent
a585333636
commit
e87c097c4e
@ -1,4 +1,5 @@
|
|||||||
using BOB.ViewModels;
|
using BOB.Models;
|
||||||
|
using BOB.ViewModels;
|
||||||
using BOB.ViewModels.Dialogs;
|
using BOB.ViewModels.Dialogs;
|
||||||
using BOB.Views;
|
using BOB.Views;
|
||||||
using BOB.Views.Dialogs;
|
using BOB.Views.Dialogs;
|
||||||
@ -33,7 +34,8 @@ namespace BOB
|
|||||||
containerRegistry.RegisterForNavigation<MainView>("MainView");
|
containerRegistry.RegisterForNavigation<MainView>("MainView");
|
||||||
//注册弹窗
|
//注册弹窗
|
||||||
containerRegistry.RegisterDialog<MessageBoxView, MessageBoxViewModel>("MessageBox");
|
containerRegistry.RegisterDialog<MessageBoxView, MessageBoxViewModel>("MessageBox");
|
||||||
|
//注册全局变量
|
||||||
|
containerRegistry.RegisterSingleton<GlobalVariables>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="gong-wpf-dragdrop" Version="4.0.0" />
|
||||||
<PackageReference Include="MaterialDesignColors" Version="5.3.0" />
|
<PackageReference Include="MaterialDesignColors" Version="5.3.0" />
|
||||||
<PackageReference Include="MaterialDesignThemes" Version="5.3.0" />
|
<PackageReference Include="MaterialDesignThemes" Version="5.3.0" />
|
||||||
<PackageReference Include="MaterialDesignThemes.MahApps" Version="5.3.0" />
|
<PackageReference Include="MaterialDesignThemes.MahApps" Version="5.3.0" />
|
||||||
|
|||||||
18
BOB/GlobalVariables.cs
Normal file
18
BOB/GlobalVariables.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using BOB.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BOB
|
||||||
|
{
|
||||||
|
public class GlobalVariables
|
||||||
|
{
|
||||||
|
public ProgramModel Program = new();
|
||||||
|
public bool IsAdmin=true;
|
||||||
|
public String UserName="hsc";
|
||||||
|
public string CurrentFilePath;
|
||||||
|
public StepModel SelectedStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
BOB/Models/DeviceModel.cs
Normal file
52
BOB/Models/DeviceModel.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BOB.Models
|
||||||
|
{
|
||||||
|
public class DeviceModel
|
||||||
|
{
|
||||||
|
public DeviceModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeviceModel(DeviceModel source)
|
||||||
|
{
|
||||||
|
ID = source.ID;
|
||||||
|
ParameterID = source.ParameterID;
|
||||||
|
Name = source.Name;
|
||||||
|
Connected = source.Connected;
|
||||||
|
ErrorMessage = source.ErrorMessage;
|
||||||
|
Type = source.Type;
|
||||||
|
ConnectString = source.ConnectString;
|
||||||
|
CommunicationProtocol = source.CommunicationProtocol;
|
||||||
|
Description = source.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ID { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
public Guid ParameterID { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool Connected { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public string? ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
public string Type { get; set; } = "Tcp";
|
||||||
|
|
||||||
|
public string ConnectString { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public object? CommunicationProtocol { get; set; }
|
||||||
|
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,13 +4,15 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
namespace BOB.Models
|
namespace BOB.Models
|
||||||
{
|
{
|
||||||
public class InstructionNode
|
public class InstructionNode
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public ObservableCollection<InstructionNode> Children { get; set; } = new();
|
public ObservableCollection<InstructionNode> Children { get; set; } = new();
|
||||||
|
public object Tag { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
40
BOB/Models/MethodModel.cs
Normal file
40
BOB/Models/MethodModel.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BOB.Models
|
||||||
|
{
|
||||||
|
public class MethodModel
|
||||||
|
{
|
||||||
|
|
||||||
|
#region 构造函数
|
||||||
|
|
||||||
|
public MethodModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodModel(MethodModel source)
|
||||||
|
{
|
||||||
|
if (source == null) return;
|
||||||
|
|
||||||
|
Name = source.Name;
|
||||||
|
FullName = source.FullName;
|
||||||
|
|
||||||
|
// 深拷贝参数
|
||||||
|
Parameters = new ObservableCollection<ParameterModel>(
|
||||||
|
source.Parameters.Select(p => new ParameterModel(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
public string? FullName { get; set; }
|
||||||
|
|
||||||
|
public ObservableCollection<ParameterModel> Parameters { get; set; } = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
316
BOB/Models/ParameterModel.cs
Normal file
316
BOB/Models/ParameterModel.cs
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Prism.Mvvm; // 引入 Prism 的 BindableBase
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BOB.Models
|
||||||
|
{
|
||||||
|
public class ParameterModel : BindableBase
|
||||||
|
{
|
||||||
|
#region 构造函数
|
||||||
|
|
||||||
|
public ParameterModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterModel(ParameterModel source)
|
||||||
|
{
|
||||||
|
if (source == null) return;
|
||||||
|
|
||||||
|
ID = source.ID;
|
||||||
|
Name = source.Name;
|
||||||
|
Type = source.Type;
|
||||||
|
Category = source.Category;
|
||||||
|
IsUseVar = source.IsUseVar;
|
||||||
|
IsSave = source.IsSave;
|
||||||
|
VariableName = source.VariableName;
|
||||||
|
VariableID = source.VariableID;
|
||||||
|
IsGlobal = source.IsGlobal;
|
||||||
|
Value = source.Value;
|
||||||
|
LowerLimit = source.LowerLimit;
|
||||||
|
UpperLimit = source.UpperLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Guid _id = Guid.NewGuid();
|
||||||
|
public Guid ID
|
||||||
|
{
|
||||||
|
get => _id;
|
||||||
|
set => SetProperty(ref _id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isVisible = true;
|
||||||
|
public bool IsVisible
|
||||||
|
{
|
||||||
|
get => _isVisible;
|
||||||
|
set => SetProperty(ref _isVisible, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _name;
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set => SetProperty(ref _name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type _type = typeof(string);
|
||||||
|
public Type Type
|
||||||
|
{
|
||||||
|
get => _type;
|
||||||
|
set => SetProperty(ref _type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParameterCategory _category = ParameterCategory.Temp;
|
||||||
|
public ParameterCategory Category
|
||||||
|
{
|
||||||
|
get => _category;
|
||||||
|
set => SetProperty(ref _category, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isGlobal;
|
||||||
|
public bool IsGlobal
|
||||||
|
{
|
||||||
|
get => _isGlobal;
|
||||||
|
set => SetProperty(ref _isGlobal, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? _value;
|
||||||
|
public object? Value
|
||||||
|
{
|
||||||
|
get => _value;
|
||||||
|
set => SetProperty(ref _value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? _lowerLimit;
|
||||||
|
public object? LowerLimit
|
||||||
|
{
|
||||||
|
get => _lowerLimit;
|
||||||
|
set => SetProperty(ref _lowerLimit, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? _upperLimit;
|
||||||
|
public object? UpperLimit
|
||||||
|
{
|
||||||
|
get => _upperLimit;
|
||||||
|
set => SetProperty(ref _upperLimit, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _result = true;
|
||||||
|
public bool Result
|
||||||
|
{
|
||||||
|
get => _result;
|
||||||
|
set => SetProperty(ref _result, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isUseVar;
|
||||||
|
public bool IsUseVar
|
||||||
|
{
|
||||||
|
get => _isUseVar;
|
||||||
|
set => SetProperty(ref _isUseVar, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isSave;
|
||||||
|
public bool IsSave
|
||||||
|
{
|
||||||
|
get => _isSave;
|
||||||
|
set => SetProperty(ref _isSave, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _variableName;
|
||||||
|
public string? VariableName
|
||||||
|
{
|
||||||
|
get => _variableName;
|
||||||
|
set => SetProperty(ref _variableName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid? _variableID;
|
||||||
|
public Guid? VariableID
|
||||||
|
{
|
||||||
|
get => _variableID;
|
||||||
|
set => SetProperty(ref _variableID, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ParameterCategory
|
||||||
|
{
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
Temp
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? GetActualValue(Dictionary<Guid, ParameterModel> paraList)
|
||||||
|
{
|
||||||
|
HashSet<Guid> visitedIds = new HashSet<Guid>();
|
||||||
|
ParameterModel current = this;
|
||||||
|
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
if (!current.IsUseVar)
|
||||||
|
{
|
||||||
|
return current.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visitedIds.Contains(current.ID))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
visitedIds.Add(current.ID);
|
||||||
|
|
||||||
|
if (current.VariableID == null)
|
||||||
|
{
|
||||||
|
if (Type != null && Value != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Convert.ChangeType(Value, Type);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterModel? next = paraList[(Guid)current.VariableID!];
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParameterModel? GetCurrentParameter(Dictionary<Guid, ParameterModel> paraList)
|
||||||
|
{
|
||||||
|
HashSet<Guid> visitedIds = new HashSet<Guid>();
|
||||||
|
ParameterModel current = this;
|
||||||
|
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
if (current.VariableID == null)
|
||||||
|
{
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (visitedIds.Contains(current.ID))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
visitedIds.Add(current.ID);
|
||||||
|
|
||||||
|
if (current.VariableID == null)
|
||||||
|
{
|
||||||
|
if (Type != null && Value != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterModel? next = paraList[(Guid)current.VariableID!];
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public (bool, string?) GetResult()
|
||||||
|
{
|
||||||
|
if (Type == typeof(string) && (!string.IsNullOrWhiteSpace(LowerLimit?.ToString()) || !string.IsNullOrWhiteSpace(UpperLimit?.ToString())))
|
||||||
|
{
|
||||||
|
return (true, $"参数 [ {Name}({Type}) ] 不可比较");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Value == null || (LowerLimit == null && UpperLimit == null))
|
||||||
|
{
|
||||||
|
return (true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(Value?.ToString()) || (string.IsNullOrWhiteSpace(LowerLimit?.ToString()) && string.IsNullOrWhiteSpace(UpperLimit?.ToString())))
|
||||||
|
{
|
||||||
|
return (true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
object? comparableValue = ConvertToComparable(Value);
|
||||||
|
object? comparableLower = LowerLimit != null ? ConvertToComparable(LowerLimit) : null;
|
||||||
|
object? comparableUpper = UpperLimit != null ? ConvertToComparable(UpperLimit) : null;
|
||||||
|
|
||||||
|
if (comparableValue == null)
|
||||||
|
{
|
||||||
|
return (true, $"参数 [ {Name}({Type}) ] 不可比较");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lowerValid = true;
|
||||||
|
bool upperValid = true;
|
||||||
|
|
||||||
|
if (comparableLower != null)
|
||||||
|
{
|
||||||
|
lowerValid = CompareValues(comparableValue, comparableLower) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comparableUpper != null)
|
||||||
|
{
|
||||||
|
upperValid = CompareValues(comparableValue, comparableUpper) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (lowerValid && upperValid, null);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return (true, $"参数 [ {Name}({Type}) ] 上下限比较失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object? ConvertToComparable(object value)
|
||||||
|
{
|
||||||
|
if (value is IConvertible convertible)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return convertible.ToDouble(null);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return convertible.ToDateTime(null);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CompareValues(object a, object b)
|
||||||
|
{
|
||||||
|
if (a is double aDouble && b is double bDouble)
|
||||||
|
{
|
||||||
|
return aDouble.CompareTo(bDouble);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a is DateTime aDate && b is DateTime bDate)
|
||||||
|
{
|
||||||
|
return aDate.CompareTo(bDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
50
BOB/Models/ProgramModel.cs
Normal file
50
BOB/Models/ProgramModel.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using Prism.Mvvm; // 引入 Prism 的 BindableBase
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace BOB.Models
|
||||||
|
{
|
||||||
|
public class ProgramModel : BindableBase
|
||||||
|
{
|
||||||
|
#region 构造函数
|
||||||
|
|
||||||
|
public ProgramModel()
|
||||||
|
{
|
||||||
|
// 可以进行初始化操作
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramModel(ProgramModel source)
|
||||||
|
{
|
||||||
|
ID = source.ID;
|
||||||
|
StepCollection = new ObservableCollection<StepModel>(source.StepCollection.Select(p => new StepModel(p)));
|
||||||
|
Devices = new ObservableCollection<DeviceModel>(source.Devices.Select(p => new DeviceModel(p)));
|
||||||
|
Parameters = new ObservableCollection<ParameterModel>(source.Parameters.Select(p => new ParameterModel(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public Guid ID { get; set; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
private ObservableCollection<StepModel> _stepCollection = new ObservableCollection<StepModel>();
|
||||||
|
public ObservableCollection<StepModel> StepCollection
|
||||||
|
{
|
||||||
|
get => _stepCollection;
|
||||||
|
set => SetProperty(ref _stepCollection, value); // 使用 SetProperty 来处理属性更改
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<ParameterModel> _parameters = new ObservableCollection<ParameterModel>();
|
||||||
|
public ObservableCollection<ParameterModel> Parameters
|
||||||
|
{
|
||||||
|
get => _parameters;
|
||||||
|
set => SetProperty(ref _parameters, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<DeviceModel> _devices = new ObservableCollection<DeviceModel>();
|
||||||
|
public ObservableCollection<DeviceModel> Devices
|
||||||
|
{
|
||||||
|
get => _devices;
|
||||||
|
set => SetProperty(ref _devices, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
177
BOB/Models/StepModel.cs
Normal file
177
BOB/Models/StepModel.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Prism.Mvvm; // 引入 Prism 的 BindableBase
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace BOB.Models
|
||||||
|
{
|
||||||
|
public class StepModel : BindableBase
|
||||||
|
{
|
||||||
|
#region 构造函数
|
||||||
|
|
||||||
|
public StepModel() { }
|
||||||
|
|
||||||
|
public StepModel(StepModel source)
|
||||||
|
{
|
||||||
|
if (source == null) return;
|
||||||
|
|
||||||
|
ID = source.ID;
|
||||||
|
Index = source.Index;
|
||||||
|
Name = source.Name;
|
||||||
|
StepType = source.StepType;
|
||||||
|
LoopCount = source.LoopCount;
|
||||||
|
LoopStartStepId = source.LoopStartStepId;
|
||||||
|
OKExpression = source.OKExpression;
|
||||||
|
OKGotoStepID = source.OKGotoStepID;
|
||||||
|
NGGotoStepID = source.NGGotoStepID;
|
||||||
|
Description = source.Description;
|
||||||
|
IsUsed = source.IsUsed;
|
||||||
|
|
||||||
|
if (source.Method != null)
|
||||||
|
{
|
||||||
|
Method = new MethodModel(source.Method);
|
||||||
|
}
|
||||||
|
if (source.SubProgram != null)
|
||||||
|
{
|
||||||
|
SubProgram = new ProgramModel(source.SubProgram);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private Guid _id = Guid.NewGuid();
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public Guid ID
|
||||||
|
{
|
||||||
|
get => _id;
|
||||||
|
set => SetProperty(ref _id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isUsed = true;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public bool IsUsed
|
||||||
|
{
|
||||||
|
get => _isUsed;
|
||||||
|
set => SetProperty(ref _isUsed, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _index;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
get => _index;
|
||||||
|
set => SetProperty(ref _index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _name;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public string? Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set => SetProperty(ref _name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _stepType;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public string? StepType
|
||||||
|
{
|
||||||
|
get => _stepType;
|
||||||
|
set => SetProperty(ref _stepType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodModel? _method;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public MethodModel? Method
|
||||||
|
{
|
||||||
|
get => _method;
|
||||||
|
set => SetProperty(ref _method, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProgramModel? _subProgram;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public ProgramModel? SubProgram
|
||||||
|
{
|
||||||
|
get => _subProgram;
|
||||||
|
set => SetProperty(ref _subProgram, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? _loopCount;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public int? LoopCount
|
||||||
|
{
|
||||||
|
get => _loopCount;
|
||||||
|
set => SetProperty(ref _loopCount, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? _currentLoopCount;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public int? CurrentLoopCount
|
||||||
|
{
|
||||||
|
get => _currentLoopCount;
|
||||||
|
set => SetProperty(ref _currentLoopCount, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid? _loopStartStepId;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public Guid? LoopStartStepId
|
||||||
|
{
|
||||||
|
get => _loopStartStepId;
|
||||||
|
set => SetProperty(ref _loopStartStepId, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _result = -1;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public int Result
|
||||||
|
{
|
||||||
|
get => _result;
|
||||||
|
set => SetProperty(ref _result, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? _runTime;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public int? RunTime
|
||||||
|
{
|
||||||
|
get => _runTime;
|
||||||
|
set => SetProperty(ref _runTime, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _okExpression;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public string? OKExpression
|
||||||
|
{
|
||||||
|
get => _okExpression;
|
||||||
|
set => SetProperty(ref _okExpression, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _gotoSettingString = "";
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public string GotoSettingString
|
||||||
|
{
|
||||||
|
get => _gotoSettingString;
|
||||||
|
set => SetProperty(ref _gotoSettingString, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid? _okGotoStepID;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public Guid? OKGotoStepID
|
||||||
|
{
|
||||||
|
get => _okGotoStepID;
|
||||||
|
set => SetProperty(ref _okGotoStepID, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid? _ngGotoStepID;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public Guid? NGGotoStepID
|
||||||
|
{
|
||||||
|
get => _ngGotoStepID;
|
||||||
|
set => SetProperty(ref _ngGotoStepID, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _description;
|
||||||
|
[JsonIgnore] // 添加 JsonIgnore
|
||||||
|
public string? Description
|
||||||
|
{
|
||||||
|
get => _description;
|
||||||
|
set => SetProperty(ref _description, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -67,7 +67,7 @@ namespace BOB
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LoggerHelper.Logger.Error($"配置加载失败: {ex.Message}");
|
LoggerHelper.ErrorWithNotify($"配置加载失败: {ex.Message}",ex.StackTrace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void SaveToFile()
|
public void SaveToFile()
|
||||||
@ -84,11 +84,11 @@ namespace BOB
|
|||||||
|
|
||||||
File.WriteAllText(configPath, json);
|
File.WriteAllText(configPath, json);
|
||||||
|
|
||||||
LoggerHelper.Logger.Info("系统配置已保存。");
|
LoggerHelper.InfoWithNotify("系统配置已保存。");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LoggerHelper.Logger.Error($"配置保存失败: {ex.Message}");
|
LoggerHelper.ErrorWithNotify($"配置保存失败: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Common.Attributes;
|
using Common.Attributes;
|
||||||
using Logger;
|
using Logger;
|
||||||
using Microsoft.IdentityModel.Logging;
|
using Microsoft.IdentityModel.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
@ -15,6 +16,7 @@ using System.Windows;
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using static BOB.Models.ParameterModel;
|
||||||
|
|
||||||
namespace BOB.ViewModels
|
namespace BOB.ViewModels
|
||||||
{
|
{
|
||||||
@ -28,34 +30,60 @@ namespace BOB.ViewModels
|
|||||||
get => _SearchText;
|
get => _SearchText;
|
||||||
set => SetProperty(ref _SearchText, value);
|
set => SetProperty(ref _SearchText, value);
|
||||||
}
|
}
|
||||||
public ObservableCollection<InstructionNode> _InstructionTree=new();
|
private ObservableCollection<InstructionNode> _instructionTree = new();
|
||||||
public ObservableCollection<InstructionNode> InstructionTree
|
public ObservableCollection<InstructionNode> InstructionTree
|
||||||
{
|
{
|
||||||
get => _InstructionTree;
|
get => _instructionTree;
|
||||||
set => SetProperty(ref _InstructionTree, value);
|
set => SetProperty(ref _instructionTree, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<Assembly> Assemblies { get; set; } = [];
|
private ProgramModel _program;
|
||||||
|
public ProgramModel Program
|
||||||
|
{
|
||||||
|
get => _program;
|
||||||
|
set => SetProperty(ref _program, value);
|
||||||
|
}
|
||||||
|
|
||||||
public ObservableCollection<SubProgramItem> SubPrograms { get; set; } = [];
|
private ObservableCollection<Assembly> _assemblies = new();
|
||||||
|
public ObservableCollection<Assembly> Assemblies
|
||||||
|
{
|
||||||
|
get => _assemblies;
|
||||||
|
set => SetProperty(ref _assemblies, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<SubProgramItem> _subPrograms = new();
|
||||||
|
public ObservableCollection<SubProgramItem> SubPrograms
|
||||||
|
{
|
||||||
|
get => _subPrograms;
|
||||||
|
set => SetProperty(ref _subPrograms, value);
|
||||||
|
}
|
||||||
|
|
||||||
private Dictionary<object, InstructionNode> _treeViewItemMap = [];
|
private Dictionary<object, InstructionNode> _treeNodeMap = new();
|
||||||
|
public Dictionary<object, InstructionNode> TreeNodeMap
|
||||||
private TreeViewItem _subProgramRootNode;
|
{
|
||||||
|
get => _treeNodeMap;
|
||||||
private readonly Dictionary<string, XmlDocument> _xmlDocumentCache = [];
|
set => SetProperty(ref _treeNodeMap, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, XmlDocument> _xmlDocumentCache = new();
|
||||||
|
public Dictionary<string, XmlDocument> XmlDocumentCache
|
||||||
|
{
|
||||||
|
get => _xmlDocumentCache;
|
||||||
|
set => SetProperty(ref _xmlDocumentCache, value);
|
||||||
|
}
|
||||||
|
GlobalVariables GlobalVariables { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
public ICommand LoadedCommand { get; set; }
|
public ICommand LoadedCommand { get; set; }
|
||||||
public ICommand SearchEnterCommand { get; set; }
|
public ICommand SearchEnterCommand { get; set; }
|
||||||
public ICommand TreeDoubleClickCommand { get; set; }
|
public ICommand TreeDoubleClickCommand { get; set; }
|
||||||
public ICommand ReloadCommand { get; set; }
|
public ICommand ReloadCommand { get; set; }
|
||||||
public CommandTreeViewModel()
|
public CommandTreeViewModel(GlobalVariables _GlobalVariables)
|
||||||
{
|
{
|
||||||
|
GlobalVariables= _GlobalVariables;
|
||||||
|
Program = GlobalVariables.Program;
|
||||||
LoadedCommand = new DelegateCommand(Loaded);
|
LoadedCommand = new DelegateCommand(Loaded);
|
||||||
SearchEnterCommand = new DelegateCommand(Search);
|
SearchEnterCommand = new DelegateCommand(Search);
|
||||||
TreeDoubleClickCommand = new DelegateCommand(TreeDoubleClick);
|
TreeDoubleClickCommand = new DelegateCommand<object>(TreeDoubleClick);
|
||||||
ReloadCommand = new DelegateCommand(Reload);
|
ReloadCommand = new DelegateCommand(Reload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,9 +95,31 @@ namespace BOB.ViewModels
|
|||||||
LoadSubPrograms();
|
LoadSubPrograms();
|
||||||
LoadInstructionsToTreeView();
|
LoadInstructionsToTreeView();
|
||||||
}
|
}
|
||||||
private void TreeDoubleClick()
|
private void TreeDoubleClick(object obj)
|
||||||
{
|
{
|
||||||
|
if(obj is InstructionNode Node)
|
||||||
|
{
|
||||||
|
if(Node.Children.Count == 0)
|
||||||
|
{
|
||||||
|
int index = GlobalVariables.SelectedStep?.Index >= 0 ? GlobalVariables.SelectedStep.Index : -1;
|
||||||
|
if (Node.Tag is MethodInfo method)
|
||||||
|
{
|
||||||
|
AddMethodToProgram(method, index);
|
||||||
|
}
|
||||||
|
else if(Node.Tag is string tag)
|
||||||
|
{
|
||||||
|
switch (tag)
|
||||||
|
{
|
||||||
|
case "循环开始":
|
||||||
|
AddLoopStartStep(index);
|
||||||
|
break;
|
||||||
|
case "循环结束":
|
||||||
|
AddLoopEndStep(index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private void Search()
|
private void Search()
|
||||||
{
|
{
|
||||||
@ -113,13 +163,13 @@ namespace BOB.ViewModels
|
|||||||
}
|
}
|
||||||
catch (Exception xmlEx)
|
catch (Exception xmlEx)
|
||||||
{
|
{
|
||||||
LoggerHelper.Logger.Warn($"加载XML注释失败: {Path.GetFileName(xmlPath)} - {xmlEx.Message}");
|
LoggerHelper.warnWithNotify($"加载XML注释失败: {Path.GetFileName(xmlPath)} - {xmlEx.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LoggerHelper.Logger.Warn($"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}");
|
LoggerHelper.warnWithNotify($"无法加载程序集 {Path.GetFileName(dllPath)}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +196,7 @@ namespace BOB.ViewModels
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LoggerHelper.Logger.Warn($"加载子程序错误: {filePath} - {ex.Message}");
|
LoggerHelper.warnWithNotify($"加载子程序错误: {filePath} - {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,6 +209,7 @@ namespace BOB.ViewModels
|
|||||||
var controlRootNode = new InstructionNode
|
var controlRootNode = new InstructionNode
|
||||||
{
|
{
|
||||||
Name = "系统指令",
|
Name = "系统指令",
|
||||||
|
Tag = "ControlRoot"
|
||||||
};
|
};
|
||||||
InstructionTree.Add(controlRootNode);
|
InstructionTree.Add(controlRootNode);
|
||||||
|
|
||||||
@ -166,12 +217,14 @@ namespace BOB.ViewModels
|
|||||||
controlRootNode.Children.Add(new InstructionNode
|
controlRootNode.Children.Add(new InstructionNode
|
||||||
{
|
{
|
||||||
Name = "循环开始",
|
Name = "循环开始",
|
||||||
|
Tag = "循环开始"
|
||||||
});
|
});
|
||||||
|
|
||||||
// 循环结束
|
// 循环结束
|
||||||
controlRootNode.Children.Add(new InstructionNode
|
controlRootNode.Children.Add(new InstructionNode
|
||||||
{
|
{
|
||||||
Name = "循环结束",
|
Name = "循环结束",
|
||||||
|
Tag = "循环结束"
|
||||||
});
|
});
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
@ -180,6 +233,7 @@ namespace BOB.ViewModels
|
|||||||
var subProgramRoot = new InstructionNode
|
var subProgramRoot = new InstructionNode
|
||||||
{
|
{
|
||||||
Name = "子程序",
|
Name = "子程序",
|
||||||
|
Tag = "SubProgramRoot"
|
||||||
};
|
};
|
||||||
InstructionTree.Add(subProgramRoot);
|
InstructionTree.Add(subProgramRoot);
|
||||||
|
|
||||||
@ -188,6 +242,7 @@ namespace BOB.ViewModels
|
|||||||
subProgramRoot.Children.Add(new InstructionNode
|
subProgramRoot.Children.Add(new InstructionNode
|
||||||
{
|
{
|
||||||
Name = subProgram.Name,
|
Name = subProgram.Name,
|
||||||
|
Tag = subProgram,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +276,7 @@ namespace BOB.ViewModels
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LoggerHelper.Logger.Error($"加载类型错误: {assembly.FullName} - {ex.Message}");
|
LoggerHelper.ErrorWithNotify($"加载类型错误: {assembly.FullName} - {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validTypes.Count > 0)
|
if (validTypes.Count > 0)
|
||||||
@ -229,19 +284,20 @@ namespace BOB.ViewModels
|
|||||||
var assemblyNode = new InstructionNode
|
var assemblyNode = new InstructionNode
|
||||||
{
|
{
|
||||||
Name = assembly.GetName().Name,
|
Name = assembly.GetName().Name,
|
||||||
|
Tag = assembly
|
||||||
};
|
};
|
||||||
InstructionTree.Add(assemblyNode);
|
InstructionTree.Add(assemblyNode);
|
||||||
_treeViewItemMap[assembly] = assemblyNode;
|
TreeNodeMap[assembly] = assemblyNode;
|
||||||
|
|
||||||
foreach (var type in validTypes)
|
foreach (var type in validTypes)
|
||||||
{
|
{
|
||||||
var typeNode = new InstructionNode
|
var typeNode = new InstructionNode
|
||||||
{
|
{
|
||||||
Name = type.Name,
|
Name = type.Name,
|
||||||
|
Tag = type,
|
||||||
};
|
};
|
||||||
assemblyNode.Children.Add(typeNode);
|
assemblyNode.Children.Add(typeNode);
|
||||||
_treeViewItemMap[type] = typeNode;
|
TreeNodeMap[type] = typeNode;
|
||||||
|
|
||||||
var allMethods = new HashSet<MethodInfo>();
|
var allMethods = new HashSet<MethodInfo>();
|
||||||
GetPublicMethods(type, allMethods);
|
GetPublicMethods(type, allMethods);
|
||||||
@ -263,11 +319,11 @@ namespace BOB.ViewModels
|
|||||||
var methodNode = new InstructionNode
|
var methodNode = new InstructionNode
|
||||||
{
|
{
|
||||||
Name = $"{method.Name}({paramText})",
|
Name = $"{method.Name}({paramText})",
|
||||||
|
Tag = method,
|
||||||
};
|
};
|
||||||
|
|
||||||
typeNode.Children.Add(methodNode);
|
typeNode.Children.Add(methodNode);
|
||||||
_treeViewItemMap[method] = methodNode;
|
TreeNodeMap[method] = methodNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,6 +331,7 @@ namespace BOB.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
#region 辅助方法
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 递归获取类型的所有公共方法(包括继承的方法),但跳过被重写的方法
|
/// 递归获取类型的所有公共方法(包括继承的方法),但跳过被重写的方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -328,6 +385,175 @@ namespace BOB.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
#region 指令添加
|
||||||
|
|
||||||
|
private void AddMethodToProgram(MethodInfo method, int insertIndex = -1)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var newStep = new StepModel
|
||||||
|
{
|
||||||
|
Name = method.Name,
|
||||||
|
StepType = "方法",
|
||||||
|
Method = new MethodModel
|
||||||
|
{
|
||||||
|
FullName = method.DeclaringType?.FullName,
|
||||||
|
Name = method.Name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加输入参数
|
||||||
|
foreach (var param in method.GetParameters())
|
||||||
|
{
|
||||||
|
newStep.Method.Parameters.Add(new ParameterModel
|
||||||
|
{
|
||||||
|
Name = param.Name!,
|
||||||
|
Type = param.ParameterType,
|
||||||
|
Category = ParameterCategory.Input
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加输出参数(返回值)
|
||||||
|
Type returnType = method.ReturnType;
|
||||||
|
if (returnType == typeof(Task))
|
||||||
|
{
|
||||||
|
// 不添加输出参数(无返回值)
|
||||||
|
}
|
||||||
|
else if (returnType.IsGenericType &&
|
||||||
|
returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||||
|
{
|
||||||
|
// 提取实际返回类型(如 Task<bool> -> bool)
|
||||||
|
Type actualType = returnType.GetGenericArguments()[0];
|
||||||
|
newStep.Method.Parameters.Add(new ParameterModel
|
||||||
|
{
|
||||||
|
Name = "Result",
|
||||||
|
Type = actualType, // 使用实际类型
|
||||||
|
Category = ParameterCategory.Output
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (returnType != typeof(void))
|
||||||
|
{
|
||||||
|
// 同步方法正常添加
|
||||||
|
newStep.Method.Parameters.Add(new ParameterModel
|
||||||
|
{
|
||||||
|
Name = "Result",
|
||||||
|
Type = returnType,
|
||||||
|
Category = ParameterCategory.Output
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到程序
|
||||||
|
if (insertIndex >= 0 && insertIndex <= Program.StepCollection.Count)
|
||||||
|
{
|
||||||
|
Program.StepCollection.Insert(insertIndex, newStep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Program.StepCollection.Add(newStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LoggerHelper.ErrorWithNotify($"添加方法失败: {method.Name} - {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//private void AddSubProgramToProgram(SubProgramItem subProgram, int insertIndex = -1)
|
||||||
|
//{
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// var newStep = new StepModel
|
||||||
|
// {
|
||||||
|
// Name = subProgram.Name,
|
||||||
|
// StepType = "子程序"
|
||||||
|
// };
|
||||||
|
// var jsonstr = File.ReadAllText($"{subProgram.FilePath}");
|
||||||
|
// var tmp = JsonConvert.DeserializeObject<ProgramModel>(jsonstr);
|
||||||
|
// if (tmp != null)
|
||||||
|
// {
|
||||||
|
// if (tmp.Devices != null && tmp.Devices.Count > 0)
|
||||||
|
// {
|
||||||
|
// foreach (var device in tmp.Devices)
|
||||||
|
// {
|
||||||
|
// _ = DeviceConnect.InitAndConnectDevice(tmp, device);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// newStep.SubProgram = tmp;
|
||||||
|
// }
|
||||||
|
// 添加到程序
|
||||||
|
// if (insertIndex >= 0 && insertIndex <= Program.StepCollection.Count)
|
||||||
|
// {
|
||||||
|
// Program.StepCollection.Insert(insertIndex, newStep);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// Program.StepCollection.Add(newStep);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ReOrderProgramList();
|
||||||
|
// }
|
||||||
|
// catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// Log.Error($"添加子程序失败: {subProgram.Name} - {ex.Message}");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
private void AddLoopStartStep(int insertIndex = -1)
|
||||||
|
{
|
||||||
|
var newStep = new StepModel
|
||||||
|
{
|
||||||
|
Name = "循环开始",
|
||||||
|
StepType = "循环开始",
|
||||||
|
LoopCount = 1,
|
||||||
|
Method = new() { Parameters = [new() { Name = "循环次数", Type = typeof(int), Category = ParameterCategory.Input }] }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (insertIndex >= 0)
|
||||||
|
{
|
||||||
|
Program.StepCollection.Insert(insertIndex, newStep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Program.StepCollection.Add(newStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddLoopEndStep(int insertIndex = -1)
|
||||||
|
{
|
||||||
|
// 查找最近的未匹配循环开始
|
||||||
|
StepModel? lastUnmatchedLoopStart = null;
|
||||||
|
for (int i = Program.StepCollection.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (Program.StepCollection[i].StepType == "循环开始")
|
||||||
|
{
|
||||||
|
bool isMatched = Program.StepCollection.Any(s => s.StepType == "循环结束" && s.LoopStartStepId == Program.StepCollection[i].ID);
|
||||||
|
|
||||||
|
if (!isMatched)
|
||||||
|
{
|
||||||
|
lastUnmatchedLoopStart = Program.StepCollection[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var newStep = new StepModel
|
||||||
|
{
|
||||||
|
Name = "循环结束",
|
||||||
|
StepType = "循环结束",
|
||||||
|
LoopStartStepId = lastUnmatchedLoopStart?.ID
|
||||||
|
};
|
||||||
|
|
||||||
|
if (insertIndex >= 0)
|
||||||
|
{
|
||||||
|
Program.StepCollection.Insert(insertIndex, newStep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Program.StepCollection.Add(newStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,37 @@
|
|||||||
using System;
|
using Logger;
|
||||||
using System.Collections.Generic;
|
using Prism.Mvvm;
|
||||||
using System.Linq;
|
using System.Collections.ObjectModel;
|
||||||
using System.Text;
|
using System.Windows.Media;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace BOB.ViewModels
|
namespace BOB.ViewModels
|
||||||
{
|
{
|
||||||
public class LogAreaViewModel
|
public class LogAreaViewModel : BindableBase
|
||||||
{
|
{
|
||||||
|
// 日志集合
|
||||||
|
private ObservableCollection<LogItem> _logs = new();
|
||||||
|
public ObservableCollection<LogItem> Logs
|
||||||
|
{
|
||||||
|
get => _logs;
|
||||||
|
set => SetProperty(ref _logs, value);
|
||||||
|
}
|
||||||
|
|
||||||
public LogAreaViewModel()
|
public LogAreaViewModel()
|
||||||
{
|
{
|
||||||
|
LoggerHelper.LogAdded += OnLogAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方便外部添加日志
|
||||||
|
public void OnLogAdded(string message, string color)
|
||||||
|
{
|
||||||
|
var brush = (Brush)new BrushConverter().ConvertFromString(color);
|
||||||
|
Logs.Add(new LogItem { Message = message, Color = brush });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 日志条目类
|
||||||
|
public class LogItem
|
||||||
|
{
|
||||||
|
public string Message { get; set; }
|
||||||
|
public Brush Color { get; set; } = Brushes.Black;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,138 @@
|
|||||||
using System;
|
using BOB.Models;
|
||||||
|
using Common.PubEvent;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Xml;
|
||||||
|
|
||||||
namespace BOB.ViewModels
|
namespace BOB.ViewModels
|
||||||
{
|
{
|
||||||
public class StepsManagerViewModel
|
public class StepsManagerViewModel:BindableBase
|
||||||
{
|
{
|
||||||
public StepsManagerViewModel()
|
#region 属性
|
||||||
|
private string _Title;
|
||||||
|
public string Title
|
||||||
{
|
{
|
||||||
|
get => _Title;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
SetProperty(ref _Title, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
private StepModel _SelectedStep;
|
||||||
|
public StepModel SelectedStep
|
||||||
|
{
|
||||||
|
get => _SelectedStep;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _SelectedStep, value))
|
||||||
|
{
|
||||||
|
GlobalVariables.SelectedStep = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProgramModel _program = new();
|
||||||
|
public ProgramModel Program
|
||||||
|
{
|
||||||
|
get => _program;
|
||||||
|
set => SetProperty(ref _program, value);
|
||||||
|
}
|
||||||
|
private bool _IsAdmin = new();
|
||||||
|
public bool IsAdmin
|
||||||
|
{
|
||||||
|
get => _IsAdmin;
|
||||||
|
set => SetProperty(ref _IsAdmin, value);
|
||||||
|
}
|
||||||
|
GlobalVariables GlobalVariables { get; set; }
|
||||||
|
private List<StepModel> tmpCopyList = new List<StepModel>();
|
||||||
|
private IEventAggregator eventAggregator;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
public ICommand EditStepCommand { get;set; }
|
||||||
|
public ICommand CopyStepCommand { get;set; }
|
||||||
|
public ICommand PasteStepCommand { get;set; }
|
||||||
|
public ICommand DeleteStepCommand { get;set; }
|
||||||
|
public StepsManagerViewModel(GlobalVariables _GlobalVariables,IEventAggregator eventAggregator)
|
||||||
|
{
|
||||||
|
eventAggregator = eventAggregator;
|
||||||
|
GlobalVariables = _GlobalVariables;
|
||||||
|
Program = GlobalVariables.Program;
|
||||||
|
IsAdmin = GlobalVariables.IsAdmin;
|
||||||
|
EditStepCommand = new DelegateCommand(EditStep);
|
||||||
|
CopyStepCommand = new DelegateCommand(CopyStep);
|
||||||
|
PasteStepCommand = new DelegateCommand(PasteStep);
|
||||||
|
DeleteStepCommand = new DelegateCommand(DeleteStep);
|
||||||
|
Program.StepCollection.CollectionChanged += StepCollection_CollectionChanged;
|
||||||
|
}
|
||||||
|
#region 委托命令
|
||||||
|
private void EditStep()
|
||||||
|
{
|
||||||
|
if (IsAdmin && SelectedStep != null)
|
||||||
|
{
|
||||||
|
var stepToEdit = SelectedStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void CopyStep()
|
||||||
|
{
|
||||||
|
if (IsAdmin && SelectedStep != null)
|
||||||
|
{
|
||||||
|
tmpCopyList.Clear();
|
||||||
|
tmpCopyList.Add(SelectedStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void PasteStep()
|
||||||
|
{
|
||||||
|
if (IsAdmin && tmpCopyList.Any())
|
||||||
|
{
|
||||||
|
int insertIndex = Program.StepCollection.IndexOf(SelectedStep) + 1;
|
||||||
|
foreach (var item in tmpCopyList)
|
||||||
|
{
|
||||||
|
Program.StepCollection.Insert(insertIndex, new StepModel(item) { ID = Guid.NewGuid() });
|
||||||
|
insertIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void DeleteStep()
|
||||||
|
{
|
||||||
|
if (IsAdmin && SelectedStep != null)
|
||||||
|
{
|
||||||
|
var tmpList = new List<StepModel> { SelectedStep };
|
||||||
|
foreach (var item in tmpList)
|
||||||
|
{
|
||||||
|
Program.StepCollection.Remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 辅助方法
|
||||||
|
private void StepCollection_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
// Add/Move/Remove 都会触发,这里判断具体情形
|
||||||
|
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add ||
|
||||||
|
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Move||
|
||||||
|
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
|
||||||
|
{
|
||||||
|
// 如果需要等 UI 更新完再处理,可也用 Dispatcher 延迟一小段时间
|
||||||
|
Application.Current?.Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
// after drop: 重新编号或其他处理
|
||||||
|
for (int i = 0; i < Program.StepCollection.Count; i++)
|
||||||
|
Program.StepCollection[i].Index = i + 1;
|
||||||
|
|
||||||
|
// 发布 Prism 事件(如果需要)
|
||||||
|
// _eventAggregator.GetEvent<StepMovedEvent>().Publish(...);
|
||||||
|
}), System.Windows.Threading.DispatcherPriority.Background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,7 +55,8 @@
|
|||||||
<!-- 双击 -->
|
<!-- 双击 -->
|
||||||
<i:Interaction.Triggers>
|
<i:Interaction.Triggers>
|
||||||
<i:EventTrigger EventName="MouseDoubleClick">
|
<i:EventTrigger EventName="MouseDoubleClick">
|
||||||
<prism:InvokeCommandAction Command="{Binding TreeDoubleClickCommand}" />
|
<prism:InvokeCommandAction Command="{Binding TreeDoubleClickCommand}"
|
||||||
|
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=TreeView}}" />
|
||||||
</i:EventTrigger>
|
</i:EventTrigger>
|
||||||
</i:Interaction.Triggers>
|
</i:Interaction.Triggers>
|
||||||
|
|
||||||
|
|||||||
@ -12,9 +12,8 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<GroupBox Header="系统运行日志">
|
<GroupBox Header="系统运行日志">
|
||||||
<ListView FontWeight="DemiBold"
|
<ListView FontWeight="DemiBold"
|
||||||
ItemsSource="{Binding LogEntries}"
|
ItemsSource="{Binding Logs}"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
|
||||||
SelectedItem="{Binding SelectedLog, Mode=TwoWay}">
|
|
||||||
|
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
|||||||
@ -15,12 +15,15 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<GroupBox Header="{Binding Title}">
|
<GroupBox Header="{Binding Title}">
|
||||||
<DataGrid x:Name="ProgramDataGrid"
|
<DataGrid x:Name="ProgramDataGrid"
|
||||||
|
dd:DragDrop.IsDragSource="True"
|
||||||
|
dd:DragDrop.IsDropTarget="True"
|
||||||
|
dd:DragDrop.UseDefaultDragAdorner="True"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
CanUserAddRows="False"
|
CanUserAddRows="False"
|
||||||
CanUserSortColumns="False"
|
CanUserSortColumns="False"
|
||||||
ItemsSource="{Binding Program.StepCollection}"
|
ItemsSource="{Binding Program.StepCollection}"
|
||||||
SelectedItem="{Binding SelectedStep, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedStep, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
|
||||||
SelectionMode="Extended"
|
SelectionMode="Extended"
|
||||||
SelectionUnit="FullRow">
|
SelectionUnit="FullRow">
|
||||||
|
|
||||||
@ -97,25 +100,25 @@
|
|||||||
<DataGrid.ContextMenu>
|
<DataGrid.ContextMenu>
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<MenuItem Header="编辑"
|
<MenuItem Header="编辑"
|
||||||
Command="{Binding DataContext.EditStepCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" />
|
Command="{Binding EditStepCommand}"/>
|
||||||
<MenuItem Header="复制"
|
<MenuItem Header="复制"
|
||||||
Command="{Binding DataContext.CopyStepCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" />
|
Command="{Binding CopyStepCommand}"/>
|
||||||
<MenuItem Header="粘贴"
|
<MenuItem Header="粘贴"
|
||||||
Command="{Binding DataContext.PasteStepCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" />
|
Command="{Binding PasteStepCommand}"/>
|
||||||
<MenuItem Header="删除"
|
<MenuItem Header="删除"
|
||||||
Foreground="Red"
|
Foreground="Red"
|
||||||
Command="{Binding DataContext.DeleteStepCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" />
|
Command="{Binding DeleteStepCommand}" />
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</DataGrid.ContextMenu>
|
</DataGrid.ContextMenu>
|
||||||
|
|
||||||
<!-- 键盘 删除键绑定 Delete 命令 -->
|
<!-- 键盘 删除键绑定 Delete 命令 -->
|
||||||
<i:Interaction.Triggers>
|
<!--<i:Interaction.Triggers>
|
||||||
<i:EventTrigger EventName="PreviewKeyDown">
|
<i:EventTrigger EventName="PreviewKeyDown">
|
||||||
<i:InvokeCommandAction Command="{Binding DeleteStepCommand}"
|
<i:InvokeCommandAction Command="{Binding DeleteStepCommand}"
|
||||||
CommandParameter="{Binding SelectedStep}"
|
CommandParameter="{Binding SelectedStep}"
|
||||||
PassEventArgsToCommand="True" />
|
PassEventArgsToCommand="True" />
|
||||||
</i:EventTrigger>
|
</i:EventTrigger>
|
||||||
</i:Interaction.Triggers>
|
</i:Interaction.Triggers>-->
|
||||||
|
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using Common.PubEvent;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|||||||
12
Common/PubEvent/AfterDragEvent.cs
Normal file
12
Common/PubEvent/AfterDragEvent.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Common.PubEvent
|
||||||
|
{
|
||||||
|
public class AfterDragEvent:PubSubEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@ -12,7 +13,48 @@ namespace Logger
|
|||||||
{
|
{
|
||||||
public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger");
|
public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger");
|
||||||
public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger");
|
public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger");
|
||||||
|
// 日志事件,UI可以订阅
|
||||||
|
public static event Action<string, string>? LogAdded;
|
||||||
|
|
||||||
|
public static void InfoWithNotify(string message)
|
||||||
|
{
|
||||||
|
Logger.Info(message); // 写入 NLog
|
||||||
|
NotifyUI(message, "lightblue"); // 触发UI显示
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SuccessWithNotify(string message)
|
||||||
|
{
|
||||||
|
Logger.Info(message);
|
||||||
|
NotifyUI(message, "lightgreen");
|
||||||
|
}
|
||||||
|
public static void warnWithNotify(string message, string stackTrace = null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stackTrace))
|
||||||
|
{
|
||||||
|
string location = GetProjectStackLine(stackTrace);
|
||||||
|
message = $"{message} ({location})";
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Warn(message);
|
||||||
|
NotifyUI(message, "orange");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ErrorWithNotify(string message, string stackTrace = null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stackTrace))
|
||||||
|
{
|
||||||
|
string location = GetProjectStackLine(stackTrace);
|
||||||
|
message = $"{message} ({location})";
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Error(message);
|
||||||
|
NotifyUI(message, "red");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void NotifyUI(string message, string color)
|
||||||
|
{
|
||||||
|
LogAdded?.Invoke(message,color);
|
||||||
|
}
|
||||||
// 解析堆栈,找到项目文件路径和行号
|
// 解析堆栈,找到项目文件路径和行号
|
||||||
public static string GetProjectStackLine(string stackTrace)
|
public static string GetProjectStackLine(string stackTrace)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user