CAN FD 增加逻辑功能

This commit is contained in:
2025-07-11 14:58:47 +08:00
parent 3ef3c534f3
commit f6d9437143
19 changed files with 1524 additions and 14 deletions

View File

@@ -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

@@ -0,0 +1,52 @@
using CapMachine.Model.CANLIN;
using FreeSql.DataAnnotations;
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

@@ -123,7 +123,7 @@ namespace CapMachine.Wpf
//containerRegistry.RegisterSingleton<IAppStartService, AppStartService>();
//containerRegistry.RegisterSingleton<IApplicationContext, ApplicationContext>();
containerRegistry.RegisterSingleton<LogicRuleService>();
containerRegistry.RegisterSingleton<ConfigService>();
containerRegistry.RegisterSingleton<AlarmService>();
////注册设备服务
@@ -199,6 +199,7 @@ namespace CapMachine.Wpf
containerRegistry.RegisterDialog<DialogPIDConfigView, DialogPIDConfigViewModel>();
containerRegistry.RegisterDialog<DialogLimitConfigView, DialogLimitConfigViewModel>();
containerRegistry.RegisterDialog<DialogSuperHeatCoolConfigView, DialogSuperHeatCoolConfigViewModel>();
containerRegistry.RegisterDialog<DialogLogicRuleView, DialogLogicRuleViewModel>();
containerRegistry.RegisterDialog<SplashScreenView, SplashScreenViewModel>();

View File

@@ -1,4 +1,5 @@
using System;
using CapMachine.Wpf.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -31,5 +32,17 @@ namespace CapMachine.Wpf.CanDrive
/// 没有的话,则给默认值
/// </summary>
public double SignalCmdValue { get; set; }
///// <summary>
///// 逻辑规则Id
///// </summary>
//public long LogicRuleId { get; set; }
/// <summary>
/// CanLinConfig的逻辑转换规则
/// 比如速度下发的数据SV是4000但是下发到CAN的值是40可能是其他的逻辑转换规则这里就是保存其中的逻辑规则
/// </summary>
public LogicRuleDto? LogicRuleDto { get; set; }
}
}

View File

@@ -664,6 +664,7 @@
<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" />

View File

@@ -70,7 +70,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,73 @@
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

@@ -0,0 +1,19 @@
using AutoMapper;
using CapMachine.Model;
using CapMachine.Wpf.Dtos;
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

@@ -99,7 +99,7 @@ namespace CapMachine.Wpf.Models.Tag.Cell
}
}
private string? _EngValueStr;
private string? _EngValueStr="0";
/// <summary>
/// 工程值的字符串 MV
/// </summary>

View File

@@ -0,0 +1,14 @@
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CapMachine.Wpf.PrismEvent
{
public class LogicRuleChangeEvent : PubSubEvent<string>
{
}
}

View File

