forked from amkovkov/GranuSightSoftware2
refactor: ResouceView
Move ResourceView and all related to ui core namespace GSS2.UI.Core Split ResourceView on separate elements Make parts folding depended on size
This commit is contained in:
@@ -1,458 +0,0 @@
|
|||||||
using System.Collections.ObjectModel;
|
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
|
||||||
|
|
||||||
using Avalonia.Threading;
|
|
||||||
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
using LiveChartsCore;
|
|
||||||
using LiveChartsCore.SkiaSharpView;
|
|
||||||
using LiveChartsCore.SkiaSharpView.Painting;
|
|
||||||
using LiveChartsCore.Defaults;
|
|
||||||
|
|
||||||
using GSS2.Core.Hardware;
|
|
||||||
using GSS2.UI.Core.ViewModels;
|
|
||||||
|
|
||||||
namespace GSS2.Test.ViewModels;
|
|
||||||
|
|
||||||
public partial class ResourcesViewModel : ViewModelBase, IDisposable
|
|
||||||
{
|
|
||||||
private bool _disposedValue;
|
|
||||||
private readonly ComputeResourcesService _computeResourcesService;
|
|
||||||
private readonly ILogger<ResourcesViewModel> _logger;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpuUsageSeries;
|
|
||||||
[ObservableProperty] private ObservableCollection<Axis> _cpuUsageSeriesYAxes;
|
|
||||||
[ObservableProperty] private ObservableCollection<Axis> _cpuUsageSeriesXAxes;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpuUsagePieSeries;
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpu0UsagePieSeries;
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpu1UsagePieSeries;
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpu2UsagePieSeries;
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpu3UsagePieSeries;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpuTemperatureSeries;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<Axis> _cpuTemperatureSeriesYAxes;
|
|
||||||
[ObservableProperty] private ObservableCollection<Axis> _cpuTemperatureSeriesXAxes;
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _cpuTemperaturePieSeries;
|
|
||||||
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _memoryUsageSeries;
|
|
||||||
[ObservableProperty] private ObservableCollection<Axis> _memoryUsageSeriesYAxes;
|
|
||||||
[ObservableProperty] private ObservableCollection<Axis> _memoryUsageSeriesXAxes;
|
|
||||||
[ObservableProperty] private ObservableCollection<ISeries> _memoryUsagePieSeries;
|
|
||||||
|
|
||||||
[ObservableProperty] private int _intervalMs = 500;
|
|
||||||
[ObservableProperty] private int _chartsHistorySize = 120;
|
|
||||||
private readonly System.Timers.Timer _updateTimer;
|
|
||||||
|
|
||||||
public ResourcesViewModel(ComputeResourcesService computeResourcesService, ILogger<ResourcesViewModel> logger)
|
|
||||||
{
|
|
||||||
_computeResourcesService = computeResourcesService;
|
|
||||||
_logger = logger;
|
|
||||||
|
|
||||||
CpuUsageSeries = [
|
|
||||||
new LineSeries<double>
|
|
||||||
{
|
|
||||||
Name = "Нагрузка ЦПУ, %",
|
|
||||||
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(144), 0),
|
|
||||||
GeometrySize = 0,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
|
|
||||||
GeometryFill = new SolidColorPaint(SKColors.DeepSkyBlue, 0),
|
|
||||||
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
CpuUsageSeriesYAxes = [
|
|
||||||
new Axis
|
|
||||||
{
|
|
||||||
MinLimit = 0.0,
|
|
||||||
MaxLimit = 100.0,
|
|
||||||
Name = "Нагрузка ЦПУ, %",
|
|
||||||
NameTextSize = 14,
|
|
||||||
MinStep = 10,
|
|
||||||
ForceStepToMin = true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
CpuUsageSeriesXAxes = [
|
|
||||||
new Axis
|
|
||||||
{
|
|
||||||
Labels = new ObservableCollection<string>(){ $"{IntervalMs * ChartsHistorySize / 1000} сек" },
|
|
||||||
LabelsAlignment = LiveChartsCore.Drawing.Align.Start
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
CpuUsagePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 100,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 100,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
Cpu0UsagePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 50,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 50,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
Cpu1UsagePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 50,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 50,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
Cpu2UsagePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 50,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 50,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
Cpu3UsagePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 50,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} %",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 50,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
CpuTemperatureSeries = [
|
|
||||||
new LineSeries<double>
|
|
||||||
{
|
|
||||||
Name = "Температура ЦПУ, ℃",
|
|
||||||
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(144), 0),
|
|
||||||
GeometrySize = 0,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
|
|
||||||
GeometryFill = new SolidColorPaint(SKColors.DeepSkyBlue, 0),
|
|
||||||
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
CpuTemperatureSeriesYAxes = [
|
|
||||||
new Axis
|
|
||||||
{
|
|
||||||
MinLimit = 0.0,
|
|
||||||
MaxLimit = 100.0,
|
|
||||||
Name = "Температура ЦПУ, ℃",
|
|
||||||
NameTextSize = 14,
|
|
||||||
MinStep = 10,
|
|
||||||
ForceStepToMin = true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
CpuTemperatureSeriesXAxes = [
|
|
||||||
new Axis
|
|
||||||
{
|
|
||||||
Labels = new ObservableCollection<string>(){ $"{IntervalMs * ChartsHistorySize / 1000} сек" },
|
|
||||||
LabelsAlignment = LiveChartsCore.Drawing.Align.Start,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
CpuTemperaturePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 100,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("00.00")} ℃",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 100,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
MemoryUsageSeries = [
|
|
||||||
new LineSeries<double>
|
|
||||||
{
|
|
||||||
Name = "Нагрузка ОЗУ, МБ",
|
|
||||||
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(144), 0),
|
|
||||||
GeometrySize = 0,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
|
|
||||||
GeometryFill = new SolidColorPaint(SKColors.Transparent, 0),
|
|
||||||
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
MemoryUsageSeriesYAxes = [
|
|
||||||
new Axis
|
|
||||||
{
|
|
||||||
MinLimit = 0.0,
|
|
||||||
MaxLimit = 1000.0,
|
|
||||||
Name = "Нагрузка ОЗУ, МБ",
|
|
||||||
NameTextSize = 14,
|
|
||||||
MinStep = 1000,
|
|
||||||
ForceStepToMin = true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
MemoryUsageSeriesXAxes = [
|
|
||||||
new Axis
|
|
||||||
{
|
|
||||||
Labels = new ObservableCollection<string>(){ $"{IntervalMs * ChartsHistorySize / 1000} сек" },
|
|
||||||
LabelsAlignment = LiveChartsCore.Drawing.Align.Start
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
MemoryUsagePieSeries = [
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue),
|
|
||||||
InnerRadius = 100,
|
|
||||||
IsHoverable = false,
|
|
||||||
DataLabelsFormatter = value => $"{value.Model?.Value?.ToString("000.00")} МБ",
|
|
||||||
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
|
||||||
DataLabelsSize = 14,
|
|
||||||
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
|
||||||
},
|
|
||||||
new PieSeries<ObservableValue>
|
|
||||||
{
|
|
||||||
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
|
||||||
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64)),
|
|
||||||
InnerRadius = 100,
|
|
||||||
ShowDataLabels = false,
|
|
||||||
IsHoverable = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
Update();
|
|
||||||
|
|
||||||
_updateTimer = new System.Timers.Timer(IntervalMs);
|
|
||||||
_updateTimer.Elapsed += UpdateTimerElapsed;
|
|
||||||
_updateTimer.AutoReset = true;
|
|
||||||
_updateTimer.Start();
|
|
||||||
_logger.LogInformation("{} initialized", nameof(ResourcesViewModel));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateTimerElapsed(object? sender, System.Timers.ElapsedEventArgs ea) => Update();
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var snapshot = _computeResourcesService.GetSnapshot();
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
|
||||||
{
|
|
||||||
if (CpuUsageSeries.Count() == 1 &&
|
|
||||||
CpuUsageSeries.First().Values is ObservableCollection<double> cpuUsageValues)
|
|
||||||
{
|
|
||||||
cpuUsageValues.Add(Math.Round(snapshot.CpuUsage.AllUsagePercent, 2));
|
|
||||||
while (cpuUsageValues.Count > ChartsHistorySize)
|
|
||||||
cpuUsageValues.RemoveAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CpuUsagePieSeries.Count() == 2 &&
|
|
||||||
CpuUsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpuUsagePieValue1 &&
|
|
||||||
cpuUsagePieValue1.Count() == 1 &&
|
|
||||||
CpuUsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpuUsagePieValue2 &&
|
|
||||||
cpuUsagePieValue2.Count() == 1)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.CpuUsage.AllUsagePercent, 2);
|
|
||||||
cpuUsagePieValue1.First().Value = roundedValue;
|
|
||||||
cpuUsagePieValue2.First().Value = 100 - roundedValue;
|
|
||||||
}
|
|
||||||
if (Cpu0UsagePieSeries.Count() == 2 &&
|
|
||||||
Cpu0UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu0UsagePieValue1 &&
|
|
||||||
cpu0UsagePieValue1.Count() == 1 &&
|
|
||||||
Cpu0UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu0UsagePieValue2 &&
|
|
||||||
cpu0UsagePieValue2.Count() == 1 &&
|
|
||||||
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(0).First(), 2);
|
|
||||||
cpu0UsagePieValue1.First().Value = roundedValue;
|
|
||||||
cpu0UsagePieValue2.First().Value = 100 - roundedValue;
|
|
||||||
}
|
|
||||||
if (Cpu1UsagePieSeries.Count() == 2 &&
|
|
||||||
Cpu1UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu1UsagePieValue1 &&
|
|
||||||
cpu1UsagePieValue1.Count() == 1 &&
|
|
||||||
Cpu1UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu1UsagePieValue2 &&
|
|
||||||
cpu1UsagePieValue2.Count() == 1 &&
|
|
||||||
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(1).First(), 2);
|
|
||||||
cpu1UsagePieValue1.First().Value = roundedValue;
|
|
||||||
cpu1UsagePieValue2.First().Value = 100 - roundedValue;
|
|
||||||
}
|
|
||||||
if (Cpu2UsagePieSeries.Count() == 2 &&
|
|
||||||
Cpu2UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu2UsagePieValue1 &&
|
|
||||||
cpu2UsagePieValue1.Count() == 1 &&
|
|
||||||
Cpu2UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu2UsagePieValue2 &&
|
|
||||||
cpu2UsagePieValue2.Count() == 1 &&
|
|
||||||
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(2).First(), 2);
|
|
||||||
cpu2UsagePieValue1.First().Value = roundedValue;
|
|
||||||
cpu2UsagePieValue2.First().Value = 100 - roundedValue;
|
|
||||||
}
|
|
||||||
if (Cpu3UsagePieSeries.Count() == 2 &&
|
|
||||||
Cpu3UsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpu3UsagePieValue1 &&
|
|
||||||
cpu3UsagePieValue1.Count() == 1 &&
|
|
||||||
Cpu3UsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpu3UsagePieValue2 &&
|
|
||||||
cpu3UsagePieValue2.Count() == 1 &&
|
|
||||||
snapshot.CpuUsage.CoreUsagePercents.Count() == 4)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(3).First(), 2);
|
|
||||||
cpu3UsagePieValue1.First().Value = roundedValue;
|
|
||||||
cpu3UsagePieValue2.First().Value = 100 - roundedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CpuTemperatureSeries.Count() == 1 &&
|
|
||||||
CpuTemperatureSeries.First().Values is ObservableCollection<double> cpuTemperatureValues)
|
|
||||||
{
|
|
||||||
cpuTemperatureValues.Add(Math.Round(snapshot.CpuTemperature.Current, 2));
|
|
||||||
while (cpuTemperatureValues.Count > ChartsHistorySize)
|
|
||||||
cpuTemperatureValues.RemoveAt(0);
|
|
||||||
}
|
|
||||||
if (CpuTemperatureSeriesYAxes.Count() == 1)
|
|
||||||
CpuTemperatureSeriesYAxes.First().MaxLimit = Math.Round(snapshot.CpuTemperature.Critical);
|
|
||||||
|
|
||||||
if (CpuTemperaturePieSeries.Count() == 2 &&
|
|
||||||
CpuTemperaturePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> cpuTemperaturePieValue1 &&
|
|
||||||
cpuTemperaturePieValue1.Count() == 1 &&
|
|
||||||
CpuTemperaturePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> cpuTemperaturePieValue2 &&
|
|
||||||
cpuTemperaturePieValue2.Count() == 1)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.CpuTemperature.Current, 2);
|
|
||||||
cpuTemperaturePieValue1.First().Value = roundedValue;
|
|
||||||
cpuTemperaturePieValue2.First().Value = snapshot.CpuTemperature.Critical - roundedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MemoryUsageSeries.Count() == 1 &&
|
|
||||||
MemoryUsageSeries.First().Values is ObservableCollection<double> memoryUsageValues)
|
|
||||||
{
|
|
||||||
memoryUsageValues.Add(Math.Round(snapshot.MemoryUsage.UsedMB, 2));
|
|
||||||
while (memoryUsageValues.Count > ChartsHistorySize)
|
|
||||||
memoryUsageValues.RemoveAt(0);
|
|
||||||
// _logger.LogInformation("Memory leakage: {} MB/s", (memoryUsageValues.TakeLast(10).Average() - memoryUsageValues.TakeLast(20).Take(10).Average()) / 5.0);
|
|
||||||
}
|
|
||||||
if (MemoryUsageSeriesYAxes.Count() == 1)
|
|
||||||
MemoryUsageSeriesYAxes.First().MaxLimit = Math.Round(snapshot.MemoryUsage.TotalMB);
|
|
||||||
|
|
||||||
if (MemoryUsagePieSeries.Count() == 2 &&
|
|
||||||
MemoryUsagePieSeries.Skip(0).First().Values is ObservableCollection<ObservableValue> memoryUsagePieValue1 &&
|
|
||||||
memoryUsagePieValue1.Count() == 1 &&
|
|
||||||
MemoryUsagePieSeries.Skip(1).First().Values is ObservableCollection<ObservableValue> memoryUsagePieValue2 &&
|
|
||||||
memoryUsagePieValue2.Count() == 1)
|
|
||||||
{
|
|
||||||
var roundedValue = Math.Round(snapshot.MemoryUsage.UsedMB, 2);
|
|
||||||
memoryUsagePieValue1.First().Value = roundedValue;
|
|
||||||
memoryUsagePieValue2.First().Value = snapshot.MemoryUsage.TotalMB - roundedValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(e, "Exception while update");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!_disposedValue)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_updateTimer.Stop();
|
|
||||||
_updateTimer.Dispose();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
|
|
||||||
_disposedValue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(disposing: true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,8 +5,8 @@
|
|||||||
xmlns:core_vm="using:GSS2.UI.Core.ViewModels"
|
xmlns:core_vm="using:GSS2.UI.Core.ViewModels"
|
||||||
x:DataType="local_vm:MainViewModel"
|
x:DataType="local_vm:MainViewModel"
|
||||||
x:Class="GSS2.Test.Views.MainView">
|
x:Class="GSS2.Test.Views.MainView">
|
||||||
<StackPanel Orientation="Vertical">
|
<Grid RowDefinitions="*,*">
|
||||||
<ContentControl Content="{Binding CameraViewModel}" Width="200" Height="200"/>
|
<ContentControl Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Content="{Binding CameraViewModel}" />
|
||||||
<ContentControl Content="{Binding ResourcesViewModel}"/>
|
<ContentControl Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Content="{Binding ResourcesViewModel}" />
|
||||||
</StackPanel>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<UserControl xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:vm="using:GSS2.Test.ViewModels"
|
|
||||||
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
|
||||||
x:Class="GSS2.Test.Views.ResourcesView"
|
|
||||||
x:DataType="vm:ResourcesViewModel">
|
|
||||||
<Grid RowDefinitions="Auto,Auto,Auto" ColumnDefinitions="*,Auto">
|
|
||||||
<lvc:CartesianChart
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="0"
|
|
||||||
Series="{Binding CpuUsageSeries}"
|
|
||||||
YAxes="{Binding CpuUsageSeriesYAxes}"
|
|
||||||
XAxes="{Binding CpuUsageSeriesXAxes}"
|
|
||||||
Height="150"
|
|
||||||
ZoomMode="None"
|
|
||||||
EasingFunction="{x:Null}" />
|
|
||||||
<lvc:CartesianChart
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
|
||||||
Series="{Binding CpuTemperatureSeries}"
|
|
||||||
YAxes="{Binding CpuTemperatureSeriesYAxes}"
|
|
||||||
XAxes="{Binding CpuTemperatureSeriesXAxes}"
|
|
||||||
Height="150"
|
|
||||||
ZoomMode="None"
|
|
||||||
EasingFunction="{x:Null}" />
|
|
||||||
<lvc:CartesianChart
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.Column="0"
|
|
||||||
Series="{Binding MemoryUsageSeries}"
|
|
||||||
YAxes="{Binding MemoryUsageSeriesYAxes}"
|
|
||||||
XAxes="{Binding MemoryUsageSeriesXAxes}"
|
|
||||||
Height="150"
|
|
||||||
ZoomMode="None"
|
|
||||||
EasingFunction="{x:Null}" />
|
|
||||||
|
|
||||||
<Grid Grid.Row="0" Grid.Column="1" RowDefinitions="Auto,Auto" ColumnDefinitions="Auto,Auto,Auto">
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.RowSpan="2"
|
|
||||||
Grid.Column="0"
|
|
||||||
Height="200"
|
|
||||||
Width="200"
|
|
||||||
Series="{Binding CpuUsagePieSeries}" />
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="1"
|
|
||||||
Height="60"
|
|
||||||
Width="60"
|
|
||||||
Series="{Binding Cpu0UsagePieSeries}" />
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="2"
|
|
||||||
Height="60"
|
|
||||||
Width="60"
|
|
||||||
Series="{Binding Cpu1UsagePieSeries}" />
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="1"
|
|
||||||
Height="60"
|
|
||||||
Width="60"
|
|
||||||
Series="{Binding Cpu2UsagePieSeries}" />
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="2"
|
|
||||||
Height="60"
|
|
||||||
Width="60"
|
|
||||||
Series="{Binding Cpu3UsagePieSeries}" />
|
|
||||||
</Grid>
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="1"
|
|
||||||
Height="150"
|
|
||||||
Width="150"
|
|
||||||
Series="{Binding CpuTemperaturePieSeries}" />
|
|
||||||
<lvc:PieChart
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.Column="1"
|
|
||||||
Height="150"
|
|
||||||
Width="150"
|
|
||||||
Series="{Binding MemoryUsagePieSeries}" />
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Оригинальное решение для проблеммы сворачивания колнок в Grid от
|
||||||
|
// https://github.com/AvaloniaUI/Avalonia/discussions/6773#discussioncomment-1514604
|
||||||
|
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.Behaviors;
|
||||||
|
|
||||||
|
public static class GridColumnHideBehavior
|
||||||
|
{
|
||||||
|
private readonly static GridLength ZeroWidth = new GridLength(0, GridUnitType.Pixel);
|
||||||
|
|
||||||
|
private readonly static AttachedProperty<GridLength?> LastWidthProperty =
|
||||||
|
AvaloniaProperty.RegisterAttached<ColumnDefinition, GridLength?>("LastWidth", typeof(GridColumnHideBehavior), default);
|
||||||
|
|
||||||
|
public readonly static AttachedProperty<bool> IsVisibleProperty =
|
||||||
|
AvaloniaProperty.RegisterAttached<ColumnDefinition, bool>("IsVisible", typeof(GridColumnHideBehavior), true,
|
||||||
|
coerce: (element, visibility) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
var lastWidth = element.GetValue(LastWidthProperty);
|
||||||
|
if (visibility && lastWidth is { })
|
||||||
|
element.SetValue(ColumnDefinition.WidthProperty, lastWidth);
|
||||||
|
else if (!visibility)
|
||||||
|
{
|
||||||
|
element.SetValue(LastWidthProperty, element.GetValue(ColumnDefinition.WidthProperty));
|
||||||
|
element.SetValue(ColumnDefinition.WidthProperty, ZeroWidth);
|
||||||
|
}
|
||||||
|
return visibility;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
public static bool GetIsVisible(ColumnDefinition columnDefinition)
|
||||||
|
{
|
||||||
|
return columnDefinition.GetValue(IsVisibleProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetIsVisible(ColumnDefinition columnDefinition, bool visibility)
|
||||||
|
{
|
||||||
|
columnDefinition.SetValue(IsVisibleProperty, visibility);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
using Avalonia;
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
using LiveChartsCore;
|
||||||
|
using LiveChartsCore.Defaults;
|
||||||
|
using LiveChartsCore.SkiaSharpView;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.ViewModels;
|
||||||
|
|
||||||
|
public partial class ResourceBarViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
[ObservableProperty] private ObservableCollection<ISeries> _series;
|
||||||
|
[ObservableProperty] private Rect _bounds;
|
||||||
|
|
||||||
|
public ResourceBarViewModel(IEnumerable<ISeries> series)
|
||||||
|
{
|
||||||
|
Series = new ObservableCollection<ISeries>(series);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnBoundsChanged(Rect value)
|
||||||
|
{
|
||||||
|
var size = Math.Min(value.Width, value.Height);
|
||||||
|
|
||||||
|
var textSize = size switch
|
||||||
|
{
|
||||||
|
< 100 => 8,
|
||||||
|
< 150 => 10,
|
||||||
|
< 175 => 12,
|
||||||
|
_ => 14
|
||||||
|
};
|
||||||
|
var innerRadius = size switch
|
||||||
|
{
|
||||||
|
< 50 => size / 2,
|
||||||
|
< 120 => size / 3,
|
||||||
|
_ => size / 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var series in Series.OfType<PieSeries<ObservableValue>>())
|
||||||
|
{
|
||||||
|
series.DataLabelsSize = textSize;
|
||||||
|
series.InnerRadius = innerRadius;
|
||||||
|
series.OuterRadiusOffset = 0;
|
||||||
|
series.RelativeOuterRadius = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateValue(double value, double maxValue)
|
||||||
|
{
|
||||||
|
if (Series.Count() == 2 &&
|
||||||
|
Series.Skip(0).First().Values is ObservableCollection<ObservableValue> value1 &&
|
||||||
|
Series.Skip(1).First().Values is ObservableCollection<ObservableValue> value2)
|
||||||
|
{
|
||||||
|
value1.First().Value = value > maxValue ? maxValue : value;
|
||||||
|
value2.First().Value = value > maxValue ? 0 : maxValue - value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
using Avalonia;
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
using LiveChartsCore;
|
||||||
|
using LiveChartsCore.SkiaSharpView;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.ViewModels;
|
||||||
|
|
||||||
|
public partial class ResourceChartViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
[ObservableProperty] private ObservableCollection<ISeries> _series;
|
||||||
|
[ObservableProperty] private ObservableCollection<Axis> _yAxes;
|
||||||
|
[ObservableProperty] private ObservableCollection<Axis> _xAxes;
|
||||||
|
[ObservableProperty] private Rect _bounds;
|
||||||
|
|
||||||
|
public ResourceChartViewModel(IEnumerable<ISeries> series, IEnumerable<Axis> yAxes, IEnumerable<Axis> xAxes)
|
||||||
|
{
|
||||||
|
Series = new ObservableCollection<ISeries>(series);
|
||||||
|
YAxes = new ObservableCollection<Axis>(yAxes);
|
||||||
|
XAxes = new ObservableCollection<Axis>(xAxes);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnBoundsChanged(Rect value)
|
||||||
|
{
|
||||||
|
var textSize = value.Height switch
|
||||||
|
{
|
||||||
|
< 100 => 8,
|
||||||
|
< 150 => 10,
|
||||||
|
< 200 => 12,
|
||||||
|
_ => 14
|
||||||
|
};
|
||||||
|
var labelsDensity = value.Height switch
|
||||||
|
{
|
||||||
|
< 100 => 0.2f,
|
||||||
|
< 150 => 0.3f,
|
||||||
|
< 200 => 0.4f,
|
||||||
|
_ => 0.5f
|
||||||
|
};
|
||||||
|
foreach (var axis in YAxes)
|
||||||
|
{
|
||||||
|
axis.TextSize = textSize;
|
||||||
|
axis.NameTextSize = textSize;
|
||||||
|
axis.LabelsDensity = labelsDensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AppendValue(double value, int maxValuesCount)
|
||||||
|
{
|
||||||
|
if (Series.Count() != 1 || Series.First().Values is not ObservableCollection<double> values)
|
||||||
|
return;
|
||||||
|
|
||||||
|
values.Add(value);
|
||||||
|
while (values.Count() > maxValuesCount || values.Count() == 0)
|
||||||
|
values.RemoveAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Avalonia;
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.ViewModels;
|
||||||
|
|
||||||
|
public partial class ResourceCpuUsageBarsViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
[ObservableProperty] private Rect _bounds;
|
||||||
|
[ObservableProperty] private bool _isCoresColumnVisible;
|
||||||
|
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _cpu;
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _cpu0;
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _cpu1;
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _cpu2;
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _cpu3;
|
||||||
|
|
||||||
|
public ResourceCpuUsageBarsViewModel(ResourceBarViewModel cpu, ResourceBarViewModel cpu0, ResourceBarViewModel cpu1, ResourceBarViewModel cpu2, ResourceBarViewModel cpu3)
|
||||||
|
{
|
||||||
|
Cpu = cpu;
|
||||||
|
Cpu0 = cpu0;
|
||||||
|
Cpu1 = cpu1;
|
||||||
|
Cpu2 = cpu2;
|
||||||
|
Cpu3 = cpu3;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnBoundsChanged(Rect value)
|
||||||
|
{
|
||||||
|
IsCoresColumnVisible = Math.Min(value.Width, value.Height * 1.5) > 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
|
using Avalonia.Threading;
|
||||||
|
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
using LiveChartsCore.SkiaSharpView;
|
||||||
|
using LiveChartsCore.SkiaSharpView.Painting;
|
||||||
|
using LiveChartsCore.Defaults;
|
||||||
|
|
||||||
|
using GSS2.Core.Hardware;
|
||||||
|
using Avalonia;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.ViewModels;
|
||||||
|
|
||||||
|
public partial class ResourcesViewModel : ViewModelBase, IDisposable
|
||||||
|
{
|
||||||
|
private bool _disposedValue;
|
||||||
|
private readonly ComputeResourcesService _computeResourcesService;
|
||||||
|
private readonly ILogger<ResourcesViewModel> _logger;
|
||||||
|
private readonly int _intervalMs = 500;
|
||||||
|
private readonly int _chartsHistorySize = 120;
|
||||||
|
private readonly System.Timers.Timer _updateTimer;
|
||||||
|
|
||||||
|
[ObservableProperty] private Rect _bounds;
|
||||||
|
[ObservableProperty] private bool _isChartsColumnVisible;
|
||||||
|
[ObservableProperty] private bool _isBarsColumnVisible;
|
||||||
|
|
||||||
|
[ObservableProperty] private ResourceChartViewModel _cpuUsageChartViewModel;
|
||||||
|
[ObservableProperty] private ResourceChartViewModel _cpuTemperatureChartViewModel;
|
||||||
|
[ObservableProperty] private ResourceChartViewModel _memoryUsageChartViewModel;
|
||||||
|
|
||||||
|
[ObservableProperty] private ResourceCpuUsageBarsViewModel _cpuUsageBarsViewModel;
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _cpuTemperatureBarViewModel;
|
||||||
|
[ObservableProperty] private ResourceBarViewModel _memoryUsageBarViewModel;
|
||||||
|
|
||||||
|
public ResourcesViewModel(ComputeResourcesService computeResourcesService, ILogger<ResourcesViewModel> logger)
|
||||||
|
{
|
||||||
|
_computeResourcesService = computeResourcesService;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
|
ResourceChartViewModel CreateChartViewModel(string name, double minLimit, double maxLimit, double minStep)
|
||||||
|
{
|
||||||
|
return new ResourceChartViewModel(
|
||||||
|
series:
|
||||||
|
[
|
||||||
|
new LineSeries<double>
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Values = new ObservableCollection<double>(Enumerable.Repeat(0.0, _chartsHistorySize)),
|
||||||
|
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(127), 0),
|
||||||
|
GeometrySize = 0,
|
||||||
|
ShowDataLabels = false,
|
||||||
|
Stroke = new SolidColorPaint(SKColors.DeepSkyBlue, 1),
|
||||||
|
GeometryFill = new SolidColorPaint(SKColors.Transparent, 0),
|
||||||
|
GeometryStroke = new SolidColorPaint(SKColors.Transparent, 0),
|
||||||
|
IsHoverable = false,
|
||||||
|
DataPadding = new LiveChartsCore.Drawing.LvcPoint(0.1f, 0.1f)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxes:
|
||||||
|
[
|
||||||
|
new Axis
|
||||||
|
{
|
||||||
|
MinLimit = minLimit,
|
||||||
|
MaxLimit = maxLimit,
|
||||||
|
MinStep = minStep,
|
||||||
|
Name = name
|
||||||
|
}
|
||||||
|
],
|
||||||
|
xAxes:
|
||||||
|
[
|
||||||
|
new Axis
|
||||||
|
{
|
||||||
|
IsVisible = false,
|
||||||
|
Padding = new LiveChartsCore.Drawing.Padding(0)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ResourceBarViewModel CreateBarViewModel(Func<LiveChartsCore.Kernel.ChartPoint<ObservableValue, LiveChartsCore.SkiaSharpView.Drawing.Geometries.DoughnutGeometry, LiveChartsCore.SkiaSharpView.Drawing.Geometries.LabelGeometry>, string> formater)
|
||||||
|
{
|
||||||
|
return new ResourceBarViewModel(
|
||||||
|
series:
|
||||||
|
[
|
||||||
|
new PieSeries<ObservableValue>
|
||||||
|
{
|
||||||
|
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
||||||
|
Fill = new SolidColorPaint(SKColors.DeepSkyBlue, 0),
|
||||||
|
ShowDataLabels = true,
|
||||||
|
IsHoverable = false,
|
||||||
|
HoverPushout = 0,
|
||||||
|
DataLabelsFormatter = formater,
|
||||||
|
DataLabelsPosition = LiveChartsCore.Measure.PolarLabelsPosition.ChartCenter,
|
||||||
|
DataLabelsPaint = new SolidColorPaint(SKColors.White)
|
||||||
|
},
|
||||||
|
new PieSeries<ObservableValue>
|
||||||
|
{
|
||||||
|
Values = new ObservableCollection<ObservableValue> { new ObservableValue(1) },
|
||||||
|
Fill = new SolidColorPaint(SKColors.DeepSkyBlue.WithAlpha(64), 0),
|
||||||
|
ShowDataLabels = false,
|
||||||
|
IsHoverable = false,
|
||||||
|
HoverPushout = 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CpuUsageChartViewModel = CreateChartViewModel("Нагрузка ЦПУ, %", 0, 100, 10);
|
||||||
|
CpuTemperatureChartViewModel = CreateChartViewModel("Температура ЦПУ, ℃", 0, 100, 10);
|
||||||
|
MemoryUsageChartViewModel = CreateChartViewModel("Нагрузка ОЗУ, МБ", 0, 8000, 1000);
|
||||||
|
|
||||||
|
CpuUsageBarsViewModel = new ResourceCpuUsageBarsViewModel(
|
||||||
|
CreateBarViewModel(value => $"{value.Model?.Value?.ToString("00.00")} %"),
|
||||||
|
CreateBarViewModel(value => $"{value.Model?.Value?.ToString("00.00")} %"),
|
||||||
|
CreateBarViewModel(value => $"{value.Model?.Value?.ToString("00.00")} %"),
|
||||||
|
CreateBarViewModel(value => $"{value.Model?.Value?.ToString("00.00")} %"),
|
||||||
|
CreateBarViewModel(value => $"{value.Model?.Value?.ToString("00.00")} %")
|
||||||
|
);
|
||||||
|
CpuTemperatureBarViewModel = CreateBarViewModel(value => $"{value.Model?.Value?.ToString("00.00")} ℃");
|
||||||
|
MemoryUsageBarViewModel = CreateBarViewModel(value => $"{value.Model?.Value?.ToString("000.00")} МБ");
|
||||||
|
|
||||||
|
Update();
|
||||||
|
|
||||||
|
_updateTimer = new System.Timers.Timer(_intervalMs);
|
||||||
|
_updateTimer.Elapsed += UpdateTimerElapsed;
|
||||||
|
_updateTimer.AutoReset = true;
|
||||||
|
_updateTimer.Start();
|
||||||
|
_logger.LogInformation("{} initialized", nameof(ResourcesViewModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnBoundsChanged(Rect value)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("BoundsChanged {}", value);
|
||||||
|
if (value.Width < 300)
|
||||||
|
{
|
||||||
|
IsChartsColumnVisible = false;
|
||||||
|
IsBarsColumnVisible = true;
|
||||||
|
}
|
||||||
|
else if (value.Width < 400)
|
||||||
|
{
|
||||||
|
IsChartsColumnVisible = true;
|
||||||
|
IsBarsColumnVisible = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsChartsColumnVisible = true;
|
||||||
|
IsBarsColumnVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnIsChartsColumnVisibleChanged(bool value)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("IsChartsColumnVisibleChanged {}", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnIsBarsColumnVisibleChanged(bool value)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("IsBarsColumnVisibleChanged {}", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTimerElapsed(object? sender, System.Timers.ElapsedEventArgs ea) => Update();
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var snapshot = _computeResourcesService.GetSnapshot();
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
if (CpuTemperatureChartViewModel.YAxes.Count() == 1)
|
||||||
|
CpuTemperatureChartViewModel.YAxes.First().MaxLimit = snapshot.CpuTemperature.Critical;
|
||||||
|
if (MemoryUsageChartViewModel.YAxes.Count() == 1)
|
||||||
|
MemoryUsageChartViewModel.YAxes.First().MaxLimit = snapshot.MemoryUsage.TotalMB;
|
||||||
|
|
||||||
|
CpuUsageChartViewModel.AppendValue(Math.Round(snapshot.CpuUsage.AllUsagePercent, 2), _chartsHistorySize);
|
||||||
|
CpuTemperatureChartViewModel.AppendValue(Math.Round(snapshot.CpuTemperature.Current, 2), _chartsHistorySize);
|
||||||
|
MemoryUsageChartViewModel.AppendValue(Math.Round(snapshot.MemoryUsage.UsedMB, 2), _chartsHistorySize);
|
||||||
|
|
||||||
|
CpuUsageBarsViewModel.Cpu.UpdateValue(Math.Round(snapshot.CpuUsage.AllUsagePercent, 2), 100);
|
||||||
|
CpuUsageBarsViewModel.Cpu0.UpdateValue(Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(0).First(), 2), 100);
|
||||||
|
CpuUsageBarsViewModel.Cpu1.UpdateValue(Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(1).First(), 2), 100);
|
||||||
|
CpuUsageBarsViewModel.Cpu2.UpdateValue(Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(2).First(), 2), 100);
|
||||||
|
CpuUsageBarsViewModel.Cpu3.UpdateValue(Math.Round(snapshot.CpuUsage.CoreUsagePercents.Skip(3).First(), 2), 100);
|
||||||
|
CpuTemperatureBarViewModel.UpdateValue(Math.Round(snapshot.CpuTemperature.Current, 2), snapshot.CpuTemperature.Critical);
|
||||||
|
MemoryUsageBarViewModel.UpdateValue(Math.Round(snapshot.MemoryUsage.UsedMB, 2), snapshot.MemoryUsage.TotalMB);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(e, "Exception while update");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!_disposedValue)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_updateTimer.Stop();
|
||||||
|
_updateTimer.Dispose();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
_disposedValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<lvc:PieChart xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="using:GSS2.UI.Core.ViewModels"
|
||||||
|
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||||
|
x:Class="GSS2.UI.Core.Views.ResourceBarView"
|
||||||
|
x:DataType="vm:ResourceBarViewModel"
|
||||||
|
Series="{Binding Series}"
|
||||||
|
Bounds="{Binding Bounds, Mode=OneWayToSource}">
|
||||||
|
</lvc:PieChart>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using LiveChartsCore.SkiaSharpView.Avalonia;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.Views;
|
||||||
|
|
||||||
|
public partial class ResourceBarView : PieChart
|
||||||
|
{
|
||||||
|
public ResourceBarView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<lvc:CartesianChart xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:vm="using:GSS2.UI.Core.ViewModels"
|
||||||
|
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||||
|
x:Class="GSS2.UI.Core.Views.ResourceChartView"
|
||||||
|
x:DataType="vm:ResourceChartViewModel"
|
||||||
|
Series="{Binding Series}"
|
||||||
|
YAxes="{Binding YAxes}"
|
||||||
|
XAxes="{Binding XAxes}"
|
||||||
|
ZoomMode="None"
|
||||||
|
EasingFunction="{x:Null}"
|
||||||
|
Bounds="{Binding Bounds, Mode=OneWayToSource}">
|
||||||
|
</lvc:CartesianChart>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using LiveChartsCore.SkiaSharpView.Avalonia;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.Views;
|
||||||
|
|
||||||
|
public partial class ResourceChartView : CartesianChart
|
||||||
|
{
|
||||||
|
public ResourceChartView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:GSS2.UI.Core.Views"
|
||||||
|
xmlns:vm="using:GSS2.UI.Core.ViewModels"
|
||||||
|
xmlns:behaviors="using:GSS2.UI.Core.Behaviors"
|
||||||
|
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||||
|
x:Class="GSS2.UI.Core.Views.ResourceCpuUsageBarsView"
|
||||||
|
x:DataType="vm:ResourceCpuUsageBarsViewModel"
|
||||||
|
Bounds="{Binding Bounds, Mode=OneWayToSource}">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="2*"/>
|
||||||
|
<ColumnDefinition Width="*" behaviors:GridColumnHideBehavior.IsVisible="{Binding IsCoresColumnVisible}" />
|
||||||
|
<ColumnDefinition Width="*" behaviors:GridColumnHideBehavior.IsVisible="{Binding IsCoresColumnVisible}" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<local:ResourceBarView Grid.Row="0" Grid.RowSpan="2" Grid.Column="0" DataContext="{Binding Cpu}" />
|
||||||
|
<local:ResourceBarView Grid.Row="0" Grid.Column="1" DataContext="{Binding Cpu0}" />
|
||||||
|
<local:ResourceBarView Grid.Row="0" Grid.Column="2" DataContext="{Binding Cpu1}" />
|
||||||
|
<local:ResourceBarView Grid.Row="1" Grid.Column="1" DataContext="{Binding Cpu2}" />
|
||||||
|
<local:ResourceBarView Grid.Row="1" Grid.Column="2" DataContext="{Binding Cpu3}" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace GSS2.UI.Core.Views;
|
||||||
|
|
||||||
|
public partial class ResourceCpuUsageBarsView : UserControl
|
||||||
|
{
|
||||||
|
public ResourceCpuUsageBarsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:GSS2.UI.Core.Views"
|
||||||
|
xmlns:vm="using:GSS2.UI.Core.ViewModels"
|
||||||
|
xmlns:behaviors="using:GSS2.UI.Core.Behaviors"
|
||||||
|
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||||
|
x:Class="GSS2.UI.Core.Views.ResourcesView"
|
||||||
|
x:DataType="vm:ResourcesViewModel"
|
||||||
|
Bounds="{Binding Bounds, Mode=OneWayToSource}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="3*" behaviors:GridColumnHideBehavior.IsVisible="{Binding IsChartsColumnVisible}" />
|
||||||
|
<ColumnDefinition Width="*" behaviors:GridColumnHideBehavior.IsVisible="{Binding IsBarsColumnVisible}" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="*,*,*" Column="0">
|
||||||
|
<local:ResourceChartView Grid.Row="0" DataContext="{Binding CpuUsageChartViewModel}" />
|
||||||
|
<local:ResourceChartView Grid.Row="1" DataContext="{Binding CpuTemperatureChartViewModel}" />
|
||||||
|
<local:ResourceChartView Grid.Row="2" DataContext="{Binding MemoryUsageChartViewModel}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid RowDefinitions="*,*,*" Column="1">
|
||||||
|
<local:ResourceCpuUsageBarsView Grid.Row="0" DataContext="{Binding CpuUsageBarsViewModel}" />
|
||||||
|
<local:ResourceBarView Grid.Row="1" DataContext="{Binding CpuTemperatureBarViewModel}" />
|
||||||
|
<local:ResourceBarView Grid.Row="2" DataContext="{Binding MemoryUsageBarViewModel}" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
|
||||||
namespace GSS2.Test.Views;
|
namespace GSS2.UI.Core.Views;
|
||||||
|
|
||||||
public partial class ResourcesView : UserControl
|
public partial class ResourcesView : UserControl
|
||||||
{
|
{
|
||||||
Reference in New Issue
Block a user