更新121

This commit is contained in:
GukSang.Jin
2026-05-25 18:41:36 +08:00
parent d4affddd6e
commit 6965d39560
5 changed files with 218 additions and 30 deletions

View File

@@ -7,6 +7,8 @@ public sealed class CValueCalibrationActionViewModel : ObservableObject
{
private bool _isActive;
private bool _isStatusKnown;
private bool _isBusy;
private string _busyDisplayText = string.Empty;
public CValueCalibrationActionViewModel(
string label,
@@ -54,11 +56,31 @@ public sealed class CValueCalibrationActionViewModel : ObservableObject
}
}
public string DisplayText => IsStatusKnown
public bool IsBusy
{
get => _isBusy;
private set
{
if (SetProperty(ref _isBusy, value))
{
OnPropertyChanged(nameof(DisplayText));
OnPropertyChanged(nameof(StatusText));
OnPropertyChanged(nameof(IsEnabled));
}
}
}
public bool IsEnabled => !IsBusy;
public string DisplayText => IsBusy
? _busyDisplayText
: IsStatusKnown
? IsActive ? ActiveDisplayText : InactiveDisplayText
: $"{Label}:未知";
public string StatusText => IsStatusKnown
public string StatusText => IsBusy
? "进行中"
: IsStatusKnown
? IsActive ? "开启" : "关闭"
: "未知";
@@ -67,4 +89,21 @@ public sealed class CValueCalibrationActionViewModel : ObservableObject
IsStatusKnown = isStatusKnown;
IsActive = isActive;
}
public void BeginWaiting(string busyDisplayText)
{
_busyDisplayText = busyDisplayText;
IsStatusKnown = true;
IsActive = true;
IsBusy = true;
OnPropertyChanged(nameof(DisplayText));
OnPropertyChanged(nameof(StatusText));
}
public void FinishWaiting()
{
IsStatusKnown = true;
IsActive = false;
IsBusy = false;
}
}

View File