@@ -1,5 +1,7 @@
using CapMachine.Model.CANLIN;
using CapMachine.Wpf.CanDrive;
using CapMachine.Wpf.Models;
using CapMachine.Wpf.Models.ProModelPars;
using ImTools;
using Prism.Ioc;
using Prism.Mvvm;
@@ -18,15 +20,17 @@ namespace CapMachine.Wpf.Services
public class CanFdDriveService : BindableBase
{
public HighSpeedDataService HighSpeedDataService { get; }
public LogicRuleService LogicRuleService { get; }
/// <summary>
/// 实例化函数
/// </summary>
public CanFdDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider)
public CanFdDriveService(HighSpeedDataService highSpeedDataService, IContainerProvider containerProvider, LogicRuleService logicRuleService)
{
ToomossCanFDDrive = new ToomossCanFD(containerProvider);
//高速数据服务
HighSpeedDataService = highSpeedDataService;
LogicRuleService = logicRuleService;
//ToomossCanFDDrive.StartCanDrive();
}
@@ -172,7 +176,14 @@ namespace CapMachine.Wpf.Services
{
if (SpeedCanCmdData != null)
{
SpeedCanCmdData.SignalCmdValue = SpeedData;
if (SpeedCanCmdData.LogicRuleDto == null)
{
//没有启动逻辑规则处理
SpeedCanCmdData.SignalCmdValue = SpeedData;
return;
}
SpeedCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(SpeedData, SpeedCanCmdData.LogicRuleDto);
}
//if (EnableCanCmdData != null)
//{
@@ -201,7 +212,12 @@ namespace CapMachine.Wpf.Services
{
if (PwLimitCanCmdData != null)
{
PwLimitCanCmdData.SignalCmdValue = PwLimit;
if (PwLimitCanCmdData.LogicRuleDto==null)
{
PwLimitCanCmdData.SignalCmdValue = PwLimit;
return;
}
PwLimitCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(PwLimit, PwLimitCanCmdData.LogicRuleDto!);
}
}
@@ -226,7 +242,12 @@ namespace CapMachine.Wpf.Services
{
if (PTCPwCanCmdData != null)
{
PTCPwCanCmdData.SignalCmdValue = PTCPw;
if (PTCPwCanCmdData.LogicRuleDto == null)
{
PTCPwCanCmdData.SignalCmdValue = PTCPw;
return;
}
PTCPwCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(PTCPw, PTCPwCanCmdData.LogicRuleDto!);
}
}
@@ -238,7 +259,12 @@ namespace CapMachine.Wpf.Services
{
if (PTCFlowCanCmdData != null)
{
PTCFlowCanCmdData.SignalCmdValue = Flow;
if (PTCFlowCanCmdData.LogicRuleDto == null)
{
PTCFlowCanCmdData.SignalCmdValue = Flow;
return;
}
PTCFlowCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(Flow, PTCFlowCanCmdData.LogicRuleDto!);
}
}
@@ -250,7 +276,12 @@ namespace CapMachine.Wpf.Services
{
if (PTCWaterTempCanCmdData != null)
{
PTCWaterTempCanCmdData.SignalCmdValue = WaterTemp;
if (PTCWaterTempCanCmdData.LogicRuleDto == null)
{
PTCWaterTempCanCmdData.SignalCmdValue = WaterTemp;
return;
}
PTCWaterTempCanCmdData.SignalCmdValue = LogicRuleService.ApplyExpressionFast(WaterTemp, PTCWaterTempCanCmdData.LogicRuleDto!);
}
}

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
{
@@ -61,6 +62,14 @@ namespace CapMachine.Wpf.Services
case "过热度/过冷度配置":
ShowSuperHeatCool(msg.Par);
break;
case "规则转换":
if (SysRunServer.MachineRunState1.IsRunState)
{
MessageBox.Show("请不要在运行时编辑规则转换,此时更改可能导致运行出错,请停止后再编辑");
return;
}
ShowLogicRule(msg.Par);
break;
default:
break;
}
@@ -93,6 +102,40 @@ 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();
//是否改变规格
var ReturnValue = par.Parameters.GetValue<bool>("IsRuleEdit");
if (ReturnValue)
{
MessageBox.Show("检测到你已经改变了规则CAN或者LIN配置中如果已经加载规则或者连接的话则会出现错误那么你需要重启软件");
//逻辑可能更改了
EventAggregator.GetEvent<LogicRuleChangeEvent>().Publish("");
}
}
else if (par.Result == ButtonResult.Cancel)
{
//取消
}
});
}

View File

