更新
This commit is contained in:
@@ -328,7 +328,7 @@
|
|||||||
|
|
||||||
<Grid Background="{StaticResource ShellGradientBrush}">
|
<Grid Background="{StaticResource ShellGradientBrush}">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition x:Name="SidebarColumn" Width="118" />
|
<ColumnDefinition Width="360" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@
|
|||||||
Background="{StaticResource SidebarBrush}"
|
Background="{StaticResource SidebarBrush}"
|
||||||
BorderBrush="#B9C7D1"
|
BorderBrush="#B9C7D1"
|
||||||
BorderThickness="0,0,1,0"
|
BorderThickness="0,0,1,0"
|
||||||
Padding="12">
|
Padding="18,16,14,16">
|
||||||
<Grid>
|
<Grid>
|
||||||
<ScrollViewer x:Name="SidebarDetails"
|
<ScrollViewer x:Name="SidebarDetails"
|
||||||
VerticalScrollBarVisibility="Auto"
|
VerticalScrollBarVisibility="Auto"
|
||||||
@@ -346,21 +346,10 @@
|
|||||||
<Border Style="{StaticResource PanelBorderStyle}"
|
<Border Style="{StaticResource PanelBorderStyle}"
|
||||||
Background="{StaticResource SurfaceRaisedBrush}"
|
Background="{StaticResource SurfaceRaisedBrush}"
|
||||||
Margin="0,0,0,14">
|
Margin="0,0,0,14">
|
||||||
<Grid>
|
<StackPanel>
|
||||||
<Grid.ColumnDefinitions>
|
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="试验参数" />
|
||||||
<ColumnDefinition Width="*" />
|
<TextBlock Style="{StaticResource SectionHintStyle}" Text="参数编辑保留在侧栏,主界面聚焦控制、曲线和结果。" />
|
||||||
<ColumnDefinition Width="Auto" />
|
</StackPanel>
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<StackPanel Grid.Column="0" Margin="0,0,12,0">
|
|
||||||
<TextBlock Style="{StaticResource SectionTitleStyle}" Text="试验参数" />
|
|
||||||
<TextBlock Style="{StaticResource SectionHintStyle}" Text="参数编辑保留在侧栏,主界面聚焦控制、曲线和结果。" />
|
|
||||||
</StackPanel>
|
|
||||||
<Button Grid.Column="1"
|
|
||||||
Width="88"
|
|
||||||
Style="{StaticResource GhostButtonStyle}"
|
|
||||||
Click="ToggleSidebar_Click"
|
|
||||||
Content="收起" />
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Style="{StaticResource PanelBorderStyle}"
|
<Border Style="{StaticResource PanelBorderStyle}"
|
||||||
@@ -505,48 +494,6 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<Grid x:Name="SidebarCollapsedRail" Visibility="Collapsed">
|
|
||||||
<Border Style="{StaticResource PanelBorderStyle}"
|
|
||||||
Background="{StaticResource SurfaceRaisedBrush}"
|
|
||||||
Padding="10">
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<Button Width="52"
|
|
||||||
Height="42"
|
|
||||||
Padding="0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Margin="0,0,0,12"
|
|
||||||
Style="{StaticResource GhostButtonStyle}"
|
|
||||||
Click="ToggleSidebar_Click"
|
|
||||||
Content=">" />
|
|
||||||
<TextBlock HorizontalAlignment="Center"
|
|
||||||
FontSize="15"
|
|
||||||
FontWeight="SemiBold"
|
|
||||||
Text="参数" />
|
|
||||||
<Border Height="4"
|
|
||||||
Margin="8,14,8,14"
|
|
||||||
Background="{StaticResource AccentStripBrush}"
|
|
||||||
CornerRadius="2" />
|
|
||||||
<Border Style="{StaticResource InsetCardStyle}" Padding="10">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock HorizontalAlignment="Center"
|
|
||||||
Style="{StaticResource CaptionStyle}"
|
|
||||||
Text="状态" />
|
|
||||||
<TextBlock HorizontalAlignment="Center"
|
|
||||||
FontWeight="SemiBold"
|
|
||||||
Text="{Binding MachineState, Mode=OneWay}" />
|
|
||||||
<TextBlock Margin="0,10,0,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Style="{StaticResource CaptionStyle}"
|
|
||||||
Text="{Binding Recipe.BatchNumber, Mode=TwoWay}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
<TextBlock Margin="0,14,0,0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Style="{StaticResource SectionHintStyle}"
|
|
||||||
Text="展开编辑" />
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
@@ -767,8 +714,11 @@
|
|||||||
|
|
||||||
<Border Grid.Column="0"
|
<Border Grid.Column="0"
|
||||||
Style="{StaticResource PanelBorderStyle}"
|
Style="{StaticResource PanelBorderStyle}"
|
||||||
Margin="0,0,16,0">
|
Margin="0,0,16,0"
|
||||||
<Grid>
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<Grid HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
@@ -784,13 +734,20 @@
|
|||||||
BorderBrush="#C2D0D9"
|
BorderBrush="#C2D0D9"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="14"
|
CornerRadius="14"
|
||||||
Padding="8">
|
Padding="8"
|
||||||
|
MinHeight="360"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
<Border Background="{StaticResource ChartSurfaceBrush}"
|
<Border Background="{StaticResource ChartSurfaceBrush}"
|
||||||
BorderBrush="#98A9B7"
|
BorderBrush="#98A9B7"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="10"
|
CornerRadius="10"
|
||||||
Padding="6">
|
Padding="8,8,8,18"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
<lvc:CartesianChart x:Name="RealtimeForceChart"
|
<lvc:CartesianChart x:Name="RealtimeForceChart"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
Series="{Binding ForceSeries}"
|
Series="{Binding ForceSeries}"
|
||||||
XAxes="{Binding ForceXAxes}"
|
XAxes="{Binding ForceXAxes}"
|
||||||
YAxes="{Binding ForceYAxes}"
|
YAxes="{Binding ForceYAxes}"
|
||||||
|
|||||||
@@ -4,22 +4,20 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using COFTester.ViewModels;
|
using COFTester.ViewModels;
|
||||||
|
using LiveChartsCore.Kernel;
|
||||||
|
|
||||||
namespace COFTester;
|
namespace COFTester;
|
||||||
|
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
private const double ExpandedSidebarWidth = 360;
|
|
||||||
private const double CollapsedSidebarWidth = 118;
|
|
||||||
private readonly MainViewModel _viewModel = new();
|
private readonly MainViewModel _viewModel = new();
|
||||||
private bool _isSidebarCollapsed;
|
|
||||||
private bool _isRealtimeChartLayoutRefreshQueued;
|
private bool _isRealtimeChartLayoutRefreshQueued;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContext = _viewModel;
|
DataContext = _viewModel;
|
||||||
SetSidebarCollapsed(true);
|
QueueRealtimeChartLayoutRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClosed(EventArgs e)
|
protected override void OnClosed(EventArgs e)
|
||||||
@@ -28,9 +26,16 @@ public partial class MainWindow : Window
|
|||||||
base.OnClosed(e);
|
base.OnClosed(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleSidebar_Click(object sender, RoutedEventArgs e)
|
protected override void OnContentRendered(EventArgs e)
|
||||||
{
|
{
|
||||||
SetSidebarCollapsed(!_isSidebarCollapsed);
|
base.OnContentRendered(e);
|
||||||
|
QueueRealtimeChartLayoutRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStateChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnStateChanged(e);
|
||||||
|
QueueRealtimeChartLayoutRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowRealtimeTab_Click(object sender, RoutedEventArgs e)
|
private void ShowRealtimeTab_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -96,16 +101,6 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetSidebarCollapsed(bool collapsed)
|
|
||||||
{
|
|
||||||
_isSidebarCollapsed = collapsed;
|
|
||||||
SidebarColumn.Width = new GridLength(collapsed ? CollapsedSidebarWidth : ExpandedSidebarWidth);
|
|
||||||
SidebarDetails.Visibility = collapsed ? Visibility.Collapsed : Visibility.Visible;
|
|
||||||
SidebarCollapsedRail.Visibility = collapsed ? Visibility.Visible : Visibility.Collapsed;
|
|
||||||
SidebarHost.Padding = collapsed ? new Thickness(12) : new Thickness(18, 16, 14, 16);
|
|
||||||
QueueRealtimeChartLayoutRefresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QueueRealtimeChartLayoutRefresh()
|
private void QueueRealtimeChartLayoutRefresh()
|
||||||
{
|
{
|
||||||
if (_isRealtimeChartLayoutRefreshQueued)
|
if (_isRealtimeChartLayoutRefreshQueued)
|
||||||
@@ -114,13 +109,25 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
_isRealtimeChartLayoutRefreshQueued = true;
|
_isRealtimeChartLayoutRefreshQueued = true;
|
||||||
Dispatcher.BeginInvoke(RefreshRealtimeChartLayout, DispatcherPriority.ContextIdle);
|
Dispatcher.BeginInvoke(RunRealtimeChartLayoutRefreshSequence, DispatcherPriority.Loaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RunRealtimeChartLayoutRefreshSequence()
|
||||||
|
{
|
||||||
|
RefreshRealtimeChartLayout();
|
||||||
|
Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
RefreshRealtimeChartLayout();
|
||||||
|
Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
RefreshRealtimeChartLayout();
|
||||||
|
_isRealtimeChartLayoutRefreshQueued = false;
|
||||||
|
}, DispatcherPriority.ApplicationIdle);
|
||||||
|
}, DispatcherPriority.Render);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshRealtimeChartLayout()
|
private void RefreshRealtimeChartLayout()
|
||||||
{
|
{
|
||||||
_isRealtimeChartLayoutRefreshQueued = false;
|
|
||||||
|
|
||||||
if (RealtimeForceChart.ActualWidth <= 0 || RealtimeForceChart.ActualHeight <= 0)
|
if (RealtimeForceChart.ActualWidth <= 0 || RealtimeForceChart.ActualHeight <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -129,5 +136,10 @@ public partial class MainWindow : Window
|
|||||||
RealtimeForceChart.InvalidateMeasure();
|
RealtimeForceChart.InvalidateMeasure();
|
||||||
RealtimeForceChart.InvalidateArrange();
|
RealtimeForceChart.InvalidateArrange();
|
||||||
RealtimeForceChart.UpdateLayout();
|
RealtimeForceChart.UpdateLayout();
|
||||||
|
RealtimeForceChart.CoreChart.Update(new ChartUpdateParams
|
||||||
|
{
|
||||||
|
IsAutomaticUpdate = false,
|
||||||
|
Throttling = false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
private static readonly TimeSpan RealtimeChartRefreshInterval = TimeSpan.FromMilliseconds(250);
|
private static readonly TimeSpan RealtimeChartRefreshInterval = TimeSpan.FromMilliseconds(250);
|
||||||
private const double RealtimeChartDisplacementStepMm = 0.5;
|
private const double RealtimeChartDisplacementStepMm = 0.5;
|
||||||
private const double RealtimeChartXAxisPaddingMm = 5;
|
private const double RealtimeChartXAxisPaddingMm = 5;
|
||||||
|
private const double MinimumEmptyChartXAxisMaxLimit = 1;
|
||||||
|
private const double EmptyChartYAxisMaxLimit = 0.5;
|
||||||
|
private const double EmptyChartPointForceN = 0.001;
|
||||||
|
|
||||||
private readonly DispatcherTimer _timer;
|
private readonly DispatcherTimer _timer;
|
||||||
private readonly DispatcherTimer _deviceReconnectTimer;
|
private readonly DispatcherTimer _deviceReconnectTimer;
|
||||||
@@ -231,8 +234,8 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
_lastForceXAxisMaxLimit = 1;
|
_lastForceXAxisMaxLimit = GetEmptyChartXAxisMaxLimit();
|
||||||
_lastForceYAxisMaxLimit = 0.5;
|
_lastForceYAxisMaxLimit = EmptyChartYAxisMaxLimit;
|
||||||
ForceXAxes = CreateForceXAxes(_lastForceXAxisMaxLimit);
|
ForceXAxes = CreateForceXAxes(_lastForceXAxisMaxLimit);
|
||||||
ForceYAxes = CreateForceYAxes(_lastForceYAxisMaxLimit);
|
ForceYAxes = CreateForceYAxes(_lastForceYAxisMaxLimit);
|
||||||
|
|
||||||
@@ -241,13 +244,14 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
Xi = Recipe.TravelMm * 0.35,
|
Xi = Recipe.TravelMm * 0.35,
|
||||||
Xj = Recipe.TravelMm,
|
Xj = Recipe.TravelMm,
|
||||||
Yi = 0,
|
Yi = 0,
|
||||||
Yj = 1,
|
Yj = EmptyChartYAxisMaxLimit,
|
||||||
Fill = new SolidColorPaint(new SKColor(0, 105, 180, 18)),
|
Fill = new SolidColorPaint(new SKColor(0, 105, 180, 18)),
|
||||||
Stroke = new SolidColorPaint(new SKColor(0, 105, 180, 70), 1)
|
Stroke = new SolidColorPaint(new SKColor(0, 105, 180, 70), 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
ForceSections = [_kineticBand];
|
ForceSections = [_kineticBand];
|
||||||
|
|
||||||
|
ShowEmptyRealtimeChartFrame();
|
||||||
LoadHistoryFromDatabase();
|
LoadHistoryFromDatabase();
|
||||||
UpdateDerivedValues();
|
UpdateDerivedValues();
|
||||||
AddInfoEvent("系统启动,正在初始化 PLC 通信与本地数据存储。");
|
AddInfoEvent("系统启动,正在初始化 PLC 通信与本地数据存储。");
|
||||||
@@ -1262,7 +1266,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
NamePaint = new SolidColorPaint(new SKColor(33, 49, 61)),
|
NamePaint = new SolidColorPaint(new SKColor(33, 49, 61)),
|
||||||
SeparatorsPaint = new SolidColorPaint(new SKColor(209, 219, 227), 1),
|
SeparatorsPaint = new SolidColorPaint(new SKColor(209, 219, 227), 1),
|
||||||
SubseparatorsPaint = new SolidColorPaint(new SKColor(229, 236, 242), 1),
|
SubseparatorsPaint = new SolidColorPaint(new SKColor(229, 236, 242), 1),
|
||||||
Padding = new Padding(8, 0, 0, 0)
|
Padding = new Padding(8, 0, 12, 8)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -1661,10 +1665,43 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_currentPointSample.Clear();
|
ShowEmptyRealtimeChartFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShowEmptyRealtimeChartFrame()
|
||||||
|
{
|
||||||
|
_forceSamples.Clear();
|
||||||
|
_peakLineSamples.Clear();
|
||||||
|
_averageLineSamples.Clear();
|
||||||
|
_currentPointSample.Clear();
|
||||||
|
_currentPointSample.Add(new ObservablePoint(0, EmptyChartPointForceN));
|
||||||
|
SetAxisLimits(GetEmptyChartXAxisMaxLimit(), EmptyChartYAxisMaxLimit);
|
||||||
|
_kineticBand.Xi = Recipe.TravelMm * 0.35;
|
||||||
|
_kineticBand.Xj = Recipe.TravelMm;
|
||||||
|
_kineticBand.Yi = 0;
|
||||||
|
_kineticBand.Yj = EmptyChartYAxisMaxLimit;
|
||||||
|
OnPropertyChanged(nameof(ForceSections));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshEmptyRealtimeChartFrameIfVisible()
|
||||||
|
{
|
||||||
|
if (_machineRuntimeState != MachineRuntimeState.Idle ||
|
||||||
|
_isShowingHistoricalRun ||
|
||||||
|
_currentRunSamples.Count > 0 ||
|
||||||
|
_forceSamples.Count > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowEmptyRealtimeChartFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double GetEmptyChartXAxisMaxLimit()
|
||||||
|
{
|
||||||
|
return Math.Max(Recipe.TravelMm, MinimumEmptyChartXAxisMaxLimit);
|
||||||
|
}
|
||||||
|
|
||||||
private void ResetRealtimePresentation()
|
private void ResetRealtimePresentation()
|
||||||
{
|
{
|
||||||
_forceSamples.Clear();
|
_forceSamples.Clear();
|
||||||
@@ -1692,13 +1729,7 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
CurrentKineticCoefficient = 0;
|
CurrentKineticCoefficient = 0;
|
||||||
TrialProgressPercent = 0;
|
TrialProgressPercent = 0;
|
||||||
|
|
||||||
SetAxisLimits(1, 0.5);
|
ShowEmptyRealtimeChartFrame();
|
||||||
_kineticBand.Xi = Recipe.TravelMm * 0.35;
|
|
||||||
_kineticBand.Xj = Recipe.TravelMm;
|
|
||||||
_kineticBand.Yi = 0;
|
|
||||||
_kineticBand.Yj = 0.5;
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(ForceSections));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetActiveRunContext()
|
private void ResetActiveRunContext()
|
||||||
@@ -1799,6 +1830,12 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
{
|
{
|
||||||
AddWarningEvent($"测试参数写入 PLC 失败 {e.PropertyName}: {ex.Message}");
|
AddWarningEvent($"测试参数写入 PLC 失败 {e.PropertyName}: {ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (e.PropertyName == nameof(TestRecipe.TravelMm))
|
||||||
|
{
|
||||||
|
RefreshEmptyRealtimeChartFrameIfVisible();
|
||||||
|
RaiseStatusProperties();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SyncRecipeFromPlcAsync()
|
private async Task SyncRecipeFromPlcAsync()
|
||||||
@@ -1830,6 +1867,9 @@ public sealed class MainViewModel : ObservableObject, IDisposable
|
|||||||
{
|
{
|
||||||
_isSyncingRecipeFromPlc = false;
|
_isSyncingRecipeFromPlc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefreshEmptyRealtimeChartFrameIfVisible();
|
||||||
|
RaiseStatusProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SyncRecipePropertyToPlcAsync(string propertyName)
|
private async Task SyncRecipePropertyToPlcAsync(string propertyName)
|
||||||
|
|||||||
Reference in New Issue
Block a user