更新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 _isActive;
private bool _isStatusKnown; private bool _isStatusKnown;
private bool _isBusy;
private string _busyDisplayText = string.Empty;
public CValueCalibrationActionViewModel( public CValueCalibrationActionViewModel(
string label, 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 ? IsActive ? ActiveDisplayText : InactiveDisplayText
: $"{Label}:未知"; : $"{Label}:未知";
public string StatusText => IsStatusKnown public string StatusText => IsBusy
? "进行中"
: IsStatusKnown
? IsActive ? "开启" : "关闭" ? IsActive ? "开启" : "关闭"
: "未知"; : "未知";
@@ -67,4 +89,21 @@ public sealed class CValueCalibrationActionViewModel : ObservableObject
IsStatusKnown = isStatusKnown; IsStatusKnown = isStatusKnown;
IsActive = isActive; 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 Action _calibrationCompletedAction;
private readonly ITcpDeviceConnectionService _tcpDeviceConnectionService; private readonly ITcpDeviceConnectionService _tcpDeviceConnectionService;
private readonly DispatcherTimer _refreshTimer; private readonly DispatcherTimer _refreshTimer;
private readonly DispatcherTimer _pairedActionCompletionTimer;
private readonly Dictionary<string, CValueCalibrationActionViewModel> _actionsByLabel = []; private readonly Dictionary<string, CValueCalibrationActionViewModel> _actionsByLabel = [];
private readonly Dictionary<string, PairedActionWaitState> _pairedActionWaitStates = [];
private readonly HashSet<ushort> _loggedFloatDiagnostics = []; private readonly HashSet<ushort> _loggedFloatDiagnostics = [];
private readonly HashSet<ushort> _loggedInvalidFloatDiagnostics = []; private readonly HashSet<ushort> _loggedInvalidFloatDiagnostics = [];
private string _baselineOxygenText = ""; private string _baselineOxygenText = "";
@@ -90,6 +92,22 @@ public sealed class CValueCalibrationViewModel : PageViewModel
]; ];
_actionsByLabel[CalibrationStartAction].UpdateStatus(false); _actionsByLabel[CalibrationStartAction].UpdateStatus(false);
_actionsByLabel[BaselineCollectionAction].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(); RefreshDeviceValues();
_refreshTimer = new DispatcherTimer _refreshTimer = new DispatcherTimer
@@ -155,14 +173,13 @@ public sealed class CValueCalibrationViewModel : PageViewModel
return; return;
} }
LastAction = action;
if (IsPairedAction(action)) if (IsPairedAction(action))
{ {
TogglePairedAction(action); StartPairedAction(action);
return; return;
} }
LastAction = action;
ToggleHoldAction(action); ToggleHoldAction(action);
} }
@@ -324,7 +341,7 @@ public sealed class CValueCalibrationViewModel : PageViewModel
Debug.WriteLine($"C value calibration action '{action}' write failed."); 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)) if (!TryGetPairedActionCoils(action, out var startCoilAddress, out var endCoilAddress, out var endActionText))
{ {
@@ -336,34 +353,98 @@ public sealed class CValueCalibrationViewModel : PageViewModel
return; return;
} }
var isActive = actionViewModel.IsActive; if (actionViewModel.IsBusy)
var coilAddress = isActive ? endCoilAddress : startCoilAddress;
var actionText = isActive ? endActionText : action;
if (TryStartCoilPulse(coilAddress, actionText))
{ {
var completedBaselineCollection = action == BaselineCollectionAction && isActive;
var completedCalibration = action == CalibrationStartAction && isActive;
LastAction = completedBaselineCollection
? "基线采集完成"
: completedCalibration ? "标定完成" : actionText;
actionViewModel.UpdateStatus(!isActive);
if (completedBaselineCollection)
{
_baselineCollectionCompletedAction();
}
if (completedCalibration)
{
_calibrationCompletedAction();
}
return; return;
} }
LastAction = $"{actionText}失败"; if (!_pairedActionWaitStates.TryGetValue(action, out var waitState))
Debug.WriteLine($"C value calibration action '{actionText}' write failed."); {
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) private bool TryStartCoilPulse(ushort coilAddress, string actionText)
@@ -441,4 +522,44 @@ public sealed class CValueCalibrationViewModel : PageViewModel
{ {
return action is BaselineCollectionAction or CalibrationStartAction; 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}" <Button Content="{Binding DisplayText}"
Command="{Binding Command}" Command="{Binding Command}"
CommandParameter="{Binding Label}" CommandParameter="{Binding Label}"
IsEnabled="{Binding IsEnabled}"
Width="150" Width="150"
Height="42" Height="42"
Margin="0,5,14,5" Margin="0,5,14,5"
@@ -252,6 +253,7 @@
<Button Content="{Binding DisplayText}" <Button Content="{Binding DisplayText}"
Command="{Binding Command}" Command="{Binding Command}"
CommandParameter="{Binding Label}" CommandParameter="{Binding Label}"
IsEnabled="{Binding IsEnabled}"
Width="150" Width="150"
Height="42" Height="42"
Margin="0,5,24,5" Margin="0,5,24,5"

View File

@@ -16,6 +16,11 @@
BorderBrush="#AEB7B2" BorderBrush="#AEB7B2"
BorderThickness="1"> BorderThickness="1">
<Grid> <Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="72" />
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" <ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"> HorizontalScrollBarVisibility="Disabled">
<TextBlock Text="{Binding BodyText}" <TextBlock Text="{Binding BodyText}"
@@ -26,6 +31,21 @@
LineHeight="43" LineHeight="43"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
</ScrollViewer> </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> </Grid>
</Border> </Border>
</Grid> </Grid>

View File

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