@@ -0,0 +1,578 @@
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, Func<double, double>> _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, Func<double, double>>();
// 初始化DynamicExpresso解释器
CurInterpreter = new Interpreter();
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 ruleOld, 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中肯定是找不到的,可以用之前的ruleOld
_expressionCache.TryRemove(ruleOld.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="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); // 只定义参数类型,不传值
// 编译为强类型委托
var compiledFunc = lambda.Compile<Func<double, double>>();
// 存入缓存
_expressionCache[rule.Name] = compiledFunc;
}
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 ApplyExpressionFast(double value, LogicRuleDto rule)
{
try
{
if (!_expressionCache.TryGetValue(rule.Name, out var CurActiveFunc))
{
CacheExpression(rule);
if (!_expressionCache.TryGetValue(rule.Name, out CurActiveFunc))
return value;
}
// 直接调用委托,无反射开销
return CurActiveFunc(value);
}
catch
{
return value;
}
}
/// <summary>
/// 如果需要对多个数据应用相同规则,考虑实现批处理版本:
/// </summary>
/// <param name="values"></param>
/// <param name="rule"></param>
/// <returns></returns>
public IEnumerable<double> ApplyExpressionBatch(IEnumerable<double> values, LogicRuleDto rule)
{
if (!_expressionCache.TryGetValue(rule.Name, out var func))
{
CacheExpression(rule);
if (!_expressionCache.TryGetValue(rule.Name, out func))
return values;
}
// 使用并行处理大量数据
return values.AsParallel().Select(v =>
{
try { return func(v); }
catch { return v; }
});
}
}
}

View File

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

View File

