更新modbus最新
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace COFTester.Models
|
namespace COFTester.Models
|
||||||
{
|
{
|
||||||
@@ -187,6 +188,16 @@ namespace COFTester.Models
|
|||||||
event EventHandler TestFinished; // 測試完成事件
|
event EventHandler TestFinished; // 測試完成事件
|
||||||
event EventHandler<string> ErrorOccurred; // 錯誤發生事件
|
event EventHandler<string> ErrorOccurred; // 錯誤發生事件
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 異步連接到設備
|
||||||
|
/// </summary>
|
||||||
|
Task<bool> ConnectAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 斷開設備連接
|
||||||
|
/// </summary>
|
||||||
|
void Disconnect();
|
||||||
|
|
||||||
void StartAcquisition(TestParameters parameters);
|
void StartAcquisition(TestParameters parameters);
|
||||||
void StopAcquisition();
|
void StopAcquisition();
|
||||||
void ResetSensors();
|
void ResetSensors();
|
||||||
|
|||||||
@@ -185,13 +185,32 @@ namespace COFTester.Services
|
|||||||
{
|
{
|
||||||
private CancellationTokenSource _cts;
|
private CancellationTokenSource _cts;
|
||||||
private bool _isAcquiring;
|
private bool _isAcquiring;
|
||||||
|
private bool _isConnected;
|
||||||
private readonly Random _random = new Random();
|
private readonly Random _random = new Random();
|
||||||
|
|
||||||
public event EventHandler<TestDataPoint> DataReceived;
|
public event EventHandler<TestDataPoint> DataReceived;
|
||||||
public event EventHandler TestFinished;
|
public event EventHandler TestFinished;
|
||||||
public event EventHandler<string> ErrorOccurred;
|
public event EventHandler<string> ErrorOccurred;
|
||||||
|
|
||||||
public bool IsConnected => true; // 模擬始終連接
|
public bool IsConnected => _isConnected;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模擬連接(始終成功)
|
||||||
|
/// </summary>
|
||||||
|
public Task<bool> ConnectAsync()
|
||||||
|
{
|
||||||
|
_isConnected = true;
|
||||||
|
return Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模擬斷開連接
|
||||||
|
/// </summary>
|
||||||
|
public void Disconnect()
|
||||||
|
{
|
||||||
|
StopAcquisition();
|
||||||
|
_isConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
public void StartAcquisition(TestParameters parameters)
|
public void StartAcquisition(TestParameters parameters)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using COFTester.Models;
|
using COFTester.Models;
|
||||||
using COFTester.Services;
|
using COFTester.Services;
|
||||||
using COFTester.Resources;
|
using COFTester.Resources;
|
||||||
@@ -15,48 +16,56 @@ using ScottPlot.WPF;
|
|||||||
|
|
||||||
namespace COFTester.ViewModels
|
namespace COFTester.ViewModels
|
||||||
{
|
{
|
||||||
public class MainViewModel : INotifyPropertyChanged
|
public class MainViewModel : INotifyPropertyChanged, IDisposable
|
||||||
{
|
{
|
||||||
private readonly IDataAcquisitionService _daqService;
|
private readonly IDataAcquisitionService _daqService;
|
||||||
private readonly DataProcessingService _processingService;
|
private readonly DataProcessingService _processingService;
|
||||||
private readonly DispatcherTimer _clockTimer;
|
private readonly DispatcherTimer _clockTimer;
|
||||||
private readonly WpfPlot _wpfPlot;
|
private readonly WpfPlot _wpfPlot;
|
||||||
|
private readonly AppConfig _config;
|
||||||
private ScottPlot.Plottables.Scatter _scatterPlot = null!;
|
private ScottPlot.Plottables.Scatter _scatterPlot = null!;
|
||||||
private readonly Dictionary<Guid, ScottPlot.Plottables.Scatter> _testCurves = new();
|
private readonly Dictionary<Guid, ScottPlot.Plottables.Scatter> _testCurves = new();
|
||||||
|
|
||||||
private double _currentForce;
|
private double _currentForce;
|
||||||
private double _currentDisp;
|
private double _currentDisp;
|
||||||
private bool _isTesting;
|
private bool _isTesting;
|
||||||
|
private bool _isConnecting;
|
||||||
private TestResult? _latestResult;
|
private TestResult? _latestResult;
|
||||||
private string _statusMessage;
|
private string _statusMessage;
|
||||||
private DateTime _currentDateTime = DateTime.Now;
|
private DateTime _currentDateTime = DateTime.Now;
|
||||||
private List<TestDataPoint> _realTimePoints;
|
private List<TestDataPoint> _realTimePoints;
|
||||||
private bool _showAllCurves = true;
|
private bool _showAllCurves = true;
|
||||||
private int _testCounter = 0;
|
private int _testCounter = 0;
|
||||||
|
private bool _disposed = false;
|
||||||
|
|
||||||
public MainViewModel(IDataAcquisitionService daqService, DataProcessingService processingService, WpfPlot wpfPlot)
|
public MainViewModel(IDataAcquisitionService daqService, DataProcessingService processingService, WpfPlot wpfPlot, AppConfig config)
|
||||||
{
|
{
|
||||||
_daqService = daqService;
|
_daqService = daqService ?? throw new ArgumentNullException(nameof(daqService));
|
||||||
_processingService = processingService;
|
_processingService = processingService ?? throw new ArgumentNullException(nameof(processingService));
|
||||||
_wpfPlot = wpfPlot;
|
_wpfPlot = wpfPlot ?? throw new ArgumentNullException(nameof(wpfPlot));
|
||||||
|
_config = config ?? throw new ArgumentNullException(nameof(config));
|
||||||
_realTimePoints = new List<TestDataPoint>();
|
_realTimePoints = new List<TestDataPoint>();
|
||||||
|
|
||||||
// 初始化状态消息
|
// 初始化状态消息
|
||||||
_statusMessage = LanguageResources.Instance.SystemReady;
|
_statusMessage = LanguageResources.Instance.SystemReady;
|
||||||
|
|
||||||
|
// 訂閱數據採集服務事件
|
||||||
_daqService.DataReceived += OnDataReceived;
|
_daqService.DataReceived += OnDataReceived;
|
||||||
_daqService.TestFinished += OnTestFinished;
|
_daqService.TestFinished += OnTestFinished;
|
||||||
_daqService.ErrorOccurred += (s, e) => StatusMessage = string.Format(Lang.Error, e);
|
_daqService.ErrorOccurred += OnErrorOccurred;
|
||||||
|
|
||||||
StartCommand = new RelayCommand(StartTest, () => !_isTesting && _daqService.IsConnected);
|
// 初始化命令
|
||||||
|
ConnectCommand = new AsyncRelayCommand(ConnectAsync, () => !IsConnected && !_isConnecting);
|
||||||
|
DisconnectCommand = new RelayCommand(Disconnect, () => IsConnected && !_isTesting);
|
||||||
|
StartCommand = new RelayCommand(StartTest, () => !_isTesting && IsConnected);
|
||||||
StopCommand = new RelayCommand(StopTest, () => _isTesting);
|
StopCommand = new RelayCommand(StopTest, () => _isTesting);
|
||||||
ResetCommand = new RelayCommand(Reset, () => !_isTesting);
|
ResetCommand = new RelayCommand(Reset, () => !_isTesting && IsConnected);
|
||||||
SwitchLanguageCommand = new RelayCommand(SwitchLanguage);
|
SwitchLanguageCommand = new RelayCommand(SwitchLanguage);
|
||||||
OpenConfigCommand = new RelayCommand(OpenConfig);
|
OpenConfigCommand = new RelayCommand(OpenConfig);
|
||||||
ClearAllTestsCommand = new RelayCommand(ClearAllTests, () => !_isTesting && TestRecords.Count > 0);
|
ClearAllTestsCommand = new RelayCommand(ClearAllTests, () => !_isTesting && TestRecords.Count > 0);
|
||||||
GenerateReportCommand = new RelayCommand(GenerateReport, () => TestRecords.Count > 0);
|
GenerateReportCommand = new RelayCommand(GenerateReport, () => TestRecords.Count > 0);
|
||||||
|
|
||||||
Parameters = new TestParameters();
|
Parameters = _config.DefaultTestParameters ?? new TestParameters();
|
||||||
TestRecords = new ObservableCollection<TestResult>();
|
TestRecords = new ObservableCollection<TestResult>();
|
||||||
TestRecords.CollectionChanged += (s, e) =>
|
TestRecords.CollectionChanged += (s, e) =>
|
||||||
{
|
{
|
||||||
@@ -74,6 +83,16 @@ namespace COFTester.ViewModels
|
|||||||
};
|
};
|
||||||
_clockTimer.Tick += (s, e) => CurrentDateTime = DateTime.Now;
|
_clockTimer.Tick += (s, e) => CurrentDateTime = DateTime.Now;
|
||||||
_clockTimer.Start();
|
_clockTimer.Start();
|
||||||
|
|
||||||
|
// 自動連接(如果是模擬模式則直接連接)
|
||||||
|
if (_config.CommunicationMode?.ToUpper() == "SIMULATED")
|
||||||
|
{
|
||||||
|
StatusMessage = "模擬模式 - 已就緒";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusMessage = $"通信模式: {_config.CommunicationMode} - 請點擊連接";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -186,6 +205,49 @@ namespace COFTester.ViewModels
|
|||||||
|
|
||||||
public TestParameters Parameters { get; set; }
|
public TestParameters Parameters { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 設備連接狀態
|
||||||
|
/// </summary>
|
||||||
|
public bool IsConnected => _daqService.IsConnected;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否正在連接
|
||||||
|
/// </summary>
|
||||||
|
public bool IsConnecting
|
||||||
|
{
|
||||||
|
get => _isConnecting;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isConnecting = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 當前通信模式
|
||||||
|
/// </summary>
|
||||||
|
public string CommunicationMode => _config.CommunicationMode ?? "Unknown";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 連接信息顯示
|
||||||
|
/// </summary>
|
||||||
|
public string ConnectionInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _config.CommunicationMode?.ToUpper() switch
|
||||||
|
{
|
||||||
|
"MODBUSTCP" => $"TCP: {_config.ModbusTcp.IpAddress}:{_config.ModbusTcp.Port}",
|
||||||
|
"MODBUSRTU" => $"RTU: {_config.ModbusRtu.PortName} @ {_config.ModbusRtu.BaudRate}",
|
||||||
|
"MODBUSASCII" => $"ASCII: {_config.ModbusRtu.PortName} @ {_config.ModbusRtu.BaudRate}",
|
||||||
|
"SERIALPORT" => $"串口: {_config.SerialPort.PortName} @ {_config.SerialPort.BaudRate}",
|
||||||
|
"SIMULATED" => "模擬模式",
|
||||||
|
_ => "未知模式"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所有测试记录集合
|
/// 所有测试记录集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -284,6 +346,8 @@ namespace COFTester.ViewModels
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Commands
|
#region Commands
|
||||||
|
public ICommand ConnectCommand { get; }
|
||||||
|
public ICommand DisconnectCommand { get; }
|
||||||
public ICommand StartCommand { get; }
|
public ICommand StartCommand { get; }
|
||||||
public ICommand StopCommand { get; }
|
public ICommand StopCommand { get; }
|
||||||
public ICommand ResetCommand { get; }
|
public ICommand ResetCommand { get; }
|
||||||
@@ -344,12 +408,103 @@ namespace COFTester.ViewModels
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnErrorOccurred(object? sender, string error)
|
||||||
|
{
|
||||||
|
Application.Current?.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
StatusMessage = $"錯誤: {error}";
|
||||||
|
System.Diagnostics.Debug.WriteLine($"[Modbus Error] {error}");
|
||||||
|
|
||||||
|
// 嚴重錯誤時停止測試
|
||||||
|
if (error.Contains("連接") || error.Contains("超時") || error.Contains("Connection"))
|
||||||
|
{
|
||||||
|
if (_isTesting)
|
||||||
|
{
|
||||||
|
IsTesting = false;
|
||||||
|
}
|
||||||
|
OnPropertyChanged(nameof(IsConnected));
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Actions
|
#region Actions
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 異步連接到設備
|
||||||
|
/// </summary>
|
||||||
|
private async Task ConnectAsync()
|
||||||
|
{
|
||||||
|
if (IsConnected || IsConnecting) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsConnecting = true;
|
||||||
|
StatusMessage = $"正在連接 {ConnectionInfo}...";
|
||||||
|
|
||||||
|
bool connected = await _daqService.ConnectAsync();
|
||||||
|
|
||||||
|
if (connected)
|
||||||
|
{
|
||||||
|
StatusMessage = $"已連接 - {ConnectionInfo}";
|
||||||
|
OnPropertyChanged(nameof(IsConnected));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusMessage = "連接失敗,請檢查設備和配置";
|
||||||
|
MessageBox.Show(
|
||||||
|
$"無法連接到設備\n\n通信模式: {CommunicationMode}\n連接信息: {ConnectionInfo}\n\n請檢查:\n1. 設備是否已開機\n2. 連接線是否正確\n3. 配置參數是否正確",
|
||||||
|
"連接失敗",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StatusMessage = $"連接錯誤: {ex.Message}";
|
||||||
|
MessageBox.Show($"連接時發生錯誤:\n{ex.Message}", "錯誤", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsConnecting = false;
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 斷開設備連接
|
||||||
|
/// </summary>
|
||||||
|
private void Disconnect()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_isTesting)
|
||||||
|
{
|
||||||
|
StopTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
_daqService.Disconnect();
|
||||||
|
StatusMessage = "已斷開連接";
|
||||||
|
OnPropertyChanged(nameof(IsConnected));
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StatusMessage = $"斷開連接錯誤: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void StartTest()
|
private void StartTest()
|
||||||
{
|
{
|
||||||
|
if (!IsConnected)
|
||||||
|
{
|
||||||
|
StatusMessage = "請先連接設備";
|
||||||
|
MessageBox.Show("請先連接設備後再開始測試", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_realTimePoints.Clear();
|
_realTimePoints.Clear();
|
||||||
OnPropertyChanged(nameof(DataPointsCount));
|
OnPropertyChanged(nameof(DataPointsCount));
|
||||||
LatestResult = null;
|
LatestResult = null;
|
||||||
@@ -568,6 +723,55 @@ namespace COFTester.ViewModels
|
|||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// 停止時鐘
|
||||||
|
_clockTimer?.Stop();
|
||||||
|
|
||||||
|
// 取消訂閱事件
|
||||||
|
if (_daqService != null)
|
||||||
|
{
|
||||||
|
_daqService.DataReceived -= OnDataReceived;
|
||||||
|
_daqService.TestFinished -= OnTestFinished;
|
||||||
|
_daqService.ErrorOccurred -= OnErrorOccurred;
|
||||||
|
|
||||||
|
// 停止測試
|
||||||
|
if (_isTesting)
|
||||||
|
{
|
||||||
|
_daqService.StopAcquisition();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 斷開連接
|
||||||
|
_daqService.Disconnect();
|
||||||
|
|
||||||
|
// 釋放服務資源
|
||||||
|
if (_daqService is IDisposable disposable)
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~MainViewModel()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -602,4 +806,53 @@ namespace COFTester.ViewModels
|
|||||||
// 自動觸發 CanExecuteChanged
|
// 自動觸發 CanExecuteChanged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 異步 RelayCommand 實現,用於異步操作(如連接設備)
|
||||||
|
/// </summary>
|
||||||
|
public class AsyncRelayCommand : ICommand
|
||||||
|
{
|
||||||
|
private readonly Func<Task> _execute;
|
||||||
|
private readonly Func<bool>? _canExecute;
|
||||||
|
private bool _isExecuting;
|
||||||
|
|
||||||
|
public AsyncRelayCommand(Func<Task> execute, Func<bool>? canExecute = null)
|
||||||
|
{
|
||||||
|
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
|
||||||
|
_canExecute = canExecute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanExecute(object? parameter)
|
||||||
|
{
|
||||||
|
return !_isExecuting && (_canExecute?.Invoke() ?? true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Execute(object? parameter)
|
||||||
|
{
|
||||||
|
if (!CanExecute(parameter)) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_isExecuting = true;
|
||||||
|
RaiseCanExecuteChanged();
|
||||||
|
await _execute();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isExecuting = false;
|
||||||
|
RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler? CanExecuteChanged;
|
||||||
|
|
||||||
|
private void RaiseCanExecuteChanged()
|
||||||
|
{
|
||||||
|
Application.Current?.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,40 @@
|
|||||||
<Border Style="{StaticResource CardStyle}" Margin="5,10,5,5">
|
<Border Style="{StaticResource CardStyle}" Margin="5,10,5,5">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock Text="{Binding Lang.TestControl}" FontWeight="Bold" Margin="0,0,0,10" Foreground="{StaticResource GrayBrush}"/>
|
<TextBlock Text="{Binding Lang.TestControl}" FontWeight="Bold" Margin="0,0,0,10" Foreground="{StaticResource GrayBrush}"/>
|
||||||
|
|
||||||
|
<!-- 連接控制 -->
|
||||||
|
<Grid Margin="0,0,0,10">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button Grid.Column="0" Content="連接" Command="{Binding ConnectCommand}" Height="36" Foreground="White" FontSize="12" Margin="0,0,3,0">
|
||||||
|
<Button.Style>
|
||||||
|
<Style TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="#27AE60"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
</Button>
|
||||||
|
<Button Grid.Column="1" Content="斷開" Command="{Binding DisconnectCommand}" Height="36" Foreground="White" FontSize="12" Margin="3,0,0,0">
|
||||||
|
<Button.Style>
|
||||||
|
<Style TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="#95A5A6"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 連接狀態顯示 -->
|
||||||
|
<Border Background="#F8F9FA" CornerRadius="4" Padding="8" Margin="0,0,0,10">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{Binding ConnectionInfo}" FontSize="11" Foreground="{StaticResource GrayBrush}" TextWrapping="Wrap"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
<Button Content="{Binding Lang.StartTest}" Command="{Binding StartCommand}" Height="50" Foreground="White" FontWeight="Bold" Margin="0,5" FontSize="16">
|
<Button Content="{Binding Lang.StartTest}" Command="{Binding StartCommand}" Height="50" Foreground="White" FontWeight="Bold" Margin="0,5" FontSize="16">
|
||||||
<Button.Style>
|
<Button.Style>
|
||||||
<Style TargetType="Button">
|
<Style TargetType="Button">
|
||||||
@@ -331,14 +365,42 @@
|
|||||||
<StatusBarItem>
|
<StatusBarItem>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Ellipse Width="8" Height="8" Margin="0,0,5,0">
|
<Ellipse Width="8" Height="8" Margin="0,0,5,0">
|
||||||
<Ellipse.Fill>
|
<Ellipse.Style>
|
||||||
<SolidColorBrush Color="#27AE60"/>
|
<Style TargetType="Ellipse">
|
||||||
</Ellipse.Fill>
|
<Setter Property="Fill" Value="#E74C3C"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||||
|
<Setter Property="Fill" Value="#27AE60"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Ellipse.Style>
|
||||||
</Ellipse>
|
</Ellipse>
|
||||||
<TextBlock Text="{Binding Lang.PLCConnected}" Foreground="{StaticResource SuccessBrush}"/>
|
<TextBlock>
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="TextBlock">
|
||||||
|
<Setter Property="Text" Value="未連接"/>
|
||||||
|
<Setter Property="Foreground" Value="#E74C3C"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||||
|
<Setter Property="Text" Value="已連接"/>
|
||||||
|
<Setter Property="Foreground" Value="#27AE60"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding IsConnecting}" Value="True">
|
||||||
|
<Setter Property="Text" Value="連接中..."/>
|
||||||
|
<Setter Property="Foreground" Value="#F39C12"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="{Binding CommunicationMode}" Foreground="{StaticResource GrayBrush}" FontSize="11"/>
|
||||||
|
</StatusBarItem>
|
||||||
|
<Separator/>
|
||||||
<StatusBarItem>
|
<StatusBarItem>
|
||||||
<TextBlock Foreground="{StaticResource GrayBrush}">
|
<TextBlock Foreground="{StaticResource GrayBrush}">
|
||||||
<Run Text="{Binding Lang.DataPointsCount, Mode=OneWay}"/>
|
<Run Text="{Binding Lang.DataPointsCount, Mode=OneWay}"/>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using COFTester.ViewModels;
|
using COFTester.ViewModels;
|
||||||
using COFTester.Services;
|
using COFTester.Services;
|
||||||
|
using COFTester.Models;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace COFTester.Views
|
namespace COFTester.Views
|
||||||
@@ -9,22 +10,29 @@ namespace COFTester.Views
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
|
private readonly MainViewModel _viewModel;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// 實例化服務
|
// 加載配置
|
||||||
var daqService = new SimulatedDataAcquisitionService();
|
var config = AppConfig.Load(AppConfig.GetDefaultConfigPath());
|
||||||
|
|
||||||
|
// 根據配置創建數據採集服務(支持 Modbus TCP/RTU/ASCII 和模擬模式)
|
||||||
|
IDataAcquisitionService daqService = ModbusServiceFactory.CreateService(config);
|
||||||
var processingService = new DataProcessingService();
|
var processingService = new DataProcessingService();
|
||||||
|
|
||||||
// 設置 DataContext
|
// 設置 DataContext
|
||||||
var viewModel = new MainViewModel(daqService, processingService, FrictionPlot);
|
_viewModel = new MainViewModel(daqService, processingService, FrictionPlot, config);
|
||||||
this.DataContext = viewModel;
|
this.DataContext = _viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Click(object sender, RoutedEventArgs e)
|
protected override void OnClosed(System.EventArgs e)
|
||||||
{
|
{
|
||||||
|
// 清理資源
|
||||||
|
_viewModel?.Dispose();
|
||||||
|
base.OnClosed(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user