From 5e16ca4f41b2ae0b1e0d57be340cbf28286fe1f7 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Mon, 22 Jun 2026 07:21:10 +0800 Subject: feat(manager): implement GUI dashboard with config management --- manager/ProcessWindow.axaml.cs | 104 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 manager/ProcessWindow.axaml.cs (limited to 'manager/ProcessWindow.axaml.cs') diff --git a/manager/ProcessWindow.axaml.cs b/manager/ProcessWindow.axaml.cs new file mode 100644 index 0000000..c11759c --- /dev/null +++ b/manager/ProcessWindow.axaml.cs @@ -0,0 +1,104 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Controls; +using Avalonia.Threading; + +namespace manager; + +public partial class ProcessWindow : Window +{ + private readonly Process _process = new(); + private readonly StringBuilder _output = new(); + + public ProcessWindow() + { + InitializeComponent(); + } + + public ProcessWindow(string fileName, string? arguments = null, string? workingDir = null) + : this() + { + Title = $"{fileName} - Process Output"; + CloseButton.Click += (_, _) => Close(); + + _process.StartInfo = new ProcessStartInfo + { + FileName = fileName, + Arguments = arguments ?? "", + WorkingDirectory = workingDir ?? "", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8, + }; + + _process.EnableRaisingEvents = true; + _process.Exited += (_, _) => + { + _process.WaitForExit(); + Dispatcher.UIThread.Post(() => + { + StatusText.Text = $"Exited (Code: {_process.ExitCode})"; + AppendOutput($"[Process exited, code: {_process.ExitCode}]"); + }); + }; + + StartProcess(); + } + + private async void StartProcess() + { + try + { + StatusText.Text = "Starting..."; + _process.Start(); + + StatusText.Text = $"Running (PID: {_process.Id})"; + + var stdoutTask = ReadStreamAsync(_process.StandardOutput); + var stderrTask = ReadStreamAsync(_process.StandardError); + await Task.WhenAll(stdoutTask, stderrTask); + } + catch (Exception ex) + { + Dispatcher.UIThread.Post(() => + { + AppendOutput($"[Start failed] {ex.Message}"); + StatusText.Text = "Start failed"; + }); + } + } + + private async Task ReadStreamAsync(System.IO.StreamReader reader) + { + var buffer = new char[4096]; + int charsRead; + while ((charsRead = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + var segment = new string(buffer, 0, charsRead); + Dispatcher.UIThread.Post(() => AppendOutput(segment)); + } + } + + private void AppendOutput(string text) + { + _output.Append(text); + OutputText.Text = _output.ToString(); + + OutputScroll.ScrollToEnd(); + } + + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + if (!_process.HasExited) + { + try { _process.Kill(); } catch { } + } + _process.Dispose(); + } +} -- cgit