@@ -34,7 +34,7 @@ namespace CapMachine.Wpf.ViewModels
{
public CANFDConfigViewModel(IDialogService dialogService, IFreeSql freeSql,
IEventAggregator eventAggregator, IRegionManager regionManager, SysRunService sysRunService,
ComActionService actionService,ILogService logService,
ComActionService actionService, ILogService logService, LogicRuleService logicRuleService,
ConfigService configService, CanFdDriveService canFdDriveService,
IMapper mapper, MachineRtDataService machineRtDataService)
{
@@ -44,6 +44,7 @@ namespace CapMachine.Wpf.ViewModels
RegionManager = regionManager;
SysRunService = sysRunService;
ComActionService = actionService;
LogicRuleService = logicRuleService;
LogService = logService;
ConfigService = configService;
CanFdDriveService = canFdDriveService;
@@ -127,8 +128,10 @@ namespace CapMachine.Wpf.ViewModels
new CbxItems(){ Key="通讯PTC膜温",Text="通讯PTC膜温"},
new CbxItems(){ Key="通讯PTC模块温度",Text="通讯PTC模块温度"},
};
InitLoadCanConfigPro();
InitLoadCanConfigPro();
//初始化写规则下拉框
InitWriteRuleCbx();
}
@@ -140,6 +143,7 @@ namespace CapMachine.Wpf.ViewModels
public IRegionManager RegionManager { get; }
public SysRunService SysRunService { get; }
public ComActionService ComActionService { get; }
public LogicRuleService LogicRuleService { get; }
public ILogService LogService { get; }
public ConfigService ConfigService { get; }
public CanFdDriveService CanFdDriveService { get; }
@@ -151,8 +155,40 @@ namespace CapMachine.Wpf.ViewModels
/// </summary>
public IDialogService DialogService { get; }
#region
/// <summary>
/// 逻辑更改事件
/// </summary>
/// <param name="msg"></param>
/// <exception cref="NotImplementedException"></exception>
private void LogicRuleChangeEventCall(string msg)
{
//InitWriteRuleCbx();
}
/// <summary>
/// 初始化写规则下拉框
/// </summary>
private void InitWriteRuleCbx()
{
WriteRuleCbxItems = new ObservableCollection<CbxItems>();
//选择的读写规则
foreach (var itemRule in LogicRuleService.LogicRuleDtos)
{
WriteRuleCbxItems.Add(new CbxItems()
{
Key = itemRule.Id.ToString(),
Text = itemRule.Name
});
}
}
#endregion
#region CanConfigPro
/// <summary>
@@ -163,7 +199,8 @@ namespace CapMachine.Wpf.ViewModels
//CAN配置集合数据
canLinConfigPros = FreeSql.Select<CanLinConfigPro>().Where(a => a.CANLINInfo == CANLIN.CANFD)
.Include(a => a.CANFdConfigExd)
.IncludeMany(a => a.CanLinConfigContents)
.IncludeMany(a => a.CanLinConfigContents, then => then.Include(b => b.LogicRule))//,then=> then.Include(b=>b.LogicRule)
//.IncludeMany(a => a.CanLinConfigContents)
.ToList();
ListCanLinConfigPro = new ObservableCollection<CanLinConfigPro>(canLinConfigPros);
@@ -197,6 +234,7 @@ namespace CapMachine.Wpf.ViewModels
MsgName = item.MsgFrameName,
SignalName = item.SignalName,
SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0,
LogicRuleDto = Mapper.Map<LogicRuleDto>(item.LogicRule),
});
//CanFdDriveService.CmdData.Add(new CanCmdData()
//{
@@ -535,7 +573,7 @@ namespace CapMachine.Wpf.ViewModels
//CANConfigExdDto 数据
SelectedCANConfigExdDto = Mapper.Map<CANFdConfigExdDto>(SelectCanLinConfigPro!.CANFdConfigExd);
if (SelectedCANConfigExdDto!=null)
if (SelectedCANConfigExdDto != null)
{
//更新波特率等配置信息
CanFdDriveService.ToomossCanFDDrive.UpdateConfig((uint)SelectedCANConfigExdDto.ArbBaudRate,
@@ -557,6 +595,7 @@ namespace CapMachine.Wpf.ViewModels
MsgName = item.MsgFrameName,
SignalName = item.SignalName,
SignalCmdValue = double.TryParse(item.DefautValue, out double result) == true ? result : 0,
LogicRuleDto = Mapper.Map<LogicRuleDto>(item.LogicRule),
});
//CanFdDriveService.CmdData.Add(new CanCmdData()
@@ -1084,6 +1123,15 @@ namespace CapMachine.Wpf.ViewModels
set { _ReadNameCbxItems = value; RaisePropertyChanged(); }
}
private ObservableCollection<CbxItems> _WriteRuleCbxItems;
/// <summary>
/// 写入的规格集合
/// </summary>
public ObservableCollection<CbxItems> WriteRuleCbxItems
{
get { return _WriteRuleCbxItems; }
set { _WriteRuleCbxItems = value; RaisePropertyChanged(); }
}
//private string _SelectedWriteName;
///// <summary>
@@ -1199,6 +1247,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,252 @@
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 = new LogicRuleDto();
/// <summary>
/// 当前选中的规则
/// </summary>
public LogicRuleDto SelectedRule
{
get { return _selectedRule; }
set { _selectedRule = value; RaisePropertyChanged(); }
}
/// <summary>
/// 选中更改之前的LogicRuleDto
/// </summary>
public LogicRuleDto SelectedRuleOld { get; set; }
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)
{
//防止需要未更改之前的数据
SelectedRuleOld = selectedItem;
//先判断是否是正确的集合数据防止DataGrid的数据源刷新导致的触发事件
SelectedRule = selectedItem.DeepClone();
}
////选中的行数据
}
/// <summary>
/// 是否编辑
/// </summary>
private bool IsRuleEdit { get; set; } = false;
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)
{
IsRuleEdit = true;
//先判断是否是正确的集合数据防止DataGrid的数据源刷新导致的触发事件
switch (par)
{
case "Create":
//SelectedRule
LogicRuleService.AddRule(Mapper.Map<LogicRule>(SelectedRule));
break;
case "Update":
if (SelectedRule == null)
{
MessageBox.Show("选中后再操作数据");
return;
}
LogicRuleService.UpdateRule(Mapper.Map<LogicRule>(SelectedRuleOld), Mapper.Map<LogicRule>(SelectedRule));
break;
case "Delete":
if (SelectedRule == null)
{
MessageBox.Show("选中后再操作数据");
return;
}
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
{
{ "IsRuleEdit", IsRuleEdit }
};
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");
IsRuleEdit = false;
}
#endregion
}
}

View File

@@ -779,6 +779,18 @@
<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,327 @@
<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="&#xe6f0;" />
<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="&#xe7e4;" />
<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="&#xe9c1;" />
<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="360"
Margin="0"
Padding="5"
AcceptsReturn="True"
Background="#404040"
FontSize="16"
FontWeight="Bold"
Foreground="WhiteSmoke"
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="&#xe8c0;" />
<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="&#xe625;" />
<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="&#xe933;" />
<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();
}
}
}