This commit is contained in:
xyy
2026-03-31 20:17:17 +08:00
parent 8bd9226955
commit e14d6de146
18 changed files with 865 additions and 206 deletions

View File

@@ -70,8 +70,8 @@
<GroupBox Header="📊 压力数据">
<StackPanel>
<Label Content="当前压力(kPa)" FontWeight="Normal" Margin="5,0,0,0"/>
<TextBox Text="{Binding Record.BubbleCurrentPressure}" Width="150" Margin="5,0,5,5"/>
<Label Content="泡点压力(kPa)" FontWeight="Normal" Margin="5,0,0,0"/>
<TextBox HorizontalAlignment="Left" Text="{Binding Record.BubbleCurrentPressure}" Width="150" Margin="5,0,5,5"/>
<Label Content="泡点压力(Pa)" FontWeight="Normal" Margin="5,0,0,0"/>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Record.BubblePointPressure}" Width="150" Margin="5"/>
<Button Content="涨破" Command="{Binding ReadPlcCommand}" Padding="10,5" Margin="5" Background="#FF9800"/>
@@ -83,11 +83,16 @@
</StackPanel>
<!-- 结果显示 -->
<Border Grid.Row="1" Margin="0,10" Background="White" CornerRadius="8" BorderBrush="#E9ECF0" BorderThickness="1">
<Border Grid.Row="1" Margin="0,10" Background="White" CornerRadius="8" BorderBrush="#E9ECF0" BorderThickness="1">
<Grid>
<GroupBox Header="✨ 测试结果" BorderThickness="0" Margin="0">
<TextBlock FontSize="48" FontWeight="Bold" TextAlignment="Center"
Text="{Binding MaxPoreSize, StringFormat={}{0:F3} μm}" Foreground="#2196F3"/>
<GroupBox Header="✨ 测试结果" BorderThickness="0"
Margin="0" Padding="5,0">
<!-- 减少内边距 -->
<TextBlock FontSize="40" FontWeight="Bold" TextAlignment="Center"
Text="{Binding MaxPoreSize, StringFormat={}{0:F3} μm}"
Foreground="#2196F3"
Margin="0,-30,0,-10"/>
<!-- 负边距压缩垂直空间 -->
</GroupBox>
</Grid>
</Border>

View File

