diff --git a/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor b/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor
index 022349d..df2137d 100644
--- a/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor
+++ b/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor
@@ -4,6 +4,7 @@
@using IOModuleTestBlazor.Services
@inject ISerialPortService SerialService
+@inject IJSRuntime JS
Serial Terminal
@@ -122,6 +123,8 @@
private string? _connectError;
private List _availablePorts = new();
private List _displayLines = new();
+ private IJSObjectReference? _jsModule;
+ private bool _scrollPending = false;
private static readonly (string Label, string Cmd)[] _quickCommands =
[
@@ -188,15 +191,30 @@
InvokeAsync(() =>
{
RefreshLines();
+ _scrollPending = true;
StateHasChanged();
});
}
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if (firstRender)
+ _jsModule = await JS.InvokeAsync(
+ "import", "./Components/Pages/SerialTerminal.razor.js");
+
+ if (_scrollPending && _jsModule is not null)
+ {
+ _scrollPending = false;
+ await _jsModule.InvokeVoidAsync("scrollToBottom", "terminal-output");
+ }
+ }
+
private void RefreshLines()
=> _displayLines = SerialService.GetLines().ToList();
private void ClearTerminal()
{
+ SerialService.ClearLines();
_displayLines.Clear();
StateHasChanged();
}
@@ -205,5 +223,8 @@
=> string.Join("\n", _displayLines);
public void Dispose()
- => SerialService.DataReceived -= OnDataReceived;
+ {
+ SerialService.DataReceived -= OnDataReceived;
+ _jsModule?.DisposeAsync();
+ }
}
diff --git a/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor.js b/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor.js
new file mode 100644
index 0000000..7dd5524
--- /dev/null
+++ b/IOModuleTestBlazor/Components/Pages/SerialTerminal.razor.js
@@ -0,0 +1,4 @@
+export function scrollToBottom(elementId) {
+ const el = document.getElementById(elementId);
+ if (el) el.scrollTop = el.scrollHeight;
+}
diff --git a/IOModuleTestBlazor/Services/ISerialPortService.cs b/IOModuleTestBlazor/Services/ISerialPortService.cs
index e0c8939..fc8d2ba 100644
--- a/IOModuleTestBlazor/Services/ISerialPortService.cs
+++ b/IOModuleTestBlazor/Services/ISerialPortService.cs
@@ -21,6 +21,9 @@ public interface ISerialPortService
/// Each line is prefixed with "> " (sent) or "< " (received).
IReadOnlyList GetLines();
+ /// Clears the line buffer.
+ void ClearLines();
+
/// Fired on the SerialPort receive thread when new lines arrive.
event Action? DataReceived;
}
diff --git a/IOModuleTestBlazor/Services/SerialPortService.cs b/IOModuleTestBlazor/Services/SerialPortService.cs
index b033b4c..e5585da 100644
--- a/IOModuleTestBlazor/Services/SerialPortService.cs
+++ b/IOModuleTestBlazor/Services/SerialPortService.cs
@@ -97,6 +97,12 @@ public sealed class SerialPortService : ISerialPortService, IDisposable
return _lines.ToList();
}
+ public void ClearLines()
+ {
+ lock (_lock)
+ _lines.Clear();
+ }
+
private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort? port;