using Prism.Mvvm; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CapMachine.Wpf.CanDrive { /// /// Dbc 信息 /// public class CanDbcModel : BindableBase { /// /// 消息Id /// public string? MsgId { get; set; } /// /// 配置的中文名称:速度,转速限制,使能等常用的信息数据 /// 但不是所有的SignalName都会配置一个Name,只是需要时才会配置名称 /// 但是CanDbcModel集合会包括所有的SignalName名称的 /// public string? Name { get; set; } /// /// 消息名称 /// public string? MsgName { get; set; } /// /// 信号名称 /// public string? SignalName { get; set; } /// /// 信号描述 /// public string? SignalDesc { get; set; } /// /// 信号单位 /// public string? SignalUnit { get; set; } private string? _SignalRtValue = "--"; /// /// 信号实时值(供 UI 绑定显示)。 /// /// /// - 仅当文本发生变化时才触发通知,避免无谓 UI 刷新。 /// - 若期望进一步降低分配开销,建议在调用方(接收循环)先做“数值层去重”, /// 即:仅在数值变化(可设置容差)时才调用 ToString() 格式化并赋值到本属性。 /// 这样可以显著减少字符串分配与 GC 压力。 /// /// /// // 示例:数值层去重后再格式化(接收循环中使用) /// // if (Math.Abs(newVal - lastVal) > 1e-3) { model.SignalRtValue = newVal.ToString("F3"); lastVal = newVal; } /// public string? SignalRtValue { get { return _SignalRtValue; } set { if (_SignalRtValue != value) { _SignalRtValue = value; RaisePropertyChanged(); } } } private StringBuilder _SignalRtValueSb = new StringBuilder(16); /// /// 信号实时值的可变文本缓冲接口。 /// 设计目的: /// - 避免外部传入的 StringBuilder 被直接保存(引用别名问题),统一复制文本到内部缓冲 _SignalRtValueSb; /// - 仅当文本内容变化时才更新 SignalRtValue 并 RaisePropertyChanged,减少 UI 抖动与无谓刷新; /// - 对 value == null 做防御:清空内部缓冲并置空显示文本(如需显示 “--” 可按需替换)。 /// 使用方式: /// - 接收环路可重复复用同一个外部 StringBuilder 作为临时缓存,调用本属性进行更新不会产生实例共享风险。 /// /// /// 注意事项: /// 1) 本属性会复制文本,不会保存外部 StringBuilder 引用;这可避免多个模型共享同一实例导致的数据串扰和并发问题。 /// 2) 若你的 UI 需要统一的“空值占位符”,可将 setter 中的空字符串替换为 "--",与字段初始值保持一致。 /// 3) 线程模型:建议仍在 UI 线程更新以避免跨线程通知问题;如需后台线程更新,请确保有合适的调度(Dispatcher/同步上下文)。 /// 4) 性能建议:结合 SignalRtValue 的备注,在进入本 setter 前尽量做数值层去重,进一步减少字符串分配。 /// /// /// // 示例:接收循环中复用临时缓存 /// // var tmp = new StringBuilder(32); /// // ... 填充 tmp ... /// // model.SignalRtValueSb = tmp; // 本属性会复制 tmp 的内容,安全且不会产生实例共享 /// public StringBuilder SignalRtValueSb { get { return _SignalRtValueSb; } set { // 防御:若外部传入 null,清空内部状态并复位显示文本 // 注意:此处将显示文本设为空字符串 "",如果希望与初始占位符 "--" 一致,可改为 SignalRtValue = "--"。 if (value == null) { if (_SignalRtValue != string.Empty) { _SignalRtValueSb.Clear(); SignalRtValue = string.Empty; } return; } // 复制策略:不保存外部 StringBuilder 的引用,改为复制其当前文本内容 // 这样可避免多个模型共享同一 StringBuilder 实例导致的数据串扰与线程安全问题 var str = value.ToString(); // 仅当文本内容确实发生变化时,才更新内部缓冲与绑定属性,减少无谓的 UI 刷新与字符串分配 if (!string.Equals(_SignalRtValue, str, StringComparison.Ordinal)) { _SignalRtValueSb.Clear(); _SignalRtValueSb.Append(str); SignalRtValue = str; } } } private int _IsSeletedInfo; /// /// 被选中的信息 /// 方便标注着色 /// public int IsSeletedInfo { get { return _IsSeletedInfo; } set { _IsSeletedInfo = value;RaisePropertyChanged(); } } /// /// 发布者 /// public string? Publisher { get; set; } } }