@@ -1,8 +1,92 @@
<Window x:Class="MembranePoreTester.Views.HistoryWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="历史记录" Height="600" Width="900"
WindowStartupLocation="CenterOwner">
Title="历史记录" Height="600" Width="1000"
WindowStartupLocation="CenterOwner" Loaded="Window_Loaded"
Background="#F5F7FA" FontFamily="Segoe UI">
<Window.Resources>
<!-- 统一按钮样式 -->
<Style TargetType="Button">
<Setter Property="Background" Value="#2196F3"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="12,6"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="4" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#1976D2"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#0D47A1"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- 统一文本框样式 -->
<Style TargetType="TextBox">
<Setter Property="Height" Value="28"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#D0D3D9"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="5,2"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<!-- 统一组合框样式 -->
<Style TargetType="ComboBox">
<Setter Property="Height" Value="28"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#D0D3D9"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<!-- 统一标签样式 -->
<Style TargetType="Label">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#2C3E50"/>
<Setter Property="Margin" Value="5"/>
</Style>
<!-- 统一 DatePicker 样式(保持一致性) -->
<Style TargetType="DatePicker">
<Setter Property="Height" Value="28"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#D0D3D9"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<!-- DataGrid 样式 -->
<Style TargetType="DataGrid">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#E9ECF0"/>
<Setter Property="RowHeight" Value="28"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="GridLinesVisibility" Value="Horizontal"/>
<Setter Property="HeadersVisibility" Value="Column"/>
<Setter Property="RowBackground" Value="White"/>
<Setter Property="AlternatingRowBackground" Value="#F9F9F9"/>
</Style>
</Window.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
@@ -10,48 +94,53 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 过滤条件 -->
<StackPanel Orientation="Horizontal" Grid.Row="0" Margin="0,0,0,10">
<Label Content="工位:"/>
<ComboBox x:Name="cmbStation" SelectedIndex="0" Width="80" Margin="5,0">
<ComboBoxItem Content="全部"/>
<ComboBoxItem Content="1"/>
<ComboBoxItem Content="2"/>
<ComboBoxItem Content="3"/>
</ComboBox>
<Label Content="测试类型:"/>
<ComboBox x:Name="cmbType" SelectedIndex="0" Width="120" Margin="5,0">
<ComboBoxItem Content="全部"/>
<ComboBoxItem Content="泡点法"/>
<ComboBoxItem Content="孔分布"/>
</ComboBox>
<Label Content="日期范围:"/>
<DatePicker x:Name="dpStart" Width="120"/>
<Label Content="-" Margin="2"/>
<DatePicker x:Name="dpEnd" Width="120"/>
<Button Content="查询" Click="Query_Click" Padding="15,5" Margin="10,0"/>
<Button Content="导出选中" Click="ExportSelected_Click" Padding="15,5"/>
</StackPanel>
<!-- 过滤条件区域(卡片式) -->
<Border Grid.Row="0" Background="White" CornerRadius="6" Padding="10" Margin="0,0,0,10" BorderBrush="#E9ECF0" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Label Content="工位:"/>
<ComboBox x:Name="cmbStation" Width="80">
<ComboBoxItem Content="全部"/>
<ComboBoxItem Content="1"/>
<ComboBoxItem Content="2"/>
<ComboBoxItem Content="3"/>
</ComboBox>
<Label Content="测试类型:"/>
<ComboBox x:Name="cmbType" Width="120">
<ComboBoxItem Content="全部"/>
<ComboBoxItem Content="泡点法"/>
<ComboBoxItem Content="孔分布"/>
</ComboBox>
<Label Content="日期范围:"/>
<DatePicker x:Name="dpStart" Width="120"/>
<Label Content="-" Margin="2,0,2,0" VerticalAlignment="Center"/>
<DatePicker x:Name="dpEnd" Width="120"/>
<Button Content="🔍 查询" Click="Query_Click" Padding="15,5" Background="#2196F3"/>
<Button Content="📊 导出选中" Click="ExportSelected_Click" Padding="15,5" Background="#4CAF50"/>
</StackPanel>
</Border>
<!-- 历史记录列表 -->
<DataGrid x:Name="dgHistory" Grid.Row="1" AutoGenerateColumns="False"
IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Id}" Width="50"/>
<DataGridTextColumn Header="工位" Binding="{Binding StationId}" Width="50"/>
<DataGridTextColumn Header="类型" Binding="{Binding Type}" Width="80"/>
<DataGridTextColumn Header="测试日期" Binding="{Binding TestDate}" Width="150"/>
<DataGridTextColumn Header="样品类型" Binding="{Binding SampleType}" Width="100"/>
<DataGridTextColumn Header="规格" Binding="{Binding SampleSpec}" Width="100"/>
<DataGridTextColumn Header="测试者" Binding="{Binding Tester}" Width="100"/>
<DataGridTextColumn Header="结果" Binding="{Binding Result}" Width="150"/>
</DataGrid.Columns>
</DataGrid>
<!-- 历史记录列表(带边框) -->
<Border Grid.Row="1" Background="White" CornerRadius="6" BorderBrush="#E9ECF0" BorderThickness="1" Padding="5">
<DataGrid x:Name="dgHistory" AutoGenerateColumns="False"
IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow"
BorderThickness="0" HorizontalGridLinesBrush="#E9ECF0">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Id}" Width="50"/>
<DataGridTextColumn Header="工位" Binding="{Binding StationId}" Width="50"/>
<DataGridTextColumn Header="类型" Binding="{Binding Type}" Width="80"/>
<DataGridTextColumn Header="测试日期" Binding="{Binding TestDate}" Width="150"/>
<DataGridTextColumn Header="样品类型" Binding="{Binding SampleType}" Width="100"/>
<DataGridTextColumn Header="规格" Binding="{Binding SampleSpec}" Width="100"/>
<DataGridTextColumn Header="测试者" Binding="{Binding Tester}" Width="100"/>
<DataGridTextColumn Header="结果" Binding="{Binding Result}" Width="150"/>
</DataGrid.Columns>
</DataGrid>
</Border>
<!-- 底部按钮 -->
<!-- 底部按钮区域 -->
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
<Button Content="加载到当前工位" Click="LoadToCurrentStation_Click" Padding="15,5" Margin="5"/>
<Button Content="关闭" Click="Close_Click" Padding="15,5"/>
<Button Content="📂 加载到当前工位" Click="LoadToCurrentStation_Click" Padding="15,5" Background="#FF9800"/>
<Button Content="关闭" Click="Close_Click" Padding="15,5" Background="#607D8B"/>
</StackPanel>
</Grid>
</Window>