@@ -48,7 +48,9 @@ public sealed class CValueCalibrationViewModel : PageViewModel
private readonly Action _calibrationCompletedAction;
private readonly ITcpDeviceConnectionService _tcpDeviceConnectionService;
private readonly DispatcherTimer _refreshTimer;
private readonly DispatcherTimer _pairedActionCompletionTimer;
private readonly Dictionary<string, CValueCalibrationActionViewModel> _actionsByLabel = [];
private readonly Dictionary<string, PairedActionWaitState> _pairedActionWaitStates = [];
private readonly HashSet<ushort> _loggedFloatDiagnostics = [];
private readonly HashSet<ushort> _loggedInvalidFloatDiagnostics = [];
private string _baselineOxygenText = "";
@@ -90,6 +92,22 @@ public sealed class CValueCalibrationViewModel : PageViewModel
];
_actionsByLabel[CalibrationStartAction].UpdateStatus(false);
_actionsByLabel[BaselineCollectionAction].UpdateStatus(false);
_pairedActionWaitStates[CalibrationStartAction] = new PairedActionWaitState(
CalibrationEndCoil,
"标定中",
"标定完成",
_calibrationCompletedAction);
_pairedActionWaitStates[BaselineCollectionAction] = new PairedActionWaitState(
BaselineEndCoil,
"基线采集中",
"基线采集完成",
_baselineCollectionCompletedAction);
_pairedActionCompletionTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(250)
};
_pairedActionCompletionTimer.Tick += (_, _) => RefreshPairedActionCompletions();
RefreshDeviceValues();
_refreshTimer = new DispatcherTimer
@@ -155,14 +173,13 @@ public sealed class CValueCalibrationViewModel : PageViewModel
return;
}
LastAction = action;
if (IsPairedAction(action))
{
TogglePairedAction(action);
StartPairedAction(action);
return;
}
LastAction = action;
ToggleHoldAction(action);
}
@@ -324,7 +341,7 @@ public sealed class CValueCalibrationViewModel : PageViewModel
Debug.WriteLine($"C value calibration action '{action}' write failed.");
}
private void TogglePairedAction(string action)
private void StartPairedAction(string action)
{
if (!TryGetPairedActionCoils(action, out var startCoilAddress, out var endCoilAddress, out var endActionText))
{
@@ -336,34 +353,98 @@ public sealed class CValueCalibrationViewModel : PageViewModel
return;
}
var isActive = actionViewModel.IsActive;
var coilAddress = isActive ? endCoilAddress : startCoilAddress;
var actionText = isActive ? endActionText : action;
if (TryStartCoilPulse(coilAddress, actionText))
if (actionViewModel.IsBusy)
{
var completedBaselineCollection = action == BaselineCollectionAction && isActive;
var completedCalibration = action == CalibrationStartAction && isActive;
LastAction = completedBaselineCollection
? "基线采集完成"
: completedCalibration ? "标定完成" : actionText;
actionViewModel.UpdateStatus(!isActive);
if (completedBaselineCollection)
{
_baselineCollectionCompletedAction();
}
if (completedCalibration)
{
_calibrationCompletedAction();
}
return;
}
LastAction = $"{actionText}失败";
Debug.WriteLine($"C value calibration action '{actionText}' write failed.");
if (!_pairedActionWaitStates.TryGetValue(action, out var waitState))
{
return;
}
if (!TryStartCoilPulse(startCoilAddress, action))
{
LastAction = $"{action}失败";
Debug.WriteLine($"C value calibration action '{action}' write failed.");
return;
}
var completionIsAlreadyActive = _tcpDeviceConnectionService.TryReadCoil(endCoilAddress, out var isComplete) && isComplete;
waitState.Begin(completionIsAlreadyActive);
actionViewModel.BeginWaiting(waitState.WaitingText);
_pairedActionCompletionTimer.Start();
LastAction = waitState.WaitingText;
if (completionIsAlreadyActive)
{
Debug.WriteLine(
$"C value calibration completion coil {endCoilAddress} was already active when '{action}' started; "
+ "waiting for it to reset before accepting completion.");
}
}
private void RefreshPairedActionCompletions()
{
var hasWaitingAction = false;
foreach (var (action, waitState) in _pairedActionWaitStates)
{
if (!waitState.IsWaiting)
{
continue;
}
hasWaitingAction = true;
if (!_actionsByLabel.TryGetValue(action, out var actionViewModel))
{
continue;
}
if (!_tcpDeviceConnectionService.TryReadCoil(waitState.CompletionCoilAddress, out var isComplete))
{
LastAction = $"{waitState.WaitingText},完成状态读取失败";
Debug.WriteLine(
$"C value calibration completion coil {waitState.CompletionCoilAddress} read failed for '{action}'.");
continue;
}
if (!isComplete)
{
waitState.MarkCompletionInactive();
continue;
}
if (waitState.RequiresInactiveBeforeCompletion && !waitState.HasSeenInactiveCompletionState)
{
continue;
}
CompletePairedAction(waitState, actionViewModel);
}
if (!hasWaitingAction)
{
_pairedActionCompletionTimer.Stop();
}
}
private void CompletePairedAction(
PairedActionWaitState waitState,
CValueCalibrationActionViewModel actionViewModel)
{
LastAction = waitState.CompletedText;
waitState.End();
try
{
waitState.CompletedAction();
}
finally
{
actionViewModel.FinishWaiting();
}
}
private bool TryStartCoilPulse(ushort coilAddress, string actionText)
@@ -441,4 +522,44 @@ public sealed class CValueCalibrationViewModel : PageViewModel
{
return action is BaselineCollectionAction or CalibrationStartAction;
}
private sealed class PairedActionWaitState(
ushort completionCoilAddress,
string waitingText,
string completedText,
Action completedAction)
{
public ushort CompletionCoilAddress { get; } = completionCoilAddress;
public string WaitingText { get; } = waitingText;
public string CompletedText { get; } = completedText;
public Action CompletedAction { get; } = completedAction;
public bool IsWaiting { get; private set; }
public bool RequiresInactiveBeforeCompletion { get; private set; }
public bool HasSeenInactiveCompletionState { get; private set; }
public void Begin(bool completionIsAlreadyActive)
{
IsWaiting = true;
RequiresInactiveBeforeCompletion = completionIsAlreadyActive;
HasSeenInactiveCompletionState = !completionIsAlreadyActive;
}
public void MarkCompletionInactive()
{
HasSeenInactiveCompletionState = true;
}
public void End()
{
IsWaiting = false;
RequiresInactiveBeforeCompletion = false;
HasSeenInactiveCompletionState = false;
}
}
}

View File

@@ -231,6 +231,7 @@
<Button Content="{Binding DisplayText}"
Command="{Binding Command}"
CommandParameter="{Binding Label}"
IsEnabled="{Binding IsEnabled}"
Width="150"
Height="42"
Margin="0,5,14,5"
@@ -252,6 +253,7 @@
<Button Content="{Binding DisplayText}"
Command="{Binding Command}"
CommandParameter="{Binding Label}"
IsEnabled="{Binding IsEnabled}"
Width="150"
Height="42"
Margin="0,5,24,5"

View File

@@ -16,6 +16,11 @@
BorderBrush="#AEB7B2"
BorderThickness="1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="72" />
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<TextBlock Text="{Binding BodyText}"
@@ -26,6 +31,21 @@
LineHeight="43"
TextWrapping="Wrap" />
</ScrollViewer>
<Border Grid.Row="1"
BorderBrush="#D7DEDA"
BorderThickness="0,1,0,0"
Background="#F7F9F8">
<Button Content="确定"
Width="120"
Height="42"
Margin="0,0,24,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
IsDefault="True"
Click="ConfirmButton_Click"
Style="{StaticResource InstrumentButtonStyle}" />
</Border>
</Grid>
</Border>
</Grid>

View File

@@ -10,4 +10,10 @@ public partial class HelpDialogWindow : Window
InitializeComponent();
DataContext = new HelpDialogViewModel(headerText, titleText, bodyText);
}
private void ConfirmButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
}