修复性能监控页面
曲线增加 Y 轴百分比刻度:0%、25%、50%、75%、100% 增加 X 轴时间刻度:-60 秒、-30 秒、现在 CPU、内存、磁盘曲线统一坐标范围 修复磁盘曲线区域高度为 0 的问题 磁盘历史数据改为直接使用数值百分比,避免字符串解析失败
This commit is contained in:
@@ -110,7 +110,7 @@ namespace XplorePlane.ViewModels.Diagnostics
|
||||
AddSample(MemoryHistory, MemoryUsage);
|
||||
var totalMemory = memory.TotalPhys == 0 ? 0 : (double)_process.WorkingSet64 / memory.TotalPhys * 100;
|
||||
AddSample(ProcessMemoryHistory, totalMemory);
|
||||
AddSample(DiskHistory, Disks.Count == 0 ? 0 : Disks.Max(d => double.TryParse(d.Usage.TrimEnd('%'), out var value) ? value : 0));
|
||||
AddSample(DiskHistory, Disks.Count == 0 ? 0 : Disks.Max(d => d.UsagePercent));
|
||||
LastUpdatedText = $"更新于 {DateTime.Now:HH:mm:ss}";
|
||||
OverallStatus = HasAlerts ? $"{Alerts.Count} 项告警" : "系统正常";
|
||||
RaisePropertyChanged(nameof(LastUpdatedText));
|
||||
@@ -156,7 +156,7 @@ namespace XplorePlane.ViewModels.Diagnostics
|
||||
var total = drive.TotalSize; var free = drive.AvailableFreeSpace;
|
||||
var usage = total <= 0 ? 0 : (double)(total - free) / total * 100;
|
||||
var status = free < 5L * 1024 * 1024 * 1024 || usage >= 95 ? "严重" : free < 10L * 1024 * 1024 * 1024 || usage >= 90 ? "警告" : free < 20L * 1024 * 1024 * 1024 || usage >= 80 ? "注意" : "正常";
|
||||
Disks.Add(new DiskUsageRow { Drive = drive.Name, Total = FormatBytes(total), Used = FormatBytes(total - free), Free = FormatBytes(free), Usage = $"{usage:F0}%", Purpose = pair.Value, Status = status });
|
||||
Disks.Add(new DiskUsageRow { Drive = drive.Name, Total = FormatBytes(total), Used = FormatBytes(total - free), Free = FormatBytes(free), Usage = $"{usage:F0}%", UsagePercent = usage, Purpose = pair.Value, Status = status });
|
||||
if (status != "正常") Alerts.Add($"{drive.Name} 剩余空间 {FormatBytes(free)},状态:{status}。建议清理历史数据。");
|
||||
}
|
||||
catch (Exception ex) { _logger.Warn("读取磁盘信息失败:{Path},{Message}", pair.Key, ex.Message); }
|
||||
@@ -185,6 +185,7 @@ namespace XplorePlane.ViewModels.Diagnostics
|
||||
public string Used { get; init; } = string.Empty;
|
||||
public string Free { get; init; } = string.Empty;
|
||||
public string Usage { get; init; } = string.Empty;
|
||||
public double UsagePercent { get; init; }
|
||||
public string Purpose { get; init; } = string.Empty;
|
||||
public string Status { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
@@ -41,19 +42,33 @@ namespace XplorePlane.Views.Diagnostics
|
||||
base.OnRender(drawingContext);
|
||||
var rect = new Rect(0, 0, ActualWidth, ActualHeight);
|
||||
drawingContext.DrawRectangle(Background ?? Brushes.Transparent, null, rect);
|
||||
const double left = 38;
|
||||
const double bottom = 22;
|
||||
var plot = new Rect(left, 4, Math.Max(0, ActualWidth - left - 4), Math.Max(0, ActualHeight - bottom - 4));
|
||||
var gridPen = new Pen(new SolidColorBrush(Color.FromArgb(45, 80, 100, 120)), 1);
|
||||
for (var i = 1; i < 4; i++) drawingContext.DrawLine(gridPen, new Point(0, rect.Height * i / 4), new Point(rect.Width, rect.Height * i / 4));
|
||||
DrawSeries(drawingContext, Values, LineBrush);
|
||||
DrawSeries(drawingContext, SecondaryValues, SecondaryLineBrush);
|
||||
var labelBrush = new SolidColorBrush(Color.FromArgb(170, 55, 65, 75));
|
||||
for (var i = 0; i <= 4; i++)
|
||||
{
|
||||
var y = plot.Top + plot.Height * i / 4;
|
||||
drawingContext.DrawLine(gridPen, new Point(plot.Left, y), new Point(plot.Right, y));
|
||||
DrawText(drawingContext, $"{100 - i * 25}%", new Point(0, y - 7), labelBrush);
|
||||
}
|
||||
drawingContext.DrawLine(new Pen(labelBrush, 1), new Point(plot.Left, plot.Top), new Point(plot.Left, plot.Bottom));
|
||||
drawingContext.DrawLine(new Pen(labelBrush, 1), new Point(plot.Left, plot.Bottom), new Point(plot.Right, plot.Bottom));
|
||||
DrawText(drawingContext, "-60 秒", new Point(plot.Left, plot.Bottom + 3), labelBrush);
|
||||
DrawText(drawingContext, "-30 秒", new Point(plot.Left + plot.Width / 2 - 15, plot.Bottom + 3), labelBrush);
|
||||
DrawText(drawingContext, "现在", new Point(plot.Right - 22, plot.Bottom + 3), labelBrush);
|
||||
DrawSeries(drawingContext, Values, LineBrush, plot);
|
||||
DrawSeries(drawingContext, SecondaryValues, SecondaryLineBrush, plot);
|
||||
}
|
||||
|
||||
private void DrawSeries(DrawingContext dc, ObservableCollection<double> values, Brush brush)
|
||||
private void DrawSeries(DrawingContext dc, ObservableCollection<double> values, Brush brush, Rect plot)
|
||||
{
|
||||
if (values == null || values.Count == 0 || ActualWidth <= 0 || ActualHeight <= 0) return;
|
||||
if (values.Count > 0) Trace.WriteLine($"[PERF-CHART] 绘制曲线:点数={values.Count},尺寸={ActualWidth:F0}x{ActualHeight:F0}");
|
||||
if (values == null || values.Count == 0 || plot.Width <= 0 || plot.Height <= 0) return;
|
||||
if (values.Count > 0) Trace.WriteLine($"[PERF-CHART] 绘制曲线:点数={values.Count},绘图区={plot.Width:F0}x{plot.Height:F0}");
|
||||
var points = values.Select((value, index) => new Point(
|
||||
values.Count == 1 ? ActualWidth / 2 : index * ActualWidth / Math.Max(1, values.Count - 1),
|
||||
ActualHeight - Math.Clamp(value, 0, 100) / 100 * ActualHeight)).ToArray();
|
||||
values.Count == 1 ? plot.Left + plot.Width / 2 : plot.Left + index * plot.Width / Math.Max(1, values.Count - 1),
|
||||
plot.Bottom - Math.Clamp(value, 0, 100) / 100 * plot.Height)).ToArray();
|
||||
if (points.Length == 1)
|
||||
{
|
||||
dc.DrawEllipse(brush ?? Brushes.DeepSkyBlue, null, points[0], 3, 3);
|
||||
@@ -68,6 +83,13 @@ namespace XplorePlane.Views.Diagnostics
|
||||
dc.DrawGeometry(null, new Pen(brush ?? Brushes.DeepSkyBlue, 2), geometry);
|
||||
}
|
||||
|
||||
private static void DrawText(DrawingContext dc, string text, Point origin, Brush brush)
|
||||
{
|
||||
var formatted = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
|
||||
new Typeface("Segoe UI"), 10, brush, 1.0);
|
||||
dc.DrawText(formatted, origin);
|
||||
}
|
||||
|
||||
private static void OnValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var chart = (PerformanceChart)d;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<GroupBox Grid.Column="0" Header="CPU 使用率" Margin="0,0,8,0"><local:PerformanceChart Values="{Binding CpuHistory}" LineBrush="{StaticResource NovaPrimaryBrush}" Background="{StaticResource NovaSurfaceContainerLowBrush}" Margin="10,8"/></GroupBox>
|
||||
<GroupBox Grid.Column="1" Header="内存使用率(系统 / XP 进程)" Margin="8,0,0,0"><local:PerformanceChart Values="{Binding MemoryHistory}" SecondaryValues="{Binding ProcessMemoryHistory}" LineBrush="{StaticResource NovaInfoBrush}" SecondaryLineBrush="{StaticResource NovaTertiaryBrush}" Background="{StaticResource NovaSurfaceContainerLowBrush}" Margin="10,8"/></GroupBox>
|
||||
</Grid>
|
||||
<GroupBox Grid.Row="3" Header="磁盘使用率" Margin="0,0,0,16"><local:PerformanceChart Values="{Binding DiskHistory}" LineBrush="{StaticResource NovaWarningBrush}" Background="{StaticResource NovaSurfaceContainerLowBrush}" Margin="10,8"/></GroupBox>
|
||||
<GroupBox Grid.Row="3" Header="磁盘使用率" Margin="0,0,0,16"><local:PerformanceChart Values="{Binding DiskHistory}" LineBrush="{StaticResource NovaWarningBrush}" Background="{StaticResource NovaSurfaceContainerLowBrush}" Height="132" Margin="10,8"/></GroupBox>
|
||||
<GroupBox Grid.Row="4" Header="当前告警" Margin="0,0,0,16" Visibility="{Binding HasAlerts, Converter={StaticResource BooleanToVisibilityConverter}}"><ItemsControl ItemsSource="{Binding Alerts}"><ItemsControl.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal" Margin="4"><TextBlock Text="⚠" Foreground="{StaticResource NovaWarningBrush}" Margin="0,0,6,0"/><TextBlock Text="{Binding}" Foreground="{StaticResource NovaWarningBrush}" TextWrapping="Wrap"/></StackPanel></DataTemplate></ItemsControl.ItemTemplate></ItemsControl></GroupBox>
|
||||
<TextBlock Grid.Row="5" Text="磁盘空间不足时,XP 将提前提示用户清理相关数据。" Foreground="{StaticResource NovaOnSurfaceVariantBrush}" VerticalAlignment="Top"/>
|
||||
</Grid>
|
||||
|
||||
@@ -802,14 +802,6 @@
|
||||
Command="{Binding OpenDebugPanelCommand}"
|
||||
Text="{loc:Localization Key=Main_DebugPanel}" />
|
||||
<telerik:RadRibbonButton
|
||||
telerik:ScreenTip.Description="查看 CPU、内存和磁盘空间使用情况"
|
||||
telerik:ScreenTip.Title="性能监控"
|
||||
Command="{Binding OpenPerformanceMonitorCommand}"
|
||||
Size="Large"
|
||||
LargeImage="/Assets/Icons/tools.png"
|
||||
SmallImage="/Assets/Icons/tools.png"
|
||||
Text="性能监控" />
|
||||
<telerik:RadRibbonButton
|
||||
telerik:ScreenTip.Description="打开检测报告配置窗口"
|
||||
telerik:ScreenTip.Title="{loc:Localization Key=Main_Report}"
|
||||
Command="{Binding OpenReportConfigCommand}"
|
||||
@@ -819,6 +811,19 @@
|
||||
Text="{loc:Localization Key=Main_ReportGeneration}"
|
||||
Visibility="{Binding IsReportSettingsVisible, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</telerik:RadRibbonGroup>
|
||||
<telerik:RadRibbonGroup Header="性能监控">
|
||||
<telerik:RadRibbonGroup.Variants>
|
||||
<telerik:GroupVariant Priority="0" Variant="Large" />
|
||||
</telerik:RadRibbonGroup.Variants>
|
||||
<telerik:RadRibbonButton
|
||||
telerik:ScreenTip.Description="查看 CPU、内存和磁盘空间使用情况"
|
||||
telerik:ScreenTip.Title="性能监控"
|
||||
Command="{Binding OpenPerformanceMonitorCommand}"
|
||||
Size="Large"
|
||||
LargeImage="/Assets/Icons/tools.png"
|
||||
SmallImage="/Assets/Icons/tools.png"
|
||||
Text="性能监控" />
|
||||
</telerik:RadRibbonGroup>
|
||||
</telerik:RadRibbonTab>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user