View File

@@ -145,6 +145,11 @@ namespace MembranePoreTester.Views
private void Close_Click(object sender, RoutedEventArgs e) => Close();
public static event EventHandler<LoadRecordEventArgs> LoadRecordEvent;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Query_Click(sender, e);
}
}
public class LoadRecordEventArgs : EventArgs

View File

@@ -3,64 +3,146 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MembranePoreTester.Views"
xmlns:viewModels="clr-namespace:MembranePoreTester.ViewModels"
xmlns:conv="clr-namespace:MembranePoreTester.Converters"
Title="膜孔径测试系统 (GB/T 32361-2015)"
Width="1024" Height="768"
WindowStartupLocation="CenterScreen" KeyDown="Window_KeyDown">
WindowStartupLocation="CenterScreen" KeyDown="Window_KeyDown"
Background="#F5F7FA" FontFamily="Segoe UI">
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>
<Window.Resources>
<conv:BoolToStringConverter x:Key="BoolToStringConverter"/>
<!-- 统一按钮样式(与子视图保持一致) -->
<Style TargetType="Button">
<Setter Property="Background" Value="#2196F3"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="12,6"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="4" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#1976D2"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#0D47A1"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- 统一 ComboBox 样式 -->
<Style TargetType="ComboBox">
<Setter Property="Height" Value="28"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#D0D3D9"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<!-- 统一 TabControl 样式 -->
<Style TargetType="TabControl">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<Style TargetType="TabItem">
<Setter Property="FontSize" Value="13"/>
<Setter Property="Padding" Value="15,8"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="#5F6A7A"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Background="{TemplateBinding Background}"
BorderThickness="0,0,0,2"
BorderBrush="Transparent"
Padding="{TemplateBinding Padding}">
<ContentPresenter ContentSource="Header" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="BorderBrush" Value="#2196F3"/>
<Setter Property="Background" Value="#E3F2FD"/>
<!-- 添加浅蓝背景 -->
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Background" Value="#F5F5F5"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<DockPanel>
<!-- 全局历史记录按钮 -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="5">
<Button Content="历史记录" Click="OpenHistory_Click" Padding="10,5" Margin="5"/>
</StackPanel>
<!-- 顶部历史记录栏 -->
<Border DockPanel.Dock="Top" Background="White" BorderBrush="#E9ECF0" BorderThickness="0,0,0,1" Padding="10,5">
<StackPanel Orientation="Horizontal">
<Button Content="📋 历史记录" Click="OpenHistory_Click" Width="100" HorizontalAlignment="Left" Background="#607D8B"/>
<Button Content="阀门控制" Click="OpenValveControl_Click" Padding="10,5" Margin="5"/>
</StackPanel>
</Border>
<!-- 工位选项卡 -->
<TabControl x:Name="stationTabControl" ItemsSource="{Binding Stations}">
<TabControl x:Name="stationTabControl" ItemsSource="{Binding Stations}" Background="White" Margin="10,10,10,10">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Name}" FontSize="14" FontWeight="Medium"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<DockPanel>
<DockPanel Margin="0,10,0,0">
<!-- 工位控制栏 -->
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="5">
<ComboBox ItemsSource="{Binding PressureModeList}"
SelectedItem="{Binding SelectedPressureMode}" Width="80" Margin="5"/>
<Border DockPanel.Dock="Top" Background="White" CornerRadius="6" Padding="10" Margin="0,0,0,10" BorderBrush="#E9ECF0" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding PressureModeList}" SelectedItem="{Binding SelectedPressureMode}" Width="80"/>
<Button Content="▶ 启动" Command="{Binding StartCommand}" Width="80" Background="#4CAF50"/>
<Button Content="⏹ 停止" Command="{Binding StopCommand}" Width="80" Background="#F44336"/>
<Button Content="{Binding PressButtonText}" Command="{Binding PressCommand}" Width="80" Background="#FF9800"/>
<Button Content="启动" Command="{Binding StartCommand}" Width="80" Margin="5"/>
<Button Content="停止" Command="{Binding StopCommand}" Width="80" Margin="5"/>
<Button Content="{Binding PressButtonText}" Command="{Binding PressCommand}" Width="80" Margin="5"/>
<!-- 替换为状态指示灯 -->
<StackPanel Orientation="Horizontal" Margin="5">
<!-- 带阴影和光泽的圆形指示灯 -->
<Grid Width="18" Height="18" Margin="2">
<Ellipse Fill="{Binding EnableStatusColor}">
<Ellipse.Effect>
<DropShadowEffect BlurRadius="3" ShadowDepth="0" Opacity="0.5"/>
</Ellipse.Effect>
</Ellipse>
<Ellipse Margin="2,2,2,2" Opacity="0.6">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="White" Offset="0.2"/>
<GradientStop Color="Transparent" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
<TextBlock Text="{Binding EnableStatusText}" VerticalAlignment="Center" Margin="5,0,0,0"/>
<!-- 状态指示灯 -->
<StackPanel Orientation="Horizontal" Margin="15,0,0,0">
<Grid Width="18" Height="18" Margin="2">
<Ellipse Fill="{Binding EnableStatusColor}">
<Ellipse.Effect>
<DropShadowEffect BlurRadius="3" ShadowDepth="0" Opacity="0.3"/>
</Ellipse.Effect>
</Ellipse>
<Ellipse Margin="2" Opacity="0.6">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="White" Offset="0.2"/>
<GradientStop Color="Transparent" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
<TextBlock Text="{Binding EnableStatusText}" VerticalAlignment="Center" Margin="5,0,0,0" FontSize="12"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
<!-- 测试类型选项卡 -->
<TabControl x:Name="stationTabControl" ItemsSource="{Binding Stations}" SelectionChanged="TabControl_SelectionChanged">
<!-- 测试类型选项卡修复嵌套绑定直接定义两个TabItem -->
<TabControl SelectionChanged="TabControl_SelectionChanged">
<TabItem Header="泡点法测试最大孔径">
<local:BubblePointView DataContext="{Binding BubblePointVM}"/>
</TabItem>

