using System; using System.Collections.Generic; using System.Diagnostics; using System.Net.NetworkInformation; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.Media; using Sln.Wcs.UI.ViewModels; namespace Sln.Wcs.UI.Views; public partial class MainWindow : Window { private readonly NavigationViewModel _navVm; private readonly List _openPopups = new(); private readonly Process _currentProcess; private TimeSpan _lastCpuTime; private DateTime _lastCpuCheck; private readonly DateTime _startTime; public MainWindow(NavigationViewModel navigationVm) { InitializeComponent(); _navVm = navigationVm; DataContext = _navVm; _navVm.PageChanged += OnPageChanged; BuildMenu(); _navVm.LoadDefaultPage(); _currentProcess = Process.GetCurrentProcess(); _lastCpuTime = _currentProcess.TotalProcessorTime; _lastCpuCheck = DateTime.UtcNow; _startTime = DateTime.UtcNow; // 时钟 var timer = new System.Timers.Timer(1000); timer.Elapsed += (_, _) => Avalonia.Threading.Dispatcher.UIThread.Post(() => { ClockText.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); RefreshSystemStatus(); }); timer.Start(); ClockText.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // 退出按钮 LogoutBtn.Click += (_, _) => Close(); } private void RefreshSystemStatus() { // CPU usage var now = DateTime.UtcNow; var currentCpuTime = _currentProcess.TotalProcessorTime; var cpuUsedMs = (currentCpuTime - _lastCpuTime).TotalMilliseconds; var elapsedMs = (now - _lastCpuCheck).TotalMilliseconds; _lastCpuTime = currentCpuTime; _lastCpuCheck = now; var cpuPercent = elapsedMs > 0 ? cpuUsedMs / elapsedMs / Environment.ProcessorCount * 100.0 : 0.0; CpuUsageText.Text = $"{cpuPercent:F1}%"; // CPU indicator color var cpuColor = cpuPercent switch { < 50 => "#00E676", < 80 => "#FFB74D", _ => "#FF5252" }; CpuStatusDot.Fill = Brush.Parse(cpuColor); // Memory usage var memBytes = _currentProcess.WorkingSet64; var memMB = memBytes / 1024.0 / 1024.0; MemUsageText.Text = memMB >= 1024 ? $"{memMB / 1024.0:F1} GB" : $"{memMB:F0} MB"; // Memory indicator color var memColor = memMB switch { < 512 => "#00E676", < 1024 => "#FFB74D", _ => "#FF5252" }; MemStatusDot.Fill = Brush.Parse(memColor); // Network status var isNetworkAvailable = NetworkInterface.GetIsNetworkAvailable(); var activeInterface = false; if (isNetworkAvailable) { foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) { if (ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback) { activeInterface = true; break; } } } NetStatusDot.Fill = Brush.Parse(activeInterface ? "#00E676" : "#FF5252"); NetStatusText.Text = activeInterface ? "已连接" : "未连接"; // Uptime var uptime = DateTime.UtcNow - _startTime; UptimeText.Text = uptime.TotalDays >= 1 ? $"{(int)uptime.TotalDays}d {uptime.Hours:D2}:{uptime.Minutes:D2}:{uptime.Seconds:D2}" : $"{uptime.Hours:D2}:{uptime.Minutes:D2}:{uptime.Seconds:D2}"; } private void BuildMenu() { MenuContainer.Children.Clear(); foreach (var item in _navVm.TopMenuItems) { var btn = new Button { Content = item.Label, Background = Brushes.Transparent, Foreground = Brush.Parse("#8B9BB5"), FontSize = 13, Padding = new Thickness(14, 12), Cursor = new Cursor(StandardCursorType.Hand), BorderThickness = new Thickness(0), }; if (item.Action != null) { btn.Click += (_, _) => item.Action(); } if (item.Children != null && item.Children.Count > 0) { var popup = new Popup { PlacementTarget = btn, Placement = PlacementMode.Bottom, IsLightDismissEnabled = false, }; var popupBorder = new Border { Background = Brush.Parse("#0F1620"), BorderBrush = Brush.Parse("#1A2F4A"), BorderThickness = new Thickness(1), CornerRadius = new CornerRadius(4), MinWidth = 160, }; var stack = new StackPanel { Margin = new Thickness(4) }; foreach (var sub in item.Children) { var subBtn = new Button { Content = sub.Label, Background = Brushes.Transparent, Foreground = Brush.Parse("#8B9BB5"), FontSize = 12, HorizontalAlignment = HorizontalAlignment.Stretch, HorizontalContentAlignment = HorizontalAlignment.Left, Padding = new Thickness(12, 8), BorderThickness = new Thickness(0), Cursor = new Cursor(StandardCursorType.Hand), }; subBtn.Click += (_, _) => { popup.Close(); sub.Action(); }; subBtn.PointerEntered += (_, _) => subBtn.Background = Brush.Parse("#1B3A5C"); subBtn.PointerExited += (_, _) => subBtn.Background = Brushes.Transparent; stack.Children.Add(subBtn); } popupBorder.Child = stack; popup.Child = popupBorder; // Hover 展开,离开按钮或 popup 时关闭 var closeTimer = new System.Timers.Timer(200) { AutoReset = false }; bool mouseInPopup = false; bool mouseInButton = false; popupBorder.PointerEntered += (_, _) => { mouseInPopup = true; closeTimer.Stop(); }; popupBorder.PointerExited += (_, _) => { mouseInPopup = false; TryClose(); }; btn.PointerEntered += (_, _) => { mouseInButton = true; closeTimer.Stop(); btn.Background = Brush.Parse("#1B3A5C"); btn.Foreground = Brush.Parse("#4FC3F7"); CloseAllPopups(); popup.Open(); }; btn.PointerExited += (_, _) => { mouseInButton = false; TryClose(); }; void TryClose() { closeTimer.Stop(); closeTimer.Start(); closeTimer.Elapsed += (_, _) => { Avalonia.Threading.Dispatcher.UIThread.Post(() => { if (!mouseInButton && !mouseInPopup) { popup.Close(); } }); }; } popup.Closed += (_, _) => { btn.Background = Brushes.Transparent; btn.Foreground = Brush.Parse("#8B9BB5"); }; _openPopups.Add(popup); } else { btn.PointerEntered += (_, _) => { btn.Background = Brush.Parse("#1B3A5C"); btn.Foreground = Brush.Parse("#4FC3F7"); }; btn.PointerExited += (_, _) => { btn.Background = Brushes.Transparent; btn.Foreground = Brush.Parse("#8B9BB5"); }; } MenuContainer.Children.Add(btn); } } private void CloseAllPopups() { foreach (var p in _openPopups) p.Close(); } private void OnPageChanged(Control? view) { if (view != null) { view.HorizontalAlignment = HorizontalAlignment.Stretch; view.VerticalAlignment = VerticalAlignment.Stretch; ContentArea.Child = view; } } }