using System;
using System.Threading.Tasks;
using Prism.Commands;
using Prism.Mvvm;
using XP.Hardware.PLC.Models;
namespace XP.Hardware.PLC.Sentry.ViewModels
{
///
/// 单行信号 ViewModel,封装 SignalEntry 并添加运行时状态 | Single signal row ViewModel wrapping SignalEntry with runtime state
///
public class SignalRowViewModel : BindableBase
{
private readonly SignalEntry _signal;
private string _currentValue = "--";
private bool _hasReadError;
private object _writeValue;
private string _validationError;
///
/// 构造函数 | Constructor
///
/// 信号定义条目 | Signal definition entry
/// 队列写入回调 | Queue write callback
/// 直接写入回调 | Direct write callback
/// 写入命令是否可用判断 | Write command can-execute predicate
public SignalRowViewModel(
SignalEntry signal,
Action applyAction,
Action directWriteAction,
Func canExecuteWrite)
{
_signal = signal ?? throw new ArgumentNullException(nameof(signal));
ApplyCommand = new DelegateCommand(
() => applyAction?.Invoke(this),
() => canExecuteWrite?.Invoke() ?? false);
DirectWriteCommand = new DelegateCommand(
() => directWriteAction?.Invoke(this),
() => canExecuteWrite?.Invoke() ?? false);
}
// === 信号定义信息(只读)| Signal definition info (read-only) ===
///
/// 信号名称 | Signal name
///
public string Name => _signal.Name;
///
/// 数据类型 | Data type
///
public string Type => _signal.Type;
///
/// 起始地址 | Start address
///
public int StartAddr => _signal.StartAddr;
///
/// 长度/索引 | Length/Index
///
public string IndexOrLength => _signal.IndexOrLength;
///
/// 备注 | Remark
///
public string Remark => _signal.Remark;
///
/// DB 块号 | DB block number
///
public int DBNumber => _signal.DBNumber;
///
/// 原始信号定义条目 | Original signal definition entry
///
public SignalEntry Signal => _signal;
///
/// 格式化的地址显示 | Formatted address display
/// bool 类型显示位地址(DB{n}.{addr}.{bit}),其他类型显示字节地址(DB{n}.{addr})
///
public string AddressDisplay => Type?.ToLowerInvariant() == "bool"
? $"DB{DBNumber}.{StartAddr}.{IndexOrLength}"
: $"DB{DBNumber}.{StartAddr}";
// === 运行时状态 | Runtime state ===
///
/// 当前读取值 | Current read value
///
public string CurrentValue
{
get => _currentValue;
set => SetProperty(ref _currentValue, value ?? "--");
}
///
/// 是否存在读取错误 | Whether read error exists
///
public bool HasReadError
{
get => _hasReadError;
set => SetProperty(ref _hasReadError, value);
}
///
/// 写入值 | Write value
///
public object WriteValue
{
get => _writeValue;
set
{
if (SetProperty(ref _writeValue, value))
{
// 写入值变更时清除校验错误 | Clear validation error when write value changes
ValidationError = null;
}
}
}
///
/// 校验错误信息 | Validation error message
///
public string ValidationError
{
get => _validationError;
set => SetProperty(ref _validationError, value);
}
// === 命令 | Commands ===
///
/// 队列写入命令 | Queue write command
///
public DelegateCommand ApplyCommand { get; }
///
/// 直接写入+回读校验命令 | Direct write with verify command
///
public DelegateCommand DirectWriteCommand { get; }
///
/// 刷新写入命令可用状态 | Refresh write command can-execute state
///
public void RefreshCommandState()
{
ApplyCommand.RaiseCanExecuteChanged();
DirectWriteCommand.RaiseCanExecuteChanged();
}
///
/// 校验写入值是否符合信号数据类型要求 | Validate write value against signal data type
///
/// 校验错误信息,null 表示通过 | Validation error message, null means passed
public string ValidateWriteValue()
{
if (WriteValue == null)
return "写入值不能为空 | Write value cannot be empty";
var strValue = WriteValue.ToString();
if (string.IsNullOrWhiteSpace(strValue))
return "写入值不能为空 | Write value cannot be empty";
switch (Type?.ToLowerInvariant())
{
case "bool":
if (!bool.TryParse(strValue, out _))
return "布尔值仅接受 True/False | Bool accepts only True/False";
break;
case "byte":
if (!byte.TryParse(strValue, out _))
return "字节值超出范围 (0-255) | Byte value out of range (0-255)";
break;
case "short":
if (!short.TryParse(strValue, out _))
return "短整型值超出范围 | Short value out of range";
break;
case "int":
if (!int.TryParse(strValue, out _))
return "整型值超出范围 | Int value out of range";
break;
case "single":
if (!float.TryParse(strValue, out _))
return "浮点数格式错误 | Float format error";
break;
case "double":
if (!double.TryParse(strValue, out _))
return "双精度浮点数格式错误 | Double format error";
break;
case "string":
// 字符串接受任意非空值 | String accepts any non-empty value
break;
default:
return $"不支持的类型: {Type} | Unsupported type: {Type}";
}
return null;
}
}
}