View File

@@ -103,5 +103,12 @@ namespace MembranePoreTester.Views
}
return null;
}
private void OpenValveControl_Click(object sender, RoutedEventArgs e)
{
var win = new ValveControlWindow();
win.Owner = this;
win.Show();
}
}
}

View File

@@ -87,29 +87,6 @@
</Grid>
</GroupBox>
<!--<GroupBox Header="校准参数">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0">压力零点校准:</Label>
<TextBox x:Name="txtPressureZero" Grid.Row="0" Grid.Column="1"/>
<Label Grid.Row="1" Grid.Column="0">压力量程校准:</Label>
<TextBox x:Name="txtPressureSpan" Grid.Row="1" Grid.Column="1"/>
<Label Grid.Row="2" Grid.Column="0">流量零点校准:</Label>
<TextBox x:Name="txtFlowZero" Grid.Row="2" Grid.Column="1"/>
<Label Grid.Row="3" Grid.Column="0">流量量程校准:</Label>
<TextBox x:Name="txtFlowSpan" Grid.Row="3" Grid.Column="1"/>
</Grid>
</GroupBox>-->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,20,0,0">
<!--<Button Content="读取参数" Click="ReadParameters_Click" Width="100" Margin="5"/>-->

View File

@@ -155,6 +155,13 @@
</ComboBox>
<ComboBox Grid.Row="3" HorizontalAlignment="Right" Grid.Column="3" ItemsSource="{Binding PressureModeList}"
SelectedItem="{Binding SelectedPressureMode}" Width="100"/>
<Button Grid.Row="3" Grid.Column="3"
Content="🗑 清除数据"
Command="{Binding ClearAllCommand}"
Background="#F44336"
Width="90"
HorizontalAlignment="Center"
Margin="0,5,5,5"/>
</Grid>
</GroupBox>
@@ -181,11 +188,12 @@
<!-- 湿膜表格 -->
<GroupBox Grid.Column="0" Header="💧 湿膜数据" Margin="0,0,5,0">
<DataGrid ItemsSource="{Binding Record.DataPoints}"
SelectedItem="{Binding SelectedDataPoint}"
AutoGenerateColumns="False"
CanUserAddRows="False"
ColumnWidth="*">
<DataGrid.Columns>
<DataGridTextColumn Header="压力"
<DataGridTextColumn Header="压力(kPa)"
Binding="{Binding Pressure, UpdateSourceTrigger=PropertyChanged}"
MinWidth="100"/>
<DataGridTextColumn Header="湿膜流量(L/min)"
@@ -198,11 +206,12 @@
<!-- 干膜表格 -->
<GroupBox Grid.Column="1" Header="🔥 干膜数据" Margin="5,0,0,0">
<DataGrid ItemsSource="{Binding Record.DataPoints}"
SelectedItem="{Binding SelectedDataPoint}"
AutoGenerateColumns="False"
CanUserAddRows="False"
ColumnWidth="*">
<DataGrid.Columns>
<DataGridTextColumn Header="压力"
<DataGridTextColumn Header="压力(kPa)"
Binding="{Binding Pressure, UpdateSourceTrigger=PropertyChanged}"
MinWidth="100"/>
<DataGridTextColumn Header="干膜流量(L/min)"
@@ -235,27 +244,30 @@
<!-- 计算结果及操作按钮区域 -->
<Border Grid.Row="2" Margin="0,10,0,0" Background="White" CornerRadius="6" Padding="10" BorderBrush="#E9ECF0" BorderThickness="1">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<GroupBox Header="📏 平均孔径" Margin="5" BorderThickness="0">
<TextBlock Text="{Binding AveragePoreSize, StringFormat={}{0:F3} μm}" FontSize="20" FontWeight="Bold" Foreground="#2196F3"/>
<GroupBox Header="📏 平均孔径" Margin="0" BorderThickness="0">
<TextBlock Text="{Binding AveragePoreSize, StringFormat={}{0:F2} μm}" FontSize="14" FontWeight="Bold" Foreground="#2196F3"/>
</GroupBox>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Margin="10,0"/>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Margin="2,0"/>
<GroupBox Header="🎯 孔分布区间计算" Margin="5" BorderThickness="0">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding LowerPore}" Width="60" Margin="2"/>
<TextBlock Text="~" VerticalAlignment="Center" Margin="2"/>
<TextBox Text="{Binding UpperPore}" Width="60" Margin="2"/>
<TextBlock Text="μm" VerticalAlignment="Center" Margin="5,0,10,0"/>
<Button Content="计算" Command="{Binding CalculateCommand}" Margin="5,0" Padding="12,5" Background="#2196F3"/>
<TextBlock Text="{Binding RangePercentage, StringFormat={}{0:F1}%}" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" Margin="10,0" Foreground="#4CAF50"/>
<TextBox Text="{Binding LowerPore}" Width="48" Margin="1"/>
<TextBlock Text="~" VerticalAlignment="Center" Margin="1"/>
<TextBox Text="{Binding UpperPore}" Width="48" Margin="1"/>
<TextBlock Text="μm" VerticalAlignment="Center" Margin="2,0,5,0"/>
<Button Content="计算" Command="{Binding CalculateCommand}" Margin="2,0" Padding="8,5" Background="#2196F3"/>
<TextBlock Text="{Binding RangePercentage, StringFormat={}{0:F1}%}" FontSize="14" FontWeight="Bold" VerticalAlignment="Center" Margin="5,0" Foreground="#4CAF50"/>
</StackPanel>
</GroupBox>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Margin="10,0"/>
<StackPanel Orientation="Horizontal">
<Button Content="🔧 大流量校准" Command="{Binding OpenFlowCalibCommand}" Background="#607D8B"/>
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Margin="3,0"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="🔧 大流量校准" Command="{Binding OpenFlowCalibCommand}" Background="#607D8B"/>
<Button Content="🔧 小流量校准" Command="{Binding OpenFlowCalibCommand2}" Background="#607D8B"/>
<Button Content="📄 生成报告" Command="{Binding GenerateReportCommand}" Background="#2196F3"/>
<Button Content="💾 保存到历史" Command="{Binding SaveCommand}" Background="#4CAF50"/>
<Button Content="📊 导出Excel" Command="{Binding ExportCommand}" Background="#FF9800"/>
</StackPanel>
</StackPanel>
</Border>

View File

@@ -0,0 +1,161 @@
<Window x:Class="MembranePoreTester.Views.ValveControlWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MembranePoreTester.Converters"
Title="阀门控制" Height="768" Width="1024"
WindowStartupLocation="CenterOwner"
Background="#F5F7FA" FontFamily="Segoe UI">
<Window.Resources>
<local:BoolToStringConverter x:Key="BoolToStringConverter"/>
<!-- 统一按钮样式 -->
<Style TargetType="Button">
<Setter Property="Background" Value="#2196F3"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="12,6"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" CornerRadius="4" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#1976D2"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#0D47A1"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- 统一组合框样式 -->
<Style TargetType="ComboBox">
<Setter Property="Height" Value="28"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#D0D3D9"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<!-- 统一文本框样式 -->
<Style TargetType="TextBox">
<Setter Property="Height" Value="28"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#D0D3D9"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="5,2"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<!-- 统一标签样式 -->
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#2C3E50"/>
</Style>
<!-- ToggleButton 样式(开关按钮) -->
<Style TargetType="ToggleButton">
<Setter Property="Background" Value="#9E9E9E"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}" CornerRadius="4" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="#4CAF50"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#757575"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Background" Value="#45a049"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- ItemsControl 项容器样式(圆角边框,交替背景) -->
<Style TargetType="ContentPresenter">
<Setter Property="Margin" Value="0,2"/>
</Style>
<Style TargetType="Border" x:Key="ValveItemBorder">
<Setter Property="Background" Value="White"/>
<Setter Property="CornerRadius" Value="4"/>
<Setter Property="BorderBrush" Value="#E9ECF0"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="10,8"/>
<Setter Property="Margin" Value="0,2"/>
</Style>
</Window.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 工位选择卡片 -->
<Border Grid.Row="0" Background="White" CornerRadius="6" Padding="10" Margin="0,0,0,10" BorderBrush="#E9ECF0" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="工位:" VerticalAlignment="Center" Margin="5"/>
<ComboBox x:Name="cmbStation" Width="80">
<ComboBoxItem IsSelected="True" Content="工位1"/>
<ComboBoxItem Content="工位2"/>
<ComboBoxItem Content="工位3"/>
</ComboBox>
<Button Content="🔄 刷新状态" Click="Refresh_Click" Margin="10,0,0,0" Background="#607D8B"/>
</StackPanel>
</Border>
<!-- 阀门列表(带滚动条,整体卡片) -->
<Border Grid.Row="1" Background="White" CornerRadius="6" BorderBrush="#E9ECF0" BorderThickness="1" Padding="5">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl x:Name="valveList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Style="{StaticResource ValveItemBorder}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="SemiBold" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding CoilAddress}" Foreground="#7F8C8D" VerticalAlignment="Center" FontSize="11"/>
<ToggleButton Grid.Column="2" IsChecked="{Binding IsOn, Mode=TwoWay}"
Checked="ToggleButton_Checked"
Unchecked="ToggleButton_Unchecked"
Content="{Binding IsOn, Converter={StaticResource BoolToStringConverter}}"
HorizontalAlignment="Right" Width="70"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
</Grid>
</Window>

View File

@@ -0,0 +1,181 @@
using MembranePoreTester.Communication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Threading;
namespace MembranePoreTester.Views
{
public partial class ValveControlWindow : Window
{
private readonly IPlcService _plcService;
private readonly PlcConfiguration _config;
private readonly DispatcherTimer _refreshTimer;
private readonly Dictionary<int, List<ValveInfo>> _valvesByStation = new()
{
[1] = new()
{
new ValveInfo { Name = "高压进气阀", CoilAddress = 100 },
new ValveInfo { Name = "低压进气阀", CoilAddress = 101 },
new ValveInfo { Name = "排气阀", CoilAddress = 102 },
new ValveInfo { Name = "低压保护阀", CoilAddress = 103 },
new ValveInfo { Name = "大流量阀", CoilAddress = 104 },
new ValveInfo { Name = "小流量阀", CoilAddress = 105 },
new ValveInfo { Name = "底部出气阀", CoilAddress = 106 },
new ValveInfo { Name = "顶部出气阀", CoilAddress = 107 }
},
[2] = new()
{
new ValveInfo { Name = "高压进气阀", CoilAddress = 108 },
new ValveInfo { Name = "低压进气阀", CoilAddress = 109 },
new ValveInfo { Name = "排气阀", CoilAddress = 110 },
new ValveInfo { Name = "低压保护阀", CoilAddress = 111 },
new ValveInfo { Name = "大流量阀", CoilAddress = 112 },
new ValveInfo { Name = "小流量阀", CoilAddress = 113 },
new ValveInfo { Name = "底部出气阀", CoilAddress = 114 },
new ValveInfo { Name = "顶部出气阀", CoilAddress = 115 }
},
[3] = new()
{
new ValveInfo { Name = "高压进气阀", CoilAddress = 116 },
new ValveInfo { Name = "低压进气阀", CoilAddress = 117 },
new ValveInfo { Name = "排气阀", CoilAddress = 118 },
new ValveInfo { Name = "低压保护阀", CoilAddress = 119 },
new ValveInfo { Name = "大流量阀", CoilAddress = 120 },
new ValveInfo { Name = "小流量阀", CoilAddress = 121 },
new ValveInfo { Name = "底部出气阀", CoilAddress = 122 },
new ValveInfo { Name = "顶部出气阀", CoilAddress = 123 }
}
};
public ValveControlWindow()
{
InitializeComponent();
_plcService = App.PlcService;
_config = App.PlcConfig;
_refreshTimer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
_refreshTimer.Tick += async (s, e) => await RefreshValveStates();
_refreshTimer.Start();
Loaded += (s, e) => ShowStation(1);
}
private void ShowStation(int station)
{
if (valveList == null) return; // 防御性检查
if (_valvesByStation.TryGetValue(station, out var valves))
{
valveList.ItemsSource = valves;
}
else
{
valveList.ItemsSource = null;
}
}
private async void CmbStation_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (valveList == null) return; // 初始化未完成
if (cmbStation.SelectedItem is ComboBoxItem item)
{
int station = int.Parse(item.Content.ToString().Replace("工位", ""));
ShowStation(station);
await RefreshValveStates();
}
}
private async Task RefreshValveStates()
{
if (valveList.ItemsSource is not List<ValveInfo> valves) return;
foreach (var valve in valves)
{
try
{
bool state = await _plcService.ReadCoilAsync((ushort)valve.CoilAddress);
valve.IsOn = state;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"读取线圈{valve.CoilAddress}失败: {ex.Message}");
}
}
}
private async void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton btn && btn.DataContext is ValveInfo valve)
{
await WriteCoil(valve.CoilAddress, true);
}
}
private async void ToggleButton_Unchecked(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton btn && btn.DataContext is ValveInfo valve)
{
await WriteCoil(valve.CoilAddress, false);
}
}
private async Task WriteCoil(int coilAddress, bool value)
{
try
{
await _plcService.WriteCoilAsync((ushort)coilAddress, value);
await RefreshValveStates();
}
catch (Exception ex)
{
MessageBox.Show($"控制阀门失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void Refresh_Click(object sender, RoutedEventArgs e)
{
await RefreshValveStates();
}
protected override void OnClosed(EventArgs e)
{
_refreshTimer?.Stop();
base.OnClosed(e);
}
}
public class ValveInfo : INotifyPropertyChanged
{
public string Name { get; set; }
public int CoilAddress { get; set; }
private bool _isOn;
public bool IsOn
{
get => _isOn;
set
{
if (_isOn != value)
{
_isOn = value;
OnPropertyChanged(nameof(IsOn));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}