逻辑规则的初步增加工能:

1)规则的界面的增删改查
2)规则服务的初步测试,目前测试是OK的
This commit is contained in:
2025-04-21 17:10:11 +08:00
parent 5f85aed486
commit a7fc676b82
24 changed files with 1583 additions and 58 deletions

9
.windsurfrules Normal file
View File

@@ -0,0 +1,9 @@
我是一个 CSharp 软件开发者,我在开发一个压缩机耐久性能台的软件系统,主要功能如下:
# 读取PLC的数据PLC是西门子的S200
# 通过DBC配置CAN通过Ldf配置LIN通信
# 通过配置程序步骤能逐步的下载步骤信息到PLC中逐步的执行程序步骤程序中有SV(设置值),下载的速度数据是下载到压缩机中
# 获取所有的数据包括PLC的数据和压缩机的数据然后能绘制曲线
# 能对获取的数据进行数据记录保存到文件中记录的值是SV数据
# 能记录日志信息
# 用中文回复我
# 请延续我的编码框架

View File

@@ -10,7 +10,7 @@ namespace CapMachine.Model.CANLIN
/// <summary>
/// CAN和LIN的配置数据内容
/// </summary>
[Table(Name = "CanLinConfigContent")]
[Table(Name = "CanLinRWConfig")]
public class CanLinRWConfig
{
/// <summary>
@@ -61,5 +61,13 @@ namespace CapMachine.Model.CANLIN
public long CanLinConfigProId { get; set; }
public CanLinConfigPro? CanLinConfigPro { get; set; }
public long LogicRuleId { get; set; }
/// <summary>
/// CanLinConfig的逻辑转换规则
/// 比如速度下发的数据SV是4000但是下发到CAN的值是40可能是其他的逻辑转换规则这里就是保存其中的逻辑规则
/// </summary>
public LogicRule? LogicRule { get; set; }
}
}

View File

@@ -6,7 +6,7 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FreeSql" Version="3.5.102" />
<PackageReference Include="FreeSql" Version="3.5.202" />
</ItemGroup>
<ItemGroup>
<Folder Include="ProExecuteModel\" />

View File

@@ -0,0 +1,58 @@
using CapMachine.Model.CANLIN;
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CapMachine.Model
{
/// <summary>
/// 逻辑转换规则模型
/// </summary>
[Table(Name = "LogicRule")]
public class LogicRule
{
/// <summary>
/// 主键ID
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 规则名称
/// </summary>
[Column(Name = "Name", StringLength = 50)]
public string? Name { get; set; }
/// <summary>
/// 规则描述
/// </summary>
[Column(Name = "Description", StringLength = 200)]
public string? Description { get; set; }
/// <summary>
/// 规则表达式
/// </summary>
[Column(Name = "Expression", StringLength = 500)]
public string? Expression { get; set; }
/// <summary>
/// 适用的参数类型(如:转速、功率等)
/// </summary>
[Column(Name = "ParameterType", StringLength = 50)]
public string? ParameterType { get; set; }
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
/// <summary>
/// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
/// </summary>
public List<CanLinRWConfig>? CanLinRWConfigs { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
using AutoMapper;
using AutoMapper;
using CapMachine.Core;
using CapMachine.Core.IService;
using CapMachine.Wpf.MapperProfile;
@@ -94,7 +94,7 @@ namespace CapMachine.Wpf
try
{
var MachineCode = SoftAuthorizeHelper.GetMachineCode();
SoftAuthorizeHelper.WriteMachineCodeToFile(MachineCode,"");
SoftAuthorizeHelper.WriteMachineCodeToFile(MachineCode, "");
var PublicKey = SoftAuthorizeHelper.GetPublicKeyDataByFilePath("");
var Lience = SoftAuthorizeHelper.GetLienceDataByFilePath("");
var IsOK = SoftAuthorizeHelper.CheckLience(MachineCode, PublicKey, Lience);
@@ -129,6 +129,7 @@ namespace CapMachine.Wpf
//containerRegistry.RegisterSingleton<IApplicationContext, ApplicationContext>();
containerRegistry.RegisterSingleton<LogicRuleService>();
containerRegistry.RegisterSingleton<ConfigService>();
containerRegistry.RegisterSingleton<AlarmService>();
////注册设备服务
@@ -143,6 +144,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterSingleton<ComActionService>();
containerRegistry.RegisterSingleton<ProRuntimeService>();
string strsqllite = System.AppDomain.CurrentDomain.BaseDirectory + @"Db\CapMachine.db";
@@ -201,8 +203,10 @@ namespace CapMachine.Wpf
containerRegistry.RegisterDialog<DialogPIDConfigView, DialogPIDConfigViewModel>();
containerRegistry.RegisterDialog<DialogLimitConfigView, DialogLimitConfigViewModel>();
containerRegistry.RegisterDialog<DialogSuperHeatCoolConfigView, DialogSuperHeatCoolConfigViewModel>();
containerRegistry.RegisterDialog<DialogLogicRuleView, DialogLogicRuleViewModel>();
containerRegistry.RegisterDialog<SplashScreenView, SplashScreenViewModel>();
//注册AutoMapper

View File

@@ -664,12 +664,13 @@
<PackageReference Include="CsvHelper" Version="33.0.1" />
<PackageReference Include="DeepCloner" Version="0.10.4" />
<PackageReference Include="DotNetProjects.SVGImage" Version="5.2.2" />
<PackageReference Include="DynamicExpresso.Core" Version="2.19.0" />
<PackageReference Include="ExcelMapper" Version="5.2.592" />
<PackageReference Include="FreeSql" Version="3.5.102" />
<PackageReference Include="FreeSql.Extensions.ZeroEntity" Version="3.5.102" />
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.5.102" />
<PackageReference Include="FreeSql.Provider.SqlServer" Version="3.5.102" />
<PackageReference Include="FreeSql.Repository" Version="3.5.102" />
<PackageReference Include="FreeSql" Version="3.5.202" />
<PackageReference Include="FreeSql.Extensions.ZeroEntity" Version="3.5.202" />
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.5.202" />
<PackageReference Include="FreeSql.Provider.SqlServer" Version="3.5.202" />
<PackageReference Include="FreeSql.Repository" Version="3.5.202" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="2.0.1" />
<PackageReference Include="HslCommunication" Version="12.1.2" />
<PackageReference Include="Masuit.Tools.Core" Version="2024.5.8" />

View File

@@ -1,4 +1,5 @@
using CapMachine.Model.CANLIN;
using CapMachine.Model;
using CapMachine.Model.CANLIN;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
@@ -70,7 +71,12 @@ namespace CapMachine.Wpf.Dtos
set { _DefautValue = value; RaisePropertyChanged(); }
}
public long LogicRuleId { get; set; }
/// <summary>
/// CanLinConfig的逻辑转换规则
/// 比如速度下发的数据SV是4000但是下发到CAN的值是40可能是其他的逻辑转换规则这里就是保存其中的逻辑规则
/// </summary>
public LogicRuleDto? LogicRuleDto { get; set; }
}
}

View File

@@ -0,0 +1,75 @@
using CapMachine.Model.CANLIN;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CapMachine.Wpf.Dtos
{
/// <summary>
/// 逻辑转换规则模型
/// </summary>
public class LogicRuleDto : BindableBase
{
/// <summary>
/// 主键ID
/// </summary>
public int Id { get; set; }
private string _name = string.Empty;
/// <summary>
/// 规则名称
/// </summary>
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
private string _description = string.Empty;
/// <summary>
/// 规则描述
/// </summary>
public string Description
{
get { return _description; }
set { SetProperty(ref _description, value); }
}
private string _expression = string.Empty;
/// <summary>
/// 规则表达式
/// </summary>
public string Expression
{
get { return _expression; }
set { _expression = value; RaisePropertyChanged(); }
}
private string _parameterType = string.Empty;
/// <summary>
/// 适用的参数类型(如:转速、功率等)
/// </summary>
public string ParameterType
{
get { return _parameterType; }
set { SetProperty(ref _parameterType, value); }
}
private DateTime _CreateTime;
/// <summary>
/// 适用的参数类型(如:转速、功率等)
/// </summary>
public DateTime CreateTime
{
get { return _CreateTime; }
set { _CreateTime = value; RaisePropertyChanged(); }
}
}
}

View File

@@ -14,7 +14,9 @@ namespace CapMachine.Wpf.MapperProfile
{
public CanLinRWConfigProfile()
{
CreateMap<CanLinRWConfig, CanLinRWConfigDto>().ReverseMap();
CreateMap<CanLinRWConfig, CanLinRWConfigDto>()
.ForMember(dest => dest.LogicRuleDto, opt => opt.MapFrom(src => src.LogicRule))
.ReverseMap();
}
}
}

View File

@@ -0,0 +1,20 @@
using AutoMapper;
using CapMachine.Model;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CapMachine.Wpf.MapperProfile
{
public class LogicRuleProfile : Profile
{
public LogicRuleProfile()
{
CreateMap<LogicRuleDto, LogicRule>().ReverseMap();
}
}
}

View File

@@ -1,4 +1,4 @@
using CapMachine.Model.CANLIN;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
using ImTools;
using Prism.Ioc;
@@ -195,7 +195,7 @@ namespace CapMachine.Wpf.Services
{
if (ToomossCanDrive.OpenState)
{
if (ToomossCanDrive.IsCycleSend == false)
if (ToomossCanDrive.IsCycleSend == false)//要防止多次启动导致的问题,来回转换
{
if (CmdData.Count > 0)
{

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace CapMachine.Wpf.Services
{
@@ -22,6 +23,7 @@ namespace CapMachine.Wpf.Services
public DataRecordService DataRecordService { get; }
public SysRunService SysRunServer { get; }
public PPCService PPCService { get; }
public ProRuntimeService ProRuntimeService { get; }
public CanDriveService CanDriveService { get; }
public LinDriveService LinDriveService { get; }
public MachineRtDataService MachineRtDataService { get; }
@@ -29,7 +31,7 @@ namespace CapMachine.Wpf.Services
public ComActionService(ConfigService configService, IEventAggregator eventAggregator,
DataRecordService dataRecordService, SysRunService sysRunService, PPCService pPCService, CanDriveService canDriveService, LinDriveService linDriveService,
DataRecordService dataRecordService, SysRunService sysRunService, PPCService pPCService, ProRuntimeService proRuntimeService, CanDriveService canDriveService, LinDriveService linDriveService,
MachineRtDataService machineRtDataService, IDialogService dialogService)
{
ConfigService = configService;
@@ -38,6 +40,7 @@ namespace CapMachine.Wpf.Services
DataRecordService = dataRecordService;
SysRunServer = sysRunService;
PPCService = pPCService;
ProRuntimeService = proRuntimeService;
CanDriveService = canDriveService;
LinDriveService = linDriveService;
MachineRtDataService = machineRtDataService;
@@ -61,6 +64,14 @@ namespace CapMachine.Wpf.Services
case "过热度/过冷度配置":
ShowSuperHeatCool(msg.Par);
break;
case "规则转换":
if (ProRuntimeService.MachineRunState1.IsRunState)
{
MessageBox.Show("请不要在运行时编辑规则转换,此时更改可能导致运行出错,请停止后再编辑");
return;
}
ShowLogicRule(msg.Par);
break;
default:
break;
}
@@ -93,6 +104,29 @@ namespace CapMachine.Wpf.Services
}
/// <summary>
/// 过热度和过冷度配置弹窗
/// </summary>
private void ShowLogicRule(object par)
{
//弹窗
DialogService.ShowDialog("DialogLogicRuleView", new DialogParameters() { { "Name", par } }, (par) =>
{
if (par.Result == ButtonResult.OK)
{
//保存配置信息
//PPCService.SaveSuperHeatCoolConfig();
}
else if (par.Result == ButtonResult.Cancel)
{
//取消
}
});
}

View File

@@ -1,4 +1,4 @@
using CapMachine.Model.CANLIN;
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.LinDrive;
using ImTools;
using Prism.Ioc;

View File

@@ -0,0 +1,670 @@
using AutoMapper;
using CapMachine.Core;
using CapMachine.Model;
using CapMachine.Wpf.Dtos;
using DynamicExpresso;
using FreeSql;
using FreeSql.DataAnnotations;
using Prism.Mvvm;
using Syncfusion.Windows.Shared;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace CapMachine.Wpf.Services
{
/// <summary>
/// 逻辑服务 - 用于处理数据逻辑转换
/// </summary>
public class LogicRuleService : BindableBase
{
private readonly ILogService LogService;
private readonly IFreeSql FreeSql;
/// <summary>
/// 逻辑转换规则集合
/// </summary>
public ObservableCollection<LogicRuleDto> LogicRuleDtos { get; private set; }
/// <summary>
/// DynamicExpresso解释器
/// </summary>
private Interpreter CurInterpreter { get; set; }
public IMapper Mapper { get; }
/// <summary>
/// 规则表达式缓存(高性能访问)
/// Key: 规则名称, Value: 已编译的Lambda表达式
///private readonly ConcurrentDictionary<string, Func<double, double>> _expressionCache;
/// </summary>
private readonly ConcurrentDictionary<string, Lambda> _expressionCache;
///// <summary>
///// 创建包含指定值的参数数组
///// </summary>
//private Parameter[] CreateParameters(double value)
//{
// return new Parameter[]
// {
// new Parameter("value", typeof(double), value)
// };
//}
/// <summary>
/// 创建包含指定值的参数
/// </summary>
private Parameter CreateParameters(double value)
{
return new Parameter("value", typeof(double),value);
}
/// <summary>
/// 实例化函数
/// </summary>
public LogicRuleService(ILogService logService, IFreeSql freeSql, IMapper mapper)
{
LogService = logService;
FreeSql = freeSql;
Mapper = mapper;
// 初始化集合
LogicRuleDtos = new ObservableCollection<LogicRuleDto>();
_expressionCache = new ConcurrentDictionary<string, Lambda>();
// 初始化DynamicExpresso解释器
CurInterpreter = new Interpreter();
//.Reference(typeof(Math)) // 引用Math类
// //.SetVariable("Math", typeof(Math))
//.SetVariable("value", 0.2);
try
{
// 从数据库加载规则
LoadRulesFromDatabase();
}
catch (Exception ex)
{
LogService.Error($"初始化逻辑服务失败: {ex.Message}");
}
}
/// <summary>
/// 从数据库加载规则
/// </summary>
private void LoadRulesFromDatabase()
{
try
{
// 从数据库加载规则
var dbRules = FreeSql.Select<LogicRule>().OrderBy(a => a.Id).ToList();
if (dbRules != null && dbRules.Count > 0)
{
LogicRuleDtos.Clear();
_expressionCache.Clear(); // 清空表达式缓存
foreach (var rule in dbRules)
{
LogicRuleDtos.Add(Mapper.Map<LogicRuleDto>(rule));
}
// 预编译所有表达式
WarmUpExpressionCache();
//LogService.Info($"已从数据库加载并预编译 {dbRules.Count} 条逻辑规则");
}
else
{
LogService.Warn("数据库中没有逻辑规则");
}
}
catch (Exception ex)
{
LogService.Error($"从数据库加载逻辑规则失败: {ex.Message}");
throw; // 重新抛出异常以便调用者处理
}
}
#region LogicRule
/// <summary>
/// 添加新规则
/// </summary>
/// <param name="rule">规则对象</param>
public void AddRule(LogicRule rule)
{
if (string.IsNullOrWhiteSpace(rule.Name))
{
MessageBox.Show("规则名称不能为空");
return;
}
if (string.IsNullOrWhiteSpace(rule.Expression))
{
MessageBox.Show("规则表达式不能为空");
return;
}
if (LogicRuleDtos.Where(a => a.Name == rule.Name).Any())
{
MessageBox.Show("已经有另一个相同名称的规则了");
return;
}
// 验证表达式是否有效
if (!ValidateExpression(rule.Expression))
{
MessageBox.Show("规则表达式验证失败");
return;
}
if (InsertRuleToDb(rule, out LogicRule resultInsert))
{
//此时的resultInsert有新增的ID
// 添加规则
LogicRuleDtos.Add(Mapper.Map<LogicRuleDto>(resultInsert));
// 预编译并缓存表达式
CacheExpression(Mapper.Map<LogicRuleDto>(resultInsert));
}
else
{
MessageBox.Show("增加数据失败!");
return;
}
//LogService.Info($"添加新规则: {rule.Name}");
}
/// <summary>
/// 保存规格到数据库中
/// </summary>
/// <returns></returns>
public bool InsertRuleToDb(LogicRule rule, out LogicRule ResultInsert)
{
try
{
// 插入规则到数据库
var result = FreeSql.Insert<LogicRule>(rule).ExecuteInserted();
// 检查影响的行数
bool success = result.Count > 0;
if (success)
{
ResultInsert = result.FirstOrDefault()!;
return success;
//LogService.Info($"成功插入规则: {rule.Name}");
// 刷新内存中的规则集合
//LoadRulesFromDatabase();
}
else
{
LogService.Warn($"插入规则失败: {rule.Name},没有行受影响");
ResultInsert = null;
return success;
}
}
catch (Exception ex)
{
LogService.Error($"插入规则到数据库时发生异常: {ex.Message}");
ResultInsert = null;
return false;
}
}
/// <summary>
/// 更新规则
/// </summary>
/// <param name="rule">规则对象</param>
public void UpdateRule(LogicRule rule)
{
if (string.IsNullOrWhiteSpace(rule.Name))
{
MessageBox.Show("规则名称不能为空");
return;
}
if (string.IsNullOrWhiteSpace(rule.Expression))
{
MessageBox.Show("规则表达式不能为空");
return;
}
// 验证表达式是否有效
if (!ValidateExpression(rule.Expression))
{
MessageBox.Show("规则表达式验证失败");
return;
}
if (UpdateRuleToDb(rule))
{
// 更新缓存
var updatedDto = LogicRuleDtos.FirstOrDefault(r => r.Id == rule.Id);
var insertIndex = LogicRuleDtos.ToList().FindIndex(x => x.Id > rule.Id);
if (updatedDto != null)
{
//移除数据
LogicRuleDtos.Remove(updatedDto);
if (insertIndex == -1)
{
LogicRuleDtos.Add(Mapper.Map<LogicRuleDto>(rule));
}
else
{
// 在找到的位置插入
LogicRuleDtos.Insert(insertIndex - 1, Mapper.Map<LogicRuleDto>(rule));
}
_expressionCache.TryRemove(updatedDto.Name, out _);
CacheExpression(updatedDto);
}
}
//LogService.Info($"更新规则: {rule.Name}");
}
/// <summary>
/// 更新规格到数据库中
/// </summary>
/// <returns></returns>
public bool UpdateRuleToDb(LogicRule rule)
{
try
{
// 更新规则到数据库
var result = FreeSql.Update<LogicRule>()
.Set(a => a.Name, rule.Name)
.Set(a => a.Description, rule.Description)
.Set(a => a.Expression, rule.Expression)
.Set(a => a.ParameterType, rule.ParameterType)
.Where(r => r.Id == rule.Id)
.ExecuteUpdated();
// 检查影响的行数
bool success = result.Count() > 0;
if (success)
{
//LogService.Info($"成功更新规则: {rule.Name}");
}
else
{
//LogService.Warn($"更新规则失败: {rule.Name},没有行受影响");
}
return success;
}
catch (Exception ex)
{
//LogService.Error($"更新规则到数据库时发生异常: {ex.Message}");
return false;
}
}
/// <summary>
/// 删除规则
/// </summary>
/// <param name="ruleName">规则名称</param>
public void DeleteRule(string ruleName)
{
var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName);
if (rule == null)
{
MessageBox.Show("找不到删除的数据");
return;
}
var Count = FreeSql.Delete<LogicRule>().Where(r => r.Id == rule.Id).ExecuteAffrows();
if (Count > 0)
{
// 删除规则
LogicRuleDtos.Remove(rule);
// 从缓存中移除表达式
_expressionCache.TryRemove(ruleName, out _);
}
//LogService.Info($"删除规则: {ruleName}");
}
/// <summary>
/// 验证表达式是否有效
/// </summary>
/// <param name="expression">表达式字符串</param>
/// <returns>表达式是否有效</returns>
private bool ValidateExpression(string expression)
{
try
{
// 创建测试解释器并直接设置变量
var interpreter = new Interpreter()
.Reference(typeof(Math)) // 引用Math类
.SetVariable("Math", typeof(Math))
.SetVariable("value", 100); // 直接设置值变量
// 尝试编译表达式
var lambda = interpreter.Parse(expression);
// 尝试执行表达式
var result = lambda.Invoke();
// 检查结果是否为数值类型
if (result is double doubleResult)
{
// 验证结果不是NaN或Infinity
if (double.IsNaN(doubleResult) || double.IsInfinity(doubleResult))
{
//LogService.Warn($"表达式执行结果无效 (NaN或Infinity): {expression}");
return false;
}
}
return true;
}
catch (Exception ex)
{
LogService.Warn($"验证表达式失败: {expression}, 错误: {ex.Message}");
return false;
}
}
#endregion
/// <summary>
/// 根据参数类型获取适用的规则
/// </summary>
/// <param name="parameterType">参数类型</param>
/// <returns>适用的规则列表</returns>
public IEnumerable<LogicRuleDto> GetRulesByParameterType(string parameterType)
{
return LogicRuleDtos.Where(r => r.ParameterType == parameterType);
}
/// <summary>
/// 获取指定名称的规则
/// </summary>
/// <param name="ruleName">规则名称</param>
/// <returns>规则对象</returns>
public LogicRuleDto GetRuleByName(string ruleName)
{
var rule = LogicRuleDtos.FirstOrDefault(r => r.Name == ruleName);
if (rule == null)
{
throw new KeyNotFoundException($"找不到名为 {ruleName} 的规则");
}
return rule;
}
/// <summary>
/// 应用逻辑转换 - 主要使用方法
/// </summary>
/// <param name="value">输入值</param>
/// <param name="ruleName">规则名称</param>
/// <returns>转换后的输出值</returns>
public double ApplyLogic(double value, string ruleName)
{
var rule = GetRuleByName(ruleName);
return ApplyExpression(value, rule);
}
/// <summary>
/// 应用逻辑转换(基于参数类型自动选择规则)
/// </summary>
/// <param name="value">输入值</param>
/// <param name="parameterType">参数类型</param>
/// <returns>转换后的输出值</returns>
public double ApplyLogicByType(double value, string parameterType)
{
var rules = GetRulesByParameterType(parameterType).ToList();
if (rules.Count == 0)
{
LogService.Warn($"未找到适用于 {parameterType} 的转换规则,将返回原始值");
return value;
}
// 如果存在多个规则,取第一个
var rule = rules.First();
return ApplyExpression(value, rule);
}
/// <summary>
/// 将规则表达式预编译并缓存到字典中
/// </summary>
/// <param name="rule">要缓存的规则</param>
private void CacheExpression(LogicRuleDto rule)
{
if (string.IsNullOrEmpty(rule.Name) || string.IsNullOrEmpty(rule.Expression))
{
return; // 防止空名称或空表达式
}
try
{
// 使用已有的CreateParameters方法创建参数声明
var parameter = CreateParameters(0); // 值不重要,只是为了获取参数声明
// 只解析一次,得到 Lambda 对象
var lambda = CurInterpreter.Parse(rule.Expression, parameter); // 只定义参数类型,不传值
// 存入缓存
_expressionCache[rule.Name] = lambda;
}
catch (Exception ex)
{
LogService.Error($"缓存规则 {rule.Name} 表达式失败: {ex.Message}");
}
}
/// <summary>
/// 预热表达式缓存 - 预编译所有规则
/// </summary>
private void WarmUpExpressionCache()
{
foreach (var rule in LogicRuleDtos)
{
if (!_expressionCache.ContainsKey(rule.Name))
{
CacheExpression(rule);
}
}
LogService.Info($"已预编译 {_expressionCache.Count} 条规则表达式");
}
/// <summary>
/// 根据规则应用表达式(高性能版本)
/// </summary>
/// <param name="value">输入值</param>
/// <param name="rule">规则对象</param>
/// <returns>转换后的输出值</returns>
public double ApplyExpression(double value, LogicRuleDto rule)
{
try
{
// 尝试从缓存获取预编译的表达式
if (!_expressionCache.TryGetValue(rule.Name, out var compiledExpression))
{
// 如果缓存中没有,则编译并添加到缓存
CacheExpression(rule);
// 再次尝试获取
if (!_expressionCache.TryGetValue(rule.Name, out compiledExpression))
{
// 初始解析表达式(只需执行一次)
string expressionText = rule.Expression;
// 强类型函数
Func<double, double> compiledFunc = (v) =>
{
// 高性能版本:直接根据公式计算
try
{
if (expressionText.Contains("value"))
{
var parameters = CreateParameters(v);
var lambda = CurInterpreter.Parse(expressionText, parameters);
return (double)lambda.Invoke();
}
else
{
// 简单表达式使用直接求值
return v / 100.0; // 默认处理
}
}
catch
{
// 出错时返回原值
return v;
}
};
// 再次尝试缓存
CacheExpression(rule);
return compiledFunc(value);
}
}
// 创建包含实际值的参数
var parameter = new Parameter("value", typeof(double), value);
// 使用预编译的表达式执行计算(高性能)
var convertedValue = (double)compiledExpression.Invoke(value);
return convertedValue;
}
catch (Exception ex)
{
//LogService.Error($"应用规则 {rule.Name} 失败: {ex.Message}");
return value; // 出错时返回原始值
}
}
/// <summary>
/// 临时测试用
/// </summary>
/// <param name="value"></param>
/// <param name="rule"></param>
/// <returns></returns>
public double ApplyExpressionNoCache(double value, LogicRuleDto rule)
{
try
{
CurInterpreter.SetVariable("value", value);
var lambda = CurInterpreter.Parse(rule.Expression);
return (double)lambda.Invoke();
//// 创建全新的解释器实例
//var localInterpreter = new Interpreter()
// .Reference(typeof(Math))
// .SetVariable("Math", typeof(Math));
//// 直接设置变量值而不是使用参数
//localInterpreter.SetVariable("value", value);
//// 解析并执行
//var result = localInterpreter.Eval<double>(rule.Expression);
//Console.WriteLine($"直接执行: 输入={value}, 表达式={rule.Expression}, 结果={result}");
//return result;
}
catch (Exception ex)
{
LogService.Error($"直接执行表达式失败: {ex.Message}");
return value;
}
}
/// <summary>
/// 批量应用逻辑转换 (高性能版本)
/// </summary>
/// <param name="values">原始值字典(键为参数名称,值为原始值)</param>
/// <returns>转换后的值字典</returns>
public Dictionary<string, double> ApplyBatchLogic(Dictionary<string, double> values)
{
// 为了性能,预分配容量
var result = new Dictionary<string, double>(values.Count);
// 缓存参数类型到规则的映射,避免重复查询
var cachedRulesByType = new Dictionary<string, LogicRuleDto>();
foreach (var entry in values)
{
var paramName = entry.Key;
var origValue = entry.Value;
try
{
// 获取参数类型
var paramType = DetermineParameterType(paramName);
// 尝试从缓存获取规则
if (!cachedRulesByType.TryGetValue(paramType, out var rule))
{
var rules = GetRulesByParameterType(paramType).ToList();
if (rules.Count > 0)
{
rule = rules.First();
cachedRulesByType[paramType] = rule; // 添加到缓存
}
}
// 如果找到规则,应用转换
if (rule != null)
{
var convertedValue = ApplyExpression(origValue, rule);
result.Add(paramName, convertedValue);
}
else
{
result.Add(paramName, origValue); // 没有规则时使用原始值
}
}
catch (Exception ex)
{
LogService.Error($"处理参数 {paramName} 失败: {ex.Message}");
result.Add(paramName, origValue); // 出错时使用原始值
}
}
return result;
}
/// <summary>
/// 从参数名称确定参数类型
/// </summary>
/// <param name="paramName">参数名称</param>
/// <returns>参数类型</returns>
private string DetermineParameterType(string paramName)
{
// 根据参数名称确定类型的逻辑
// 这里使用简单的名称匹配,实际项目中可能需要更复杂的映射
if (paramName.Contains("速度") || paramName.Contains("转速"))
return "转速";
else if (paramName.Contains("功率") || paramName.Contains("pw") || paramName.Contains("power"))
return "功率";
else if (paramName.Contains("温度") || paramName.Contains("temp"))
return "温度";
else if (paramName.Contains("压力") || paramName.Contains("press"))
return "压力";
// 默认类型
return "通用";
}
}
}

View File

@@ -40,6 +40,7 @@ namespace CapMachine.Wpf.Services
private IEventAggregator _EventAggregator { get; set; }
public AlarmService AlarmService { get; }
public ConfigService ConfigService { get; }
public LogicRuleService LogicRuleService { get; }
public CanDriveService CanDriveService { get; }
public LinDriveService LinDriveService { get; }
public SysRunService SysRunService { get; }
@@ -133,7 +134,7 @@ namespace CapMachine.Wpf.Services
/// 实例化函数
/// </summary>
/// <param name="eventAggregator"></param>
public MachineRtDataService(IEventAggregator eventAggregator, AlarmService alarmService, ConfigService configService,
public MachineRtDataService(IEventAggregator eventAggregator, AlarmService alarmService, ConfigService configService, LogicRuleService logicRuleService,
CanDriveService canDriveService, LinDriveService linDriveService, SysRunService sysRunService)//, AlarmService alarmService
{
//ConcurrentDictionary<DateTime, RecordInfo> keyValuePairs = new ConcurrentDictionary<DateTime, RecordInfo>();
@@ -145,12 +146,12 @@ namespace CapMachine.Wpf.Services
//stopwatch.Stop(); //停止Stopwatch
//Console.WriteLine("Add Elapsed output runTime:{0}", stopwatch.Elapsed.ToString());
//MelsecMcNetDrive.
//事件服务
_EventAggregator = eventAggregator;
AlarmService = alarmService;
ConfigService = configService;
LogicRuleService = logicRuleService;
CanDriveService = canDriveService;
LinDriveService = linDriveService;
SysRunService = sysRunService;
@@ -2703,6 +2704,7 @@ namespace CapMachine.Wpf.Services
//程序步骤的写入
ProRunStepWrite();
Console.WriteLine($"结果:{LogicRuleService.ApplyExpression(random.NextDouble() * 100, LogicRuleService.LogicRuleDtos.FirstOrDefault())}");
//stopwatch.Stop(); //停止Stopwatch
//Console.WriteLine("Add Elapsed output runTime:{0}", stopwatch.Elapsed.TotalSeconds.ToString());

View File

@@ -40,10 +40,10 @@ namespace CapMachine.Wpf.Services
new NavigationItem("SuperHeatCool","过热度/过冷度配置","DialogSuperHeatCoolConfigView"),
//new NavigationItem("Palette","过冷度",""),
}),
//new NavigationItem("", "PID设置","",new ObservableCollection<NavigationItem>()
//{
// new NavigationItem("Circle","转速PID",""),
//}),
new NavigationItem("", "规则设置","",new ObservableCollection<NavigationItem>()
{
new NavigationItem("Rule","规则转换","DialogLogicRuleView"),
}),
//new NavigationItem("", "通信配置","",new ObservableCollection<NavigationItem>()
//{
// new NavigationItem("Circle","CAN配置","CANConfigView"),

View File

@@ -1,4 +1,4 @@
using AutoMapper;
using AutoMapper;
using CapMachine.Model;
using CapMachine.Shared.Controls;
using CapMachine.Wpf.ChannelModel;

View File

@@ -37,7 +37,7 @@ namespace CapMachine.Wpf.ViewModels
{
public CANConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
ComActionService actionService,
ComActionService actionService, LogicRuleService logicRuleService,
ConfigService configService, CanDriveService canDriveService,
IMapper mapper, MachineRtDataService machineRtDataService)
{
@@ -47,6 +47,7 @@ namespace CapMachine.Wpf.ViewModels
RegionManager = regionManager;
SysRunService = sysRunService;
ComActionService = actionService;
LogicRuleService = logicRuleService;
ConfigService = configService;
CanDriveService = canDriveService;
Mapper = mapper;
@@ -63,6 +64,7 @@ namespace CapMachine.Wpf.ViewModels
new CbxItems(){ Key="Anti_Sleep",Text="Anti_Sleep"},
};
ReadNameCbxItems = new ObservableCollection<CbxItems>()
{
new CbxItems(){ Key="通讯转速",Text="通讯转速"},
@@ -72,8 +74,20 @@ namespace CapMachine.Wpf.ViewModels
new CbxItems(){ Key="通讯功率",Text="通讯功率"},
new CbxItems(){ Key="通讯芯片温度",Text="通讯芯片温度"},
};
InitLoadCanConfigPro();
WriteRuleCbxItems = new ObservableCollection<CbxItems>();
//选择的读写规则
foreach (var itemRule in LogicRuleService.LogicRuleDtos)
{
WriteRuleCbxItems.Add(new CbxItems()
{
Key = itemRule.Id.ToString(),
Text = itemRule.Name
});
}
}
@@ -85,6 +99,7 @@ namespace CapMachine.Wpf.ViewModels
public IRegionManager RegionManager { get; }
public SysRunService SysRunService { get; }
public ComActionService ComActionService { get; }
public LogicRuleService LogicRuleService { get; }
public ConfigService ConfigService { get; }
public CanDriveService CanDriveService { get; }
public IMapper Mapper { get; }
@@ -107,7 +122,7 @@ namespace CapMachine.Wpf.ViewModels
//CAN配置集合数据
canLinConfigPros = FreeSql.Select<CanLinConfigPro>().Where(a => a.CANLINInfo == CANLIN.CAN)
.Include(a => a.CANConfigExd)
.IncludeMany(a => a.CanLinConfigContents)
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule)
.ToList();
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(canLinConfigPros);
@@ -116,7 +131,7 @@ namespace CapMachine.Wpf.ViewModels
SelectCanLinConfigPro = canLinConfigPros.Where(a => a.Id == SelectCanLinConfigPro.Id).FirstOrDefault()!;
//无数据就返回
if (SelectCanLinConfigPro == null) return;
SelectedCANConfigExdDto = Mapper.Map<CANConfigExdDto>(SelectCanLinConfigPro!.CANConfigExd);
//配置信息
@@ -695,7 +710,7 @@ namespace CapMachine.Wpf.ViewModels
}
//(par as SelectionChangedEventArgs)!.AddedItems[0] == null
if ((par as SelectionChangedEventArgs)!.AddedItems.Count==0)
if ((par as SelectionChangedEventArgs)!.AddedItems.Count == 0)
{
return;
}
@@ -833,7 +848,7 @@ namespace CapMachine.Wpf.ViewModels
//系统使用了CAN
ConfigService.CanLinRunStateModel.CurSysSelectedCanLin = CanLinEnum.Can;
}
//CAN DBC配置 有DBC配置的话则直接加载DBC信息
if (!string.IsNullOrEmpty(SelectCanLinConfigPro.CANConfigExd.DbcPath))
{
@@ -980,6 +995,16 @@ namespace CapMachine.Wpf.ViewModels
set { _WriteNameCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _WriteRuleCbxItems;
/// <summary>
/// 写入的规格集合
/// </summary>
public ObservableCollection<CbxItems> WriteRuleCbxItems
{
get { return _WriteRuleCbxItems; }
set { _WriteRuleCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _ReadNameCbxItems;
/// <summary>
@@ -991,6 +1016,15 @@ namespace CapMachine.Wpf.ViewModels
set { _ReadNameCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _ReadRuleCbxItems;
/// <summary>
/// 读取的规格集合
/// </summary>
public ObservableCollection<CbxItems> ReadRuleCbxItems
{
get { return _ReadRuleCbxItems; }
set { _ReadRuleCbxItems = value; RaisePropertyChanged(); }
}
//private string _SelectedWriteName;
///// <summary>
@@ -1106,6 +1140,7 @@ namespace CapMachine.Wpf.ViewModels
//直接修改
FreeSql.Update<CanLinRWConfig>(item.Id)
.Set(a => a.Name, item.Name)
.Set(a => a.LogicRuleId, item.LogicRuleId)
.Set(a => a.DefautValue, item.DefautValue)
.ExecuteAffrows();
//ListWriteCanLinRWConfigDto.Remove(SelectedWriteCanLinRWConfigDto);

View File

@@ -0,0 +1,233 @@
using AutoMapper;
using CapMachine.Core;
using CapMachine.Model;
using CapMachine.Wpf.Dtos;
using CapMachine.Wpf.Services;
using Masuit.Tools;
using Prism.Commands;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace CapMachine.Wpf.ViewModels
{
/// <summary>
/// 逻辑规则配置的弹窗
/// </summary>
public class DialogLogicRuleViewModel : DialogViewModel
{
public DialogLogicRuleViewModel(IFreeSql freeSql, IMapper mapper, LogicRuleService logicRuleService)
{
Title = "逻辑规则创建";
FreeSql = freeSql;
Mapper = mapper;
LogicRuleService = logicRuleService;
//var Data = Mapper.Map<List<LogicRuleDto>>(LogicRuleService.LogicRuleDtos);
ListLogicRuleDto = LogicRuleService.LogicRuleDtos;
}
public IFreeSql FreeSql { get; }
public IMapper Mapper { get; }
public LogicRuleService LogicRuleService { get; }
private ObservableCollection<LogicRuleDto> _ListLogicRuleDto;
/// <summary>
/// 数据集合
/// </summary>
public ObservableCollection<LogicRuleDto> ListLogicRuleDto
{
get { return _ListLogicRuleDto; }
set { _ListLogicRuleDto = value; RaisePropertyChanged(); }
}
private LogicRuleDto _selectedRule;
/// <summary>
/// 当前选中的规则
/// </summary>
public LogicRuleDto SelectedRule
{
get { return _selectedRule; }
set { _selectedRule = value; RaisePropertyChanged(); }
}
private DelegateCommand<object> _GridSelectionChangedCmd;
/// <summary>
/// 选中行数据命令
/// </summary>
public DelegateCommand<object> GridSelectionChangedCmd
{
set
{
_GridSelectionChangedCmd = value;
}
get
{
if (_GridSelectionChangedCmd == null)
{
_GridSelectionChangedCmd = new DelegateCommand<object>((par) => GridSelectionChangedCmdMethod(par));
}
return _GridSelectionChangedCmd;
}
}
private void GridSelectionChangedCmdMethod(object par)
{
var selectedItem = par as LogicRuleDto;
if (selectedItem != null)
{
//先判断是否是正确的集合数据防止DataGrid的数据源刷新导致的触发事件
SelectedRule = selectedItem.DeepClone();
}
////选中的行数据
}
private DelegateCommand<string> _RuleCmd;
/// <summary>
/// 选中行数据命令
/// </summary>
public DelegateCommand<string> RuleCmd
{
set
{
_RuleCmd = value;
}
get
{
if (_RuleCmd == null)
{
_RuleCmd = new DelegateCommand<string>((par) => RuleCmdMethod(par));
}
return _RuleCmd;
}
}
private void RuleCmdMethod(string par)
{
if (SelectedRule==null)
{
MessageBox.Show("选中后再操作数据");
return;
}
//先判断是否是正确的集合数据防止DataGrid的数据源刷新导致的触发事件
switch (par)
{
case "Create":
//SelectedRule
LogicRuleService.AddRule(Mapper.Map<LogicRule>(SelectedRule));
break;
case "Update":
LogicRuleService.UpdateRule(Mapper.Map<LogicRule>(SelectedRule));
break;
case "Delete":
LogicRuleService.DeleteRule(SelectedRule.Name);
break;
default:
break;
}
////选中的行数据
}
#region
private string name;
/// <summary>
/// 名称
/// </summary>
public string Name
{
get { return name; }
set { name = value; RaisePropertyChanged(); }
}
private DelegateCommand saveCmd;
/// <summary>
/// 保存命令
/// </summary>
public DelegateCommand SaveCmd
{
set
{
saveCmd = value;
}
get
{
if (saveCmd == null)
{
saveCmd = new DelegateCommand(() => SaveCmdMethod());
}
return saveCmd;
}
}
/// <summary>
/// 保存命令方法
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void SaveCmdMethod()
{
DialogParameters pars = new DialogParameters
{
{ "NewData", "" }
};
RaiseRequestClose(new DialogResult(ButtonResult.OK, pars));
}
private DelegateCommand cancelCmd;
/// <summary>
/// 保存命令
/// </summary>
public DelegateCommand CancelCmd
{
set
{
cancelCmd = value;
}
get
{
if (cancelCmd == null)
{
cancelCmd = new DelegateCommand(() => CancelCmdMethod());
}
return cancelCmd;
}
}
/// <summary>
/// 取消命令方法
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void CancelCmdMethod()
{
RaiseRequestClose(new DialogResult(ButtonResult.Cancel));
}
/// <summary>
/// 窗口打开时的传递的参数
/// </summary>
/// <param name="parameters"></param>
public override void OnDialogOpened(IDialogParameters parameters)
{
Name = parameters.GetValue<string>("Name");
}
#endregion
}
}

View File

@@ -6,6 +6,7 @@ using CapMachine.Wpf.Services;
using Prism.Commands;
using Prism.Events;
using Prism.Regions;
using Prism.Services.Dialogs;
using System.Windows.Input;
namespace CapMachine.Wpf.ViewModels

View File

@@ -73,7 +73,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="400" />
<ColumnDefinition />
<ColumnDefinition Width="550" />
<ColumnDefinition Width="650" />
</Grid.ColumnDefinitions>
<Grid Margin="3">
@@ -417,36 +417,10 @@
FontSize="18"
Text="&#xe9f8;" />
<TextBlock Style="{StaticResource TextBlockStyle}" Text="循环周期(ms)" />
<TextBox Style="{StaticResource TextBoxStyle}" Text="{Binding SelectedCANConfigExdDto.Cycle}" />
</StackPanel>
<StackPanel
Grid.Row="2"
Grid.Column="2"
Orientation="Horizontal">
<TextBlock
Margin="10,0,5,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe9f8;" />
<TextBlock
Width="90"
Style="{StaticResource TextBlockStyle}"
Text="转速(rpm)" />
<TextBox
Margin="5,0"
Style="{StaticResource TextBoxStyle}"
Text="{Binding HandSpeed}" />
<Button
Margin="5,0"
Command="{Binding CanOpCmd}"
CommandParameter="HandSend"
Content="手动发送"
Foreground="White" />
</StackPanel>
<StackPanel
Grid.Row="2"
Grid.ColumnSpan="3"
@@ -507,7 +481,7 @@
</Border>
<Button
Margin="15,0,5,0"
Margin="10,0,5,0"
Command="{Binding CanOpCmd}"
CommandParameter="CycleSend">
<Button.Style>
@@ -570,6 +544,27 @@
</StackPanel>
</Button>
<TextBlock
Margin="5,0,5,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe9f8;" />
<TextBlock
Width="90"
Style="{StaticResource TextBlockStyle}"
Text="转速(rpm)" />
<TextBox
Margin="5,0"
Style="{StaticResource TextBoxStyle}"
Text="{Binding HandSpeed}" />
<Button
Margin="5,0"
Command="{Binding CanOpCmd}"
CommandParameter="HandSend"
Content="手动发送"
Foreground="White" />
</StackPanel>
@@ -711,12 +706,26 @@
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding DefautValue}">
<DataGridTextColumn.Header>
<TextBlock FontWeight="Bold" Text="默认值" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTemplateColumn Width="200" Header="规则名称">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
DisplayMemberPath="Text"
ItemsSource="{Binding Source={StaticResource Proxy}, Path=Data.WriteRuleCbxItems}"
SelectedValue="{Binding LogicRuleId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Key" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">

View File

@@ -0,0 +1,323 @@
<UserControl
x:Class="CapMachine.Wpf.Views.DialogLogicRuleView"
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:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:local="clr-namespace:CapMachine.Wpf.Views"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://prismlibrary.com/"
Width="1600"
Height="800"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<DataGrid
Name="MainDatagrid"
Margin="5"
AutoGenerateColumns="False"
CanUserAddRows="False"
HeadersVisibility="Column"
IsReadOnly="True"
ItemsSource="{Binding ListLogicRuleDto}">
<DataGrid.Columns>
<DataGridTextColumn
Width="180"
Binding="{Binding Name}"
Header="规则名称" />
<DataGridTextColumn
Width="180"
Binding="{Binding ParameterType}"
Header="参数类型" />
<DataGridTextColumn
Width="*"
Binding="{Binding Expression}"
Header="表达式" />
<DataGridTextColumn
Width="100"
Binding="{Binding Description}"
Header="描述" />
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<prism:InvokeCommandAction Command="{Binding GridSelectionChangedCmd}" CommandParameter="{Binding ElementName=MainDatagrid, Path=SelectedItem}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
<!-- 右侧编辑面板 -->
<Grid Grid.Column="1" Margin="10,5,5,5">
<Grid.Resources>
<Style x:Key="EditLabelStyle" TargetType="TextBlock">
<Setter Property="Width" Value="100" />
<Setter Property="FontSize" Value="16" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="5,0" />
</Style>
<Style x:Key="EditTextBoxStyle" TargetType="TextBox">
<Setter Property="FontSize" Value="16" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="10,5" />
<Setter Property="Padding" Value="5,3" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- 标题 -->
<Border
Grid.Row="0"
Margin="0,0,0,5"
Padding="10,5"
Background="#2196F3"
CornerRadius="5">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="5,0,10,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="22"
Foreground="White"
Text="&#xe73a;" />
<TextBlock
VerticalAlignment="Center"
FontSize="18"
FontWeight="Bold"
Foreground="White"
Text="规则详情" />
</StackPanel>
</Border>
<!-- 名称 -->
<StackPanel
Grid.Row="1"
Margin="0,5"
Orientation="Horizontal">
<TextBlock
Margin="5,0,10,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe63c;" />
<TextBlock Style="{StaticResource EditLabelStyle}" Text="规则名称" />
<TextBox
Width="250"
Style="{StaticResource EditTextBoxStyle}"
Text="{Binding SelectedRule.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<!-- 描述 -->
<StackPanel
Grid.Row="2"
Margin="0,5"
Orientation="Horizontal">
<TextBlock
Margin="5,0,10,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe67c;" />
<TextBlock Style="{StaticResource EditLabelStyle}" Text="规则描述" />
<TextBox
Width="250"
Style="{StaticResource EditTextBoxStyle}"
Text="{Binding SelectedRule.Description, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<!-- 参数类型 -->
<StackPanel
Grid.Row="3"
Margin="0,5"
Orientation="Horizontal">
<TextBlock
Margin="5,0,10,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe679;" />
<TextBlock Style="{StaticResource EditLabelStyle}" Text="参数类型" />
<TextBox
Width="250"
Style="{StaticResource EditTextBoxStyle}"
Text="{Binding SelectedRule.ParameterType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<!-- 表达式 -->
<StackPanel
Grid.Row="4"
Margin="0,5"
Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="5,0,10,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Text="&#xe661;" />
<TextBlock
Style="{StaticResource EditLabelStyle}"
Text="规则表达式:"
TextWrapping="Wrap" />
</StackPanel>
<Border
Margin="3,5"
BorderBrush="Gray"
BorderThickness="1">
<!--<RichTextBox 1可输入公式2输入值用value 代替3公式需符合三元表达式可嵌套
Height="200"
materialDesign:HintAssist.Hint="规则输入"
AcceptsReturn="True"
IsDocumentEnabled="True"
IsReadOnly="False"
SpellCheck.IsEnabled="True"
VerticalScrollBarVisibility="Auto">
<FlowDocument>
<Paragraph>
<Run FontWeight="Bold">
注意:
1可输入公式
2输入值用value 代替;
3公式需符合三元表达式可嵌套
</Run>
<LineBreak />
<Run
FontStyle="Normal"
FontWeight="Bold"
Foreground="Blue"
Text="{Binding SelectedRule.Expression}" />
<LineBreak />
</Paragraph>
</FlowDocument>
</RichTextBox>-->
<TextBox
Height="100"
Margin="10,5"
Padding="5"
AcceptsReturn="True"
Text="{Binding SelectedRule.Expression, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap"
VerticalScrollBarVisibility="Auto" />
</Border>
<TextBlock
FontSize="14"
Text="1可输入公式2输入值用value 代替3公式需符合三元表达式可嵌套"
TextWrapping="Wrap" />
</StackPanel>
<!-- 操作按钮 -->
<StackPanel
Grid.Row="5"
Margin="0,20,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button
Margin="5,0"
Padding="15,5"
Command="{Binding RuleCmd}"
CommandParameter="Create">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="2,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Foreground="White"
Text="&#xe62f;" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Foreground="White"
Text="新建" />
</StackPanel>
</Button>
<Button
Margin="5,0"
Padding="15,5"
Command="{Binding RuleCmd}"
CommandParameter="Update">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="2,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Foreground="White"
Text="&#xe63a;" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Foreground="White"
Text="更新" />
</StackPanel>
</Button>
<Button
Margin="5,0"
Padding="15,5"
Command="{Binding RuleCmd}"
CommandParameter="Delete">
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="2,0"
VerticalAlignment="Center"
FontFamily="/Assets/Fonts/#iconfont"
FontSize="18"
Foreground="White"
Text="&#xe646;" />
<TextBlock
VerticalAlignment="Center"
FontSize="14"
Foreground="White"
Text="删除" />
</StackPanel>
</Button>
</StackPanel>
</Grid>
</Grid>
<StackPanel
Grid.Row="1"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Margin="10,10"
Command="{Binding SaveCmd}"
Content="确定"
Foreground="White" />
<Button
Margin="10,0"
Command="{Binding CancelCmd}"
Content="取消"
Foreground="White" />
</StackPanel>
</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 CapMachine.Wpf.Views
{
/// <summary>
/// DialogLogicRuleView.xaml 的交互逻辑
/// </summary>
public partial class DialogLogicRuleView : UserControl
{
public DialogLogicRuleView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,7 @@
我是一个C# 软件开发者,我在开发一个压缩机耐久性能台的软件系统,主要功能如下:
# 读取PLC的数据PLC是西门子的S200
# 通过DBC配置CAN通过Ldf配置LIN通信
# 通过配置程序步骤能逐步的下载步骤信息到PLC中逐步的执行程序步骤程序中有SV(设置值),下载的速度数据是下载到压缩机中
# 获取所有的数据包括PLC的数据和压缩机的数据然后能绘制曲线
# 能对获取的数据进行数据记录保存到文件中记录的值是SV数据
# 能记录日志信息