143 lines
4.2 KiB
C#
143 lines
4.2 KiB
C#
using MembranePoreTester.Communication;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace MembranePoreTester.ViewModels
|
|
{
|
|
public class ViewModelBase : INotifyPropertyChanged, IDisposable
|
|
{
|
|
private bool _disposed = false;
|
|
protected CancellationTokenSource _cts = new CancellationTokenSource();
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
|
|
{
|
|
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
|
field = value;
|
|
OnPropertyChanged(propertyName);
|
|
return true;
|
|
}
|
|
|
|
protected async Task WriteFloatAsync(ushort address, float value)
|
|
{
|
|
byte[] bytes = BitConverter.GetBytes(value);
|
|
if (BitConverter.IsLittleEndian) Array.Reverse(bytes);
|
|
ushort high = (ushort)((bytes[0] << 8) | bytes[1]);
|
|
ushort low = (ushort)((bytes[2] << 8) | bytes[3]);
|
|
await App.PlcService.WriteSingleRegisterAsync(address, high);
|
|
await App.PlcService.WriteSingleRegisterAsync((ushort)(address + 1), low);
|
|
}
|
|
|
|
// 新增:安全执行异步方法(自动处理对象释放)
|
|
protected async Task SafeExecuteAsync(Func<Task> action)
|
|
{
|
|
if (_disposed) return;
|
|
try
|
|
{
|
|
await action();
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// 正常取消
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"异步执行失败: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public bool IsInDesignMode()
|
|
{
|
|
return System.ComponentModel.DesignerProperties.GetIsInDesignMode(
|
|
new System.Windows.DependencyObject());
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ========== 错误抑制机制 ==========
|
|
private class ErrorRecord
|
|
{
|
|
public bool HasError { get; set; }
|
|
public DateTime LastErrorTime { get; set; }
|
|
}
|
|
|
|
private readonly Dictionary<string, ErrorRecord> _errorRecords = new();
|
|
|
|
/// <summary>
|
|
/// 安全执行异步操作,自动抑制重复错误
|
|
/// </summary>
|
|
protected async Task<bool> SafeExecuteAsync(string operationKey, Func<Task> action, int suppressSeconds = 3)
|
|
{
|
|
// 检查是否需要抑制
|
|
if (_errorRecords.TryGetValue(operationKey, out var record) && record.HasError)
|
|
{
|
|
if ((DateTime.Now - record.LastErrorTime).TotalSeconds < suppressSeconds)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
await action();
|
|
|
|
// 成功,清除错误记录
|
|
if (_errorRecords.TryGetValue(operationKey, out var successRecord))
|
|
{
|
|
successRecord.HasError = false;
|
|
}
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// 记录错误
|
|
if (!_errorRecords.TryGetValue(operationKey, out var errorRecord))
|
|
{
|
|
errorRecord = new ErrorRecord();
|
|
_errorRecords[operationKey] = errorRecord;
|
|
}
|
|
|
|
errorRecord.HasError = true;
|
|
errorRecord.LastErrorTime = DateTime.Now;
|
|
|
|
// 静默记录到输出窗口
|
|
Debug.WriteLine($"[{DateTime.Now:HH:mm:ss}] {operationKey} 失败: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 新增:检查是否已释放
|
|
protected bool IsDisposed => _disposed;
|
|
|
|
public virtual void Dispose()
|
|
{
|
|
if (_disposed) return;
|
|
_disposed = true;
|
|
_cts?.Cancel();
|
|
_cts?.Dispose();
|
|
_cts = null;
|
|
}
|
|
}
|
|
} |