@page "/can" @inject ICanService CanService @implements IDisposable
CAN Monitor (Live View)
@foreach (var msg in messages.Values.OrderBy(m => m.Id)) { }
Time CAN-ID Meaning Length Raw Data Result
@msg.Timestamp.ToString("HH:mm:ss.fff") @msg.Id.ToString("X3") @msg.Meaning @msg.Length @BitConverter.ToString( msg.Data.Take(msg.Length).ToArray()) @msg.ValueText
@code { // DATA STORAGE (1 ID = 1 ROW) private Dictionary messages = new(); private bool isRunning = false; private string status = "STOPPED"; // INIT protected override void OnInitialized() { CanService.OnMessageReceived += OnCanMessage; } // RECEIVE CAN FRAME private void OnCanMessage(CanMessage msg) { InvokeAsync(() => { // 🔴 Update data on the SAME row by CAN-ID messages[msg.Id] = msg; StateHasChanged(); }); } // START private async Task Start() { if (isRunning) return; status = "INITIALIZING..."; StateHasChanged(); await CanService.InitAsync(); // BẮT BUỘC CanService.StartStream(); isRunning = true; status = "RUNNING"; } // STOP private void Stop() { if (!isRunning) return; CanService.StopStream(); isRunning = false; status = "STOPPED"; } // CLEANUP public void Dispose() { CanService.OnMessageReceived -= OnCanMessage; CanService.StopStream(); } }