initial commit

This commit is contained in:
2026-04-11 12:45:18 +02:00
commit 6e1b929e2f
1246 changed files with 177580 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
<Window x:Class="HC_APTBS.Views.Dialogs.KlineErrorsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Title="K-Line Fault Codes"
Height="400" Width="600"
ResizeMode="CanResize"
WindowStartupLocation="CenterOwner">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!-- Header + action buttons -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Fault codes:" VerticalAlignment="Center" FontSize="14" FontWeight="SemiBold"/>
<Button Grid.Column="1" Content="Read" Margin="0,2,8,2"
Width="75" Height="24"
Command="{Binding ReadErrorsCommand}"/>
<Button Grid.Column="2" Content="Clear" Margin="0,2,0,2"
Width="75" Height="24"
Command="{Binding ClearErrorsCommand}"/>
</Grid>
<!-- Fault code text -->
<TextBox Grid.Row="1"
Text="{Binding ErrorText, Mode=OneWay}"
IsReadOnly="True" IsReadOnlyCaretVisible="True"
TextWrapping="Wrap"
FontFamily="Consolas" FontSize="12"
VerticalScrollBarVisibility="Auto"/>
</Grid>
<!-- Footer: progress bar + close button -->
<Grid Grid.Row="1" Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ProgressBar Value="{Binding ProgressPercent, Mode=OneWay}"
Minimum="0" Maximum="100"
VerticalAlignment="Center" Margin="0,0,10,0"/>
<Button Grid.Column="1" Content="Close" Width="80" Height="24"
VerticalAlignment="Center"
Command="{Binding CloseCommand}"/>
</Grid>
</Grid>
</Window>

View File

@@ -0,0 +1,18 @@
using System.Windows;
using HC_APTBS.ViewModels.Dialogs;
namespace HC_APTBS.Views.Dialogs
{
/// <summary>
/// Dialog for reading and clearing K-Line (KWP2000) fault codes from the pump ECU.
/// </summary>
public partial class KlineErrorsDialog : Window
{
public KlineErrorsDialog(KlineErrorsViewModel vm)
{
InitializeComponent();
DataContext = vm;
vm.RequestClose += Close;
}
}
}

View File

@@ -0,0 +1,33 @@
<Window x:Class="HC_APTBS.Views.Dialogs.ProgressDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Title="{Binding Title}"
Height="150" Width="450"
WindowStyle="None" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
Topmost="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Text="{Binding VerboseMessage, Mode=OneWay}"
IsReadOnly="True"
TextWrapping="Wrap"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
FontSize="14"
BorderThickness="0"
Background="White"/>
<ProgressBar Grid.Row="1"
Value="{Binding ProgressPercent, Mode=OneWay}"
Minimum="0" Maximum="100"
Height="15" Margin="30,0" VerticalAlignment="Center"/>
</Grid>
</Window>

View File

@@ -0,0 +1,19 @@
using System.Windows;
using HC_APTBS.ViewModels.Dialogs;
namespace HC_APTBS.Views.Dialogs
{
/// <summary>
/// Modal progress dialog shown during long-running K-Line operations.
/// Close by calling <see cref="Window.Close"/> from outside (the ViewModel raises
/// <see cref="ProgressViewModel"/> events, not this window).
/// </summary>
public partial class ProgressDialog : Window
{
public ProgressDialog(ProgressViewModel vm)
{
InitializeComponent();
DataContext = vm;
}
}
}

View File

@@ -0,0 +1,123 @@
<Window x:Class="HC_APTBS.Views.Dialogs.ReportDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Title="Generate Report"
Height="450" Width="800"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Section labels row -->
<RowDefinition Height="Auto"/> <!-- Name row -->
<RowDefinition Height="130"/> <!-- Info text -->
<RowDefinition Height="120"/> <!-- Observations / operator -->
<RowDefinition Height="Auto"/> <!-- Buttons -->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/> <!-- Client list -->
<ColumnDefinition Width="1*"/> <!-- Client data -->
<ColumnDefinition Width="1*"/> <!-- Company data -->
</Grid.ColumnDefinitions>
<!-- ── Column separators ───────────────────────────────────────────── -->
<Border BorderBrush="DarkGray" BorderThickness="1,0,0,0"
Grid.Column="2" Grid.RowSpan="5" Margin="-3,10,0,0"/>
<!-- ── Section headers ─────────────────────────────────────────────── -->
<TextBlock Text="Client List" FontSize="14" FontWeight="SemiBold"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10"/>
<TextBlock Grid.Column="1" Text="Client Data" FontSize="20" FontWeight="SemiBold"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10"/>
<TextBlock Grid.Column="2" Text="Company Data" FontSize="20" FontWeight="SemiBold"
HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,10"/>
<!-- ── Client list ─────────────────────────────────────────────────── -->
<ListBox Grid.Row="1" Grid.RowSpan="3" Margin="10,0"
ItemsSource="{Binding ClientNames}"
SelectedItem="{Binding SelectedClientName}"/>
<!-- ── Client name (editable ComboBox) ─────────────────────────────── -->
<Grid Grid.Column="1" Grid.Row="1" Margin="8,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Content="Name:" VerticalAlignment="Center" FontSize="13"/>
<ComboBox Grid.Column="1" IsEditable="True"
ItemsSource="{Binding ClientNames}"
Text="{Binding SelectedClientName, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" FontSize="13" Margin="4,0"/>
<Button Grid.Column="2" Content="Save" Width="60" Height="24"
Command="{Binding SaveClientCommand}"/>
</Grid>
<!-- ── Client info text ─────────────────────────────────────────────── -->
<GroupBox Grid.Column="1" Grid.Row="2" Header="Client information"
Margin="8,0,8,4" FontSize="13">
<TextBox Text="{Binding ClientInfo, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" AcceptsReturn="True"
BorderBrush="{x:Null}" FontSize="12"/>
</GroupBox>
<!-- ── Observations ─────────────────────────────────────────────────── -->
<GroupBox Grid.Column="1" Grid.Row="3" Header="Observations"
Margin="8,0,8,4" FontSize="13">
<TextBox Text="{Binding Observations, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap"
BorderBrush="{x:Null}" FontSize="12"/>
</GroupBox>
<!-- ── Operator name ────────────────────────────────────────────────── -->
<Grid Grid.Column="2" Grid.Row="1" Margin="8,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Operator:" VerticalAlignment="Center" FontSize="13"/>
<TextBox Grid.Column="1" Text="{Binding OperatorName, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" FontSize="13" Margin="4,0" Height="24"/>
</Grid>
<!-- ── Company name ─────────────────────────────────────────────────── -->
<Grid Grid.Column="2" Grid.Row="2" Margin="8,0,8,4" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Content="Company:" VerticalAlignment="Center" FontSize="13"/>
<TextBox Grid.Column="1" Text="{Binding CompanyName, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" FontSize="13" Margin="4,0" Height="24"/>
</Grid>
<GroupBox Grid.Row="1" Header="Company information"
Margin="0,4,0,0" FontSize="13">
<TextBox Text="{Binding CompanyInfo, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" AcceptsReturn="True"
BorderBrush="{x:Null}" FontSize="12"/>
</GroupBox>
</Grid>
<!-- ── Buttons row ──────────────────────────────────────────────────── -->
<Button Grid.Row="4" Grid.Column="0"
Content="Delete Client" Padding="6,2" Margin="10,8,0,8"
HorizontalAlignment="Left"
Command="{Binding DeleteClientCommand}"/>
<StackPanel Grid.Row="4" Grid.Column="2"
Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,8,10,8">
<Button Content="Generate" Width="80" Height="24" Margin="0,0,8,0"
Command="{Binding AcceptCommand}"/>
<Button Content="Cancel" Width="80" Height="24"
Command="{Binding CancelCommand}"/>
</StackPanel>
</Grid>
</Window>

View File

@@ -0,0 +1,19 @@
using System.Windows;
using HC_APTBS.ViewModels.Dialogs;
namespace HC_APTBS.Views.Dialogs
{
/// <summary>
/// Dialog that collects operator, client, and company information before
/// generating the PDF test report.
/// </summary>
public partial class ReportDialog : Window
{
public ReportDialog(ReportViewModel vm)
{
InitializeComponent();
DataContext = vm;
vm.RequestClose += Close;
}
}
}

View File

@@ -0,0 +1,77 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.BenchParamConfigView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,7">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<Border BorderBrush="Black" BorderThickness="2" Padding="8">
<StackPanel>
<!-- Parameter name -->
<TextBlock Text="{Binding Name}"
FontSize="16" FontWeight="Bold" Foreground="Black"
Margin="0,0,0,4"/>
<Separator Margin="0,0,0,6"/>
<!-- CAN frame fields -->
<WrapPanel Margin="0,0,0,4">
<Label Content="CAN-Bus ID (0x)" VerticalAlignment="Bottom" Foreground="Black"/>
<TextBox Text="{Binding MessageIdHex, UpdateSourceTrigger=LostFocus}"
Width="40" VerticalAlignment="Center"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19"/>
<Label Content="Byte L" VerticalAlignment="Bottom" Foreground="Black" Margin="8,0,0,0"/>
<TextBox Text="{Binding ByteL, UpdateSourceTrigger=LostFocus}"
Width="35" VerticalAlignment="Center"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19"/>
<Label Content="Byte H" VerticalAlignment="Bottom" Foreground="Black" Margin="8,0,0,0"/>
<TextBox Text="{Binding ByteH, UpdateSourceTrigger=LostFocus}"
Width="35" VerticalAlignment="Center"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19"/>
<Label Content="Filter α" VerticalAlignment="Bottom" Foreground="Black" Margin="8,0,0,0"/>
<TextBox Text="{Binding Alpha, UpdateSourceTrigger=LostFocus}"
Width="40" VerticalAlignment="Center"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19"/>
<CheckBox Content="Enable formula" IsChecked="{Binding FormulaEnabled}"
VerticalAlignment="Center" Foreground="Black" Margin="12,0,0,0"/>
</WrapPanel>
<!-- Calibration coefficients — visible only when formula is enabled -->
<WrapPanel Margin="0,2,0,0"
Visibility="{Binding FormulaEnabled, Converter={StaticResource BoolToVis}}">
<Label Content="P1:" Foreground="Black"/>
<TextBox Text="{Binding P1, UpdateSourceTrigger=LostFocus}"
Width="45" VerticalAlignment="Center" FontSize="13"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19" Margin="0,0,8,0"/>
<Label Content="P2:" Foreground="Black"/>
<TextBox Text="{Binding P2, UpdateSourceTrigger=LostFocus}"
Width="45" VerticalAlignment="Center" FontSize="13"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19" Margin="0,0,8,0"/>
<Label Content="P3:" Foreground="Black"/>
<TextBox Text="{Binding P3, UpdateSourceTrigger=LostFocus}"
Width="45" VerticalAlignment="Center" FontSize="13"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19" Margin="0,0,8,0"/>
<Label Content="P4:" Foreground="Black"/>
<TextBox Text="{Binding P4, UpdateSourceTrigger=LostFocus}"
Width="45" VerticalAlignment="Center" FontSize="13"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19" Margin="0,0,8,0"/>
<Label Content="P5:" Foreground="Black"/>
<TextBox Text="{Binding P5, UpdateSourceTrigger=LostFocus}"
Width="45" VerticalAlignment="Center" FontSize="13"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19" Margin="0,0,8,0"/>
<Label Content="P6:" Foreground="Black"/>
<TextBox Text="{Binding P6, UpdateSourceTrigger=LostFocus}"
Width="45" VerticalAlignment="Center" FontSize="13"
Background="#66FFFFFF" BorderBrush="{x:Null}" Height="19"/>
</WrapPanel>
</StackPanel>
</Border>
</UserControl>

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>Code-behind for BenchParamConfigView — no logic; all behaviour is in the ViewModel.</summary>
public partial class BenchParamConfigView : UserControl
{
public BenchParamConfigView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,104 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.DfiManageView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="800" MaxHeight="150">
<UserControl.Resources>
<Style x:Key="LcdGreen" TargetType="Border">
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="BorderBrush">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="DarkSlateGray" Offset="0"/>
<GradientStop Color="LawnGreen" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="LawnGreen" Offset="0"/>
<GradientStop Color="#57B000" Offset="1.5"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid Margin="50,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="450"/>
</Grid.ColumnDefinitions>
<!-- LEFT: version picker + read/write buttons -->
<ComboBox Margin="5" VerticalAlignment="Bottom"
SelectedIndex="{Binding VersionIndex}">
<ComboBoxItem Content="V1"/>
<ComboBoxItem Content="V2"/>
<ComboBoxItem Content="V3"/>
<ComboBoxItem Content="V4"/>
</ComboBox>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="READ" Margin="2"
Command="{Binding ReadDfiCommand}"
FontSize="12" FontWeight="Bold" Padding="4"/>
<Button Grid.Column="1" Content="WRITE" Margin="2"
Command="{Binding WriteDfiCommand}"
FontSize="12" FontWeight="Bold" Padding="4"/>
</Grid>
<!-- TOP RIGHT: DFI value LCD + auto checkbox -->
<Grid Grid.Row="0" Grid.Column="1" Margin="150,5">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" Style="{StaticResource LcdGreen}"/>
<Border Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="Black" SnapsToDevicePixels="True"/>
<TextBlock Text="DFI:"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Foreground="Black" FontSize="18" FontFamily="Consolas"/>
<TextBlock Text="{Binding CurrentDfi, StringFormat=F2, Mode=OneWay}"
Grid.Column="1"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="26" FontWeight="Bold" Foreground="Black"/>
</Grid>
<!-- AUTO checkbox — sits outside the column pair; placed in Column=1 outside normal layout -->
<CheckBox IsChecked="{Binding IsAutoMode}"
Content="AUTO"
Grid.Row="0" Grid.Column="1"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,10,0"
Foreground="Black" FontSize="20"/>
<!-- BOTTOM RIGHT: slider with range labels + current value -->
<Grid Grid.Row="1" Grid.Column="1">
<Slider Value="{Binding SliderRaw}"
Minimum="-145" Maximum="145"
TickFrequency="5" SmallChange="5" LargeChange="5"
IsSnapToTickEnabled="True" TickPlacement="BottomRight"
Margin="10,0" VerticalAlignment="Center"
Foreground="Black"/>
<TextBlock Text="-1.45" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="10,0,0,0" Foreground="DimGray"/>
<TextBlock Text="+1.45" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,0" Foreground="DimGray"/>
<TextBlock Text="{Binding SliderDfiValue, StringFormat=F2, Mode=OneWay}"
HorizontalAlignment="Center" VerticalAlignment="Bottom"
Margin="0,0,0,4" FontSize="20" Foreground="Black"/>
</Grid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>Code-behind for DfiManageView — no logic; all behaviour is in the ViewModel.</summary>
public partial class DfiManageView : UserControl
{
public DfiManageView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,194 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="260" d:DesignWidth="440"
IsEnabled="{Binding IsEnabled}">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<!-- Shared style for the settings popup min/max/step text boxes -->
<Style x:Key="SettingsTextBox" TargetType="TextBox">
<Setter Property="Width" Value="40"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!-- Label inside settings popup -->
<Style x:Key="SettingsLabel" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Bottom"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="0,2,0,0"/>
</Style>
</UserControl.Resources>
<StackPanel>
<!-- ═══ FBKW — Advance Control ═══════════════════════════════════════ -->
<Grid Margin="6,6,6,2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="FBKW - Advance Control" HorizontalAlignment="Center"
FontSize="13" Foreground="Black" Margin="0,0,0,2"/>
<DockPanel Grid.Row="1" Margin="4,0,4,2">
<!-- Settings button -->
<ToggleButton x:Name="FbkwSettingsToggle" DockPanel.Dock="Left"
Width="28" Height="28" Margin="0,0,4,0"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="14"
ToolTip="Min / Step / Max"/>
<!-- Numeric text box -->
<TextBox DockPanel.Dock="Right" Width="50" Height="28" Margin="4,0,0,0"
TextAlignment="Center" VerticalContentAlignment="Center"
FontWeight="Bold" FontSize="13"
Text="{Binding FbkwValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"/>
<!-- Slider -->
<Slider Minimum="{Binding FbkwMin}" Maximum="{Binding FbkwMax}"
Value="{Binding FbkwValue}" TickFrequency="{Binding FbkwStep}"
TickPlacement="BottomRight" AutoToolTipPrecision="2"
IsSnapToTickEnabled="True" VerticalAlignment="Center"
Focusable="False" Foreground="Black"/>
</DockPanel>
<!-- Settings popup -->
<Popup IsOpen="{Binding IsChecked, ElementName=FbkwSettingsToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True"
HorizontalOffset="30">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwMin, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Min" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwStep, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Step" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding FbkwMax, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Max" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</Grid>
<!-- ═══ ME — Quantity Control ════════════════════════════════════════ -->
<Grid Margin="6,4,6,2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="ME - Quantity Control" HorizontalAlignment="Center"
FontSize="13" Foreground="Black" Margin="0,0,0,2"/>
<DockPanel Grid.Row="1" Margin="4,0,4,2">
<ToggleButton x:Name="MeSettingsToggle" DockPanel.Dock="Left"
Width="28" Height="28" Margin="0,0,4,0"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="14"
ToolTip="Min / Step / Max"/>
<TextBox DockPanel.Dock="Right" Width="50" Height="28" Margin="4,0,0,0"
TextAlignment="Center" VerticalContentAlignment="Center"
FontWeight="Bold" FontSize="13"
Text="{Binding MeValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"/>
<Slider Minimum="{Binding MeMin}" Maximum="{Binding MeMax}"
Value="{Binding MeValue}" TickFrequency="{Binding MeStep}"
TickPlacement="BottomRight" AutoToolTipPrecision="2"
IsSnapToTickEnabled="False" VerticalAlignment="Center"
Focusable="False" Foreground="Black"/>
</DockPanel>
<Popup IsOpen="{Binding IsChecked, ElementName=MeSettingsToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True"
HorizontalOffset="30">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeMin, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Min" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeStep, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Step" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding MeMax, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Max" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</Grid>
<!-- ═══ PreIn — Pre-injection Quantity ═══════════════════════════════ -->
<Grid Margin="6,4,6,2"
Visibility="{Binding IsPreInVisible, Converter={StaticResource BoolToVis}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="ME - Pre-inj Quantity" HorizontalAlignment="Center"
FontSize="13" Foreground="Black" Margin="0,0,0,2"/>
<DockPanel Grid.Row="1" Margin="4,0,4,2">
<ToggleButton x:Name="PreInSettingsToggle" DockPanel.Dock="Left"
Width="28" Height="28" Margin="0,0,4,0"
Background="Transparent" BorderBrush="Transparent"
Content="..." FontWeight="Bold" FontSize="14"
ToolTip="Min / Step / Max"/>
<TextBox DockPanel.Dock="Right" Width="50" Height="28" Margin="4,0,0,0"
TextAlignment="Center" VerticalContentAlignment="Center"
FontWeight="Bold" FontSize="13"
Text="{Binding PreInValue, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}"/>
<Slider Minimum="{Binding PreInMin}" Maximum="{Binding PreInMax}"
Value="{Binding PreInValue}" TickFrequency="{Binding PreInStep}"
TickPlacement="BottomRight" AutoToolTipPrecision="2"
IsSnapToTickEnabled="True" VerticalAlignment="Center"
Focusable="False" Foreground="Black"/>
</DockPanel>
<Popup IsOpen="{Binding IsChecked, ElementName=PreInSettingsToggle}"
StaysOpen="False" Placement="Bottom" AllowsTransparency="True"
HorizontalOffset="30">
<Border Background="#BB000000" Padding="8,6" CornerRadius="3">
<UniformGrid Columns="3" Width="180">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInMin, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Min" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInStep, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Step" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding PreInMax, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource SettingsTextBox}"/>
<TextBlock Text="Max" Style="{StaticResource SettingsLabel}" HorizontalAlignment="Center"/>
</StackPanel>
</UniformGrid>
</Border>
</Popup>
</Grid>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Manual pump control sliders (FBKW, ME, PreIn) with configurable min/max/step popups.
/// </summary>
public partial class PumpControlView : UserControl
{
public PumpControlView()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,105 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.PumpIdentificationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</UserControl.Resources>
<StackPanel>
<!-- Pump selector -->
<Border BorderBrush="#999" BorderThickness="0,0,0,1" Padding="6,8">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Pump:" VerticalAlignment="Center" Margin="0,0,8,0" FontSize="14"/>
<ComboBox Grid.Column="1"
ItemsSource="{Binding PumpIds}"
SelectedItem="{Binding SelectedPumpId}"
FontSize="14" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Margin="8,0,0,0"
Text="{Binding CurrentPump.Model}" FontSize="12"
Foreground="Gray" VerticalAlignment="Center"/>
</Grid>
</Border>
<!-- K-Line ECU info + read button -->
<Border BorderBrush="#999" BorderThickness="0,0,0,1" Padding="6,6">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="DFI:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineDfi}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Pump ID:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlinePumpId}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Serial No:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineSerialNumber}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Model Ref:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineModelRef}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data Record:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineDataRecord}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Pump Ctrl:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlinePumpControl}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Model Index:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineModelIndex}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="SW Ver 1:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineSwVersion1}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="SW Ver 2:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineSwVersion2}" FontSize="12" FontFamily="Consolas"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Errors:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineErrors}" FontSize="12" FontFamily="Consolas" Foreground="DarkRed"/>
</StackPanel>
<!-- ConnectError row: auto-collapses when empty via DataTrigger -->
<StackPanel Orientation="Horizontal">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding KlineConnectError}" Value="">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBlock Text="Error:" FontSize="12" Margin="0,0,4,0" Foreground="Gray" Width="90"/>
<TextBlock Text="{Binding KlineConnectError}" FontSize="12" FontFamily="Consolas" Foreground="Red"/>
</StackPanel>
</StackPanel>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="6,0,0,0">
<Button Content="Read K-Line" Width="90" Margin="0,2"
Command="{Binding ReadKlineCommand}"/>
<!-- Progress bar shown during K-Line read -->
<ProgressBar Value="{Binding ProgressPercent, Mode=OneWay}"
Minimum="0" Maximum="100" Height="6"
Visibility="{Binding IsReading, Converter={StaticResource BoolToVis}}"/>
</StackPanel>
</Grid>
</Border>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,14 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Pump identification and K-Line ECU info display.
/// DataContext is <see cref="HC_APTBS.ViewModels.PumpIdentificationViewModel"/>.
/// </summary>
public partial class PumpIdentificationView : UserControl
{
/// <summary>Initialises the component.</summary>
public PumpIdentificationView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,125 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.ResultDisplayView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:conv="clr-namespace:HC_APTBS.Converters"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="700">
<UserControl.Resources>
<conv:BoolToPassFailBrushConverter x:Key="PassFailBrush"/>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<!-- Overall result banner style -->
<Style x:Key="OverallBannerStyle" TargetType="Border">
<Setter Property="Padding" Value="6,3"/>
<Setter Property="Margin" Value="0,0,0,4"/>
<Style.Triggers>
<DataTrigger Binding="{Binding OverallPassed}" Value="True">
<Setter Property="Background" Value="#C8E6C9"/>
</DataTrigger>
<DataTrigger Binding="{Binding OverallPassed}" Value="False">
<Setter Property="Background" Value="#FFCDD2"/>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!-- Test name + overall result banner -->
<Border Style="{StaticResource OverallBannerStyle}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding TestName}"
FontSize="13" FontWeight="Bold" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Margin="0,0,4,0"
FontSize="13" FontWeight="Bold" VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding OverallPassed}" Value="True">
<Setter Property="Text" Value="PASS"/>
<Setter Property="Foreground" Value="#2E7D32"/>
</DataTrigger>
<DataTrigger Binding="{Binding OverallPassed}" Value="False">
<Setter Property="Text" Value="FAIL"/>
<Setter Property="Foreground" Value="#B71C1C"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
<!-- Column headers -->
<Grid Grid.Row="1" Margin="0,0,0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Phase" FontSize="10" FontWeight="Bold" Margin="3,0" Foreground="Gray"/>
<TextBlock Text="Parameter" FontSize="10" FontWeight="Bold" Margin="3,0" Foreground="Gray" Grid.Column="1"/>
<TextBlock Text="Target" FontSize="10" FontWeight="Bold" Margin="3,0" Foreground="Gray" Grid.Column="2"/>
<TextBlock Text="Tol ±" FontSize="10" FontWeight="Bold" Margin="3,0" Foreground="Gray" Grid.Column="3"/>
<TextBlock Text="Average" FontSize="10" FontWeight="Bold" Margin="3,0" Foreground="Gray" Grid.Column="4"/>
<TextBlock Text="Result" FontSize="10" FontWeight="Bold" Margin="3,0" Foreground="Gray" Grid.Column="5"/>
</Grid>
<!-- Result rows -->
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Results}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{Binding Passed, Converter={StaticResource PassFailBrush}}"
Margin="0,1" Padding="3,2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding PhaseName}" FontSize="11" Margin="3,0"/>
<TextBlock Text="{Binding ParameterName}" FontSize="11" Margin="3,0" Grid.Column="1"/>
<TextBlock Text="{Binding Target, StringFormat=F2}" FontSize="11" Margin="3,0" Grid.Column="2"/>
<TextBlock Text="{Binding Tolerance, StringFormat=F2}" FontSize="11" Margin="3,0" Grid.Column="3"/>
<TextBlock Text="{Binding Average, StringFormat=F2}" FontSize="11" Margin="3,0" Grid.Column="4"/>
<TextBlock Text="{Binding ResultLabel}" FontSize="11" FontWeight="Bold" Margin="3,0" Grid.Column="5">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Passed}" Value="True">
<Setter Property="Foreground" Value="#2E7D32"/>
</DataTrigger>
<DataTrigger Binding="{Binding Passed}" Value="False">
<Setter Property="Foreground" Value="#B71C1C"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>Code-behind for ResultDisplayView — no logic; all behaviour is in the ViewModel.</summary>
public partial class ResultDisplayView : UserControl
{
public ResultDisplayView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,56 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.StatusDisplayView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:conv="clr-namespace:HC_APTBS.Converters"
mc:Ignorable="d"
d:DesignHeight="70" d:DesignWidth="375">
<UserControl.Resources>
<conv:HexColorToBrushConverter x:Key="HexToBrush"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!-- Title -->
<TextBlock Text="{Binding Title}"
HorizontalAlignment="Center" VerticalAlignment="Center"
FontSize="14" FontWeight="SemiBold" Foreground="Black"/>
<!-- 16-bit indicator row -->
<ItemsControl Grid.Row="1"
ItemsSource="{Binding Bits}"
Margin="10,0,10,6">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- Each bit: coloured dot + bit-number label -->
<Grid Margin="1,0">
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Rectangle Fill="{Binding Color, Converter={StaticResource HexToBrush}}"
Stroke="#5D5D5D" StrokeThickness="1"
Width="12" Height="12"
HorizontalAlignment="Center" VerticalAlignment="Center"
ToolTip="{Binding Description}"
SnapsToDevicePixels="True"/>
<TextBlock Grid.Row="1" FontSize="8"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="DimGray"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>Code-behind for StatusDisplayView — no logic; all behaviour is in the ViewModel.</summary>
public partial class StatusDisplayView : UserControl
{
public StatusDisplayView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,123 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.TestDisplayView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="800"
Background="#FFEDEDED" Foreground="Black">
<UserControl.Resources>
<!-- Phase row style: highlight active/passed/failed -->
<Style x:Key="PhaseRowStyle" TargetType="Border">
<Setter Property="Padding" Value="6,4"/>
<Setter Property="Margin" Value="2,1"/>
<Setter Property="CornerRadius" Value="2"/>
<Setter Property="Background" Value="Transparent"/>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="34"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<!-- Header: test name + status -->
<Border BorderBrush="Gray" BorderThickness="0,0,0,1">
<Grid Margin="8,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding TestName}"
FontSize="22" FontFamily="Impact" FontStyle="Italic"
VerticalAlignment="Center" Foreground="Black" Padding="5,0"/>
<TextBlock Grid.Column="1"
Text="{Binding StatusText}"
FontSize="13" FontStyle="Italic" FontFamily="Impact"
VerticalAlignment="Bottom" Foreground="Gray" Padding="10,0,0,4"/>
<TextBlock Grid.Column="2"
VerticalAlignment="Center" Foreground="DimGray" FontSize="12" Margin="0,0,8,0">
<Run Text="~"/>
<Run Text="{Binding RemainingSeconds, Mode=OneWay}"/>
<Run Text="s"/>
</TextBlock>
</Grid>
</Border>
<!-- Phase list (horizontal scroll) -->
<ScrollViewer Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled"
MinHeight="120">
<ItemsControl ItemsSource="{Binding Phases}" Margin="4,4,4,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- One card per phase -->
<Border Width="90" Margin="2,0" BorderThickness="1" CornerRadius="2"
SnapsToDevicePixels="True">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#F0F0F0"/>
<Setter Property="BorderBrush" Value="#CCCCCC"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Background" Value="#FFE082"/>
<Setter Property="BorderBrush" Value="#F9A825"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsPassed}" Value="True">
<Setter Property="Background" Value="#C8E6C9"/>
<Setter Property="BorderBrush" Value="#388E3C"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsFailed}" Value="True">
<Setter Property="Background" Value="#FFCDD2"/>
<Setter Property="BorderBrush" Value="#C62828"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Background" Value="#E0E0E0"/>
<Setter Property="BorderBrush" Value="#BDBDBD"/>
<Setter Property="Opacity" Value="0.5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel Margin="6,4">
<TextBlock Text="{Binding Name}"
FontSize="11" FontWeight="SemiBold"
TextWrapping="Wrap" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding ResultText}"
FontSize="13" FontWeight="Bold"
HorizontalAlignment="Center" Margin="0,2,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="DimGray"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsPassed}" Value="True">
<Setter Property="Foreground" Value="#2E7D32"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsFailed}" Value="True">
<Setter Property="Foreground" Value="#B71C1C"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -0,0 +1,10 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>Code-behind for TestDisplayView — no logic; all behaviour is in the ViewModel.</summary>
public partial class TestDisplayView : UserControl
{
public TestDisplayView() => InitializeComponent();
}
}

View File

@@ -0,0 +1,363 @@
<UserControl x:Class="HC_APTBS.Views.UserControls.TestPanelView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:HC_APTBS.ViewModels"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="900"
Background="#FFEDEDED" Foreground="Black">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
<!-- ═══════════════════════════════════════════════════════════════════
GRAPHIC INDICATOR TEMPLATE — vertical progress bar per receive param
═══════════════════════════════════════════════════════════════════ -->
<DataTemplate DataType="{x:Type vm:GraphicIndicatorViewModel}">
<Grid Width="58" Margin="2,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Max label -->
<RowDefinition Height="90"/> <!-- Progress bar -->
<RowDefinition Height="Auto"/> <!-- Min label -->
<RowDefinition Height="Auto"/> <!-- Param name -->
</Grid.RowDefinitions>
<!-- Max bound -->
<TextBlock Text="{Binding MaxBound, StringFormat=F1}"
FontSize="9" Foreground="Gray"
HorizontalAlignment="Center" Margin="0,0,0,1"/>
<!-- Vertical progress bar area -->
<Grid Grid.Row="1">
<!-- Border around the bar -->
<Border BorderBrush="Black" BorderThickness="1"
SnapsToDevicePixels="True"/>
<!-- The progress bar itself -->
<ProgressBar Orientation="Vertical"
Minimum="0" Maximum="100"
Value="{Binding ProgressPercent, Mode=OneWay}"
BorderThickness="0"
Background="White"
Margin="1">
<ProgressBar.Style>
<Style TargetType="ProgressBar">
<Setter Property="Foreground" Value="#4CAF50"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsWithinTolerance}" Value="False">
<Setter Property="Foreground" Value="#FF5722"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
<!-- Dashed tolerance boundary lines -->
<Canvas ClipToBounds="True">
<!-- Upper tolerance line at ~80% from bottom (60% band + 20% margin) -->
<Line X1="0" X2="58" StrokeDashArray="3,2"
Stroke="LightGray" StrokeThickness="1"
Canvas.Top="18"/>
<!-- Lower tolerance line at ~20% from bottom -->
<Line X1="0" X2="58" StrokeDashArray="3,2"
Stroke="LightGray" StrokeThickness="1"
Canvas.Top="72"/>
</Canvas>
<!-- Expected value label (center) -->
<TextBlock Text="{Binding ExpectedValue, StringFormat=F1}"
FontSize="9" Foreground="#999999"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,-14,0,0"/>
<!-- Current value label (center, bold) -->
<TextBlock Text="{Binding DisplayValue}"
FontSize="14" FontWeight="Black"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="0,10,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Black"/>
<Style.Triggers>
<DataTrigger Binding="{Binding HasValue}" Value="False">
<Setter Property="Foreground" Value="#CCCCCC"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
<!-- Min bound -->
<TextBlock Grid.Row="2"
Text="{Binding MinBound, StringFormat=F1}"
FontSize="9" Foreground="Gray"
HorizontalAlignment="Center" Margin="0,1,0,0"/>
<!-- Parameter name -->
<TextBlock Grid.Row="3"
Text="{Binding ParameterName}"
FontSize="9" FontWeight="SemiBold"
HorizontalAlignment="Center"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding ParameterName}"/>
</Grid>
</DataTemplate>
<!-- ═══════════════════════════════════════════════════════════════════
OPERATION VALUE TEMPLATE — simple name: value pair
═══════════════════════════════════════════════════════════════════ -->
<DataTemplate DataType="{x:Type vm:OperationValueViewModel}">
<StackPanel Orientation="Horizontal" Margin="0,0,6,0">
<TextBlock Text="{Binding Name}" FontSize="10" Foreground="Black"
Padding="0,0,2,0"/>
<TextBlock Text=":" FontSize="10" Foreground="Black"/>
<TextBlock Text="{Binding Value, StringFormat=F1}" FontSize="10"
Foreground="DimGray" Padding="2,0,0,0"
HorizontalAlignment="Right"/>
</StackPanel>
</DataTemplate>
<!-- ═══════════════════════════════════════════════════════════════════
PHASE CARD TEMPLATE
═══════════════════════════════════════════════════════════════════ -->
<DataTemplate x:Key="PhaseCardTemplate" DataType="{x:Type vm:PhaseCardViewModel}">
<Border MinWidth="100" Margin="2,0" Padding="4"
CornerRadius="2" SnapsToDevicePixels="True">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#F0F0F0"/>
<Setter Property="BorderBrush" Value="#CCCCCC"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Opacity" Value="1"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Background" Value="#FFE082"/>
<Setter Property="BorderBrush" Value="#F9A825"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsPassed}" Value="True">
<Setter Property="Background" Value="#C8E6C9"/>
<Setter Property="BorderBrush" Value="#388E3C"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsFailed}" Value="True">
<Setter Property="Background" Value="#FFCDD2"/>
<Setter Property="BorderBrush" Value="#C62828"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="Background" Value="#E0E0E0"/>
<Setter Property="BorderBrush" Value="#BDBDBD"/>
<Setter Property="Opacity" Value="0.5"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
<!-- Enable/disable toggle as a transparent overlay -->
<CheckBox IsChecked="{Binding IsEnabled}"
HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="0,0,0,0" ToolTip="Enable/disable this phase"/>
<StackPanel Margin="0,2,0,0">
<!-- Phase name -->
<TextBlock Text="{Binding Name}"
FontSize="11" FontWeight="SemiBold"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Margin="16,0,0,0"/>
<!-- Critical indicator -->
<TextBlock Text="Critical" FontSize="9"
Foreground="#E65100" FontWeight="Bold"
HorizontalAlignment="Center"
Visibility="{Binding IsCritical, Converter={StaticResource BoolToVis}}"/>
<!-- Operation values (show/hide) -->
<StackPanel Visibility="{Binding ShowOperationValues, Converter={StaticResource BoolToVis}}"
Margin="0,3,0,0">
<!-- Ready values -->
<StackPanel Visibility="{Binding ReadyValues.Count, FallbackValue=Collapsed}">
<TextBlock Text="Required:" FontSize="9" Foreground="#666"
FontWeight="SemiBold" Margin="0,1,0,0"/>
<ItemsControl ItemsSource="{Binding ReadyValues}"/>
</StackPanel>
<!-- Send values -->
<TextBlock Text="Test:" FontSize="9" Foreground="#666"
FontWeight="SemiBold" Margin="0,2,0,0"/>
<ItemsControl ItemsSource="{Binding OperationValues}"/>
</StackPanel>
<!-- Graphic result indicators -->
<ItemsControl ItemsSource="{Binding ResultIndicators}" Margin="0,4,0,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<!-- Result text -->
<TextBlock Text="{Binding ResultText}"
FontSize="12" FontWeight="Bold"
HorizontalAlignment="Center" Margin="0,3,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="DimGray"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsPassed}" Value="True">
<Setter Property="Foreground" Value="#2E7D32"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsFailed}" Value="True">
<Setter Property="Foreground" Value="#B71C1C"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
<!-- ═══════════════════════════════════════════════════════════════════
TEST SECTION TEMPLATE (one per TestDefinition)
═══════════════════════════════════════════════════════════════════ -->
<DataTemplate x:Key="TestSectionTemplate" DataType="{x:Type vm:TestSectionViewModel}">
<Expander IsExpanded="{Binding IsExpanded}" Margin="0,2,0,0">
<!-- Custom header -->
<Expander.Header>
<Border Padding="4,2" CornerRadius="2">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsActiveTest}" Value="True">
<Setter Property="Background" Value="#FFFFF3CD"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <!-- Name -->
<ColumnDefinition Width="Auto"/> <!-- Description -->
<ColumnDefinition/> <!-- Timing -->
<ColumnDefinition Width="Auto"/> <!-- Check all -->
</Grid.ColumnDefinitions>
<!-- Test name -->
<TextBlock Text="{Binding TestName}"
FontSize="20" FontFamily="Impact" FontStyle="Italic"
VerticalAlignment="Center" Foreground="Black"
Padding="4,0"/>
<!-- Description -->
<TextBlock Grid.Column="1"
Text="{Binding Description}"
FontSize="14" FontStyle="Italic" FontFamily="Impact"
VerticalAlignment="Bottom" Foreground="Gray"
Padding="8,0,0,3"/>
<!-- Timing info -->
<StackPanel Grid.Column="2" Orientation="Horizontal"
VerticalAlignment="Center" Margin="16,0,0,0">
<TextBlock FontSize="10" Foreground="DimGray">
<Run Text="Cond: "/>
<Run Text="{Binding ConditioningTimeSec, Mode=OneWay}"/>
<Run Text="s"/>
</TextBlock>
<TextBlock FontSize="10" Foreground="DimGray" Margin="10,0,0,0">
<Run Text="Meas: "/>
<Run Text="{Binding MeasurementTimeSec, Mode=OneWay}"/>
<Run Text="s"/>
</TextBlock>
<TextBlock FontSize="10" Foreground="DimGray" Margin="10,0,0,0">
<Run Text="M/s: "/>
<Run Text="{Binding MeasurementsPerSecond, StringFormat=F1, Mode=OneWay}"/>
</TextBlock>
</StackPanel>
<!-- Per-section check all -->
<CheckBox Grid.Column="3"
IsChecked="{Binding AllPhasesChecked}"
VerticalAlignment="Center" Margin="8,0"
ToolTip="Enable/disable all phases in this test"/>
</Grid>
</Border>
</Expander.Header>
<!-- Phase cards (horizontal scroll) -->
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled"
Padding="0,4">
<ItemsControl ItemsSource="{Binding Phases}"
ItemTemplate="{StaticResource PhaseCardTemplate}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Expander>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- Toolbar -->
<RowDefinition Height="Auto"/> <!-- Status bar -->
<RowDefinition/> <!-- Test sections -->
</Grid.RowDefinitions>
<!-- ── Toolbar ─────────────────────────────────────────────────────── -->
<Border BorderBrush="Gray" BorderThickness="0,0,0,1" Padding="8,4">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Show values toggle -->
<CheckBox IsChecked="{Binding ShowOperationValues}"
VerticalAlignment="Center">
<TextBlock Text="Show values" FontSize="12"/>
</CheckBox>
<!-- Check all button -->
<Button Grid.Column="1" Margin="12,0,0,0"
Command="{Binding ToggleCheckAllCommand}"
Padding="6,2" ToolTip="Enable/disable all phases">
<TextBlock Text="Check All" FontSize="11"/>
</Button>
<!-- Remaining time -->
<TextBlock Grid.Column="3" VerticalAlignment="Center"
Foreground="DimGray" FontSize="12" Margin="0,0,4,0">
<Run Text="~"/>
<Run Text="{Binding RemainingSeconds, Mode=OneWay}"/>
<Run Text="s remaining"/>
</TextBlock>
</Grid>
</Border>
<!-- ── Status line ─────────────────────────────────────────────────── -->
<TextBlock Grid.Row="1"
Text="{Binding StatusText}"
FontSize="12" FontStyle="Italic"
Foreground="Gray" Margin="8,2"
Visibility="{Binding IsRunning, Converter={StaticResource BoolToVis}}"/>
<!-- ── Test sections ───────────────────────────────────────────────── -->
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Tests}"
ItemTemplate="{StaticResource TestSectionTemplate}"
Margin="4"/>
</ScrollViewer>
</Grid>
</UserControl>

View File

@@ -0,0 +1,17 @@
using System.Windows.Controls;
namespace HC_APTBS.Views.UserControls
{
/// <summary>
/// Interaction logic for TestPanelView.xaml.
/// All logic resides in <see cref="ViewModels.TestPanelViewModel"/>.
/// </summary>
public partial class TestPanelView : UserControl
{
/// <summary>Initialises a new instance of the <see cref="TestPanelView"/> class.</summary>
public TestPanelView()
{
InitializeComponent();
}
}
}