更新121
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user