This commit is contained in:
GukSang.Jin
2026-04-05 16:46:26 +08:00
parent 719d248197
commit c4d6a58bf4
3 changed files with 346 additions and 48 deletions

View File

@@ -0,0 +1,45 @@
using System.Collections;
using System.Globalization;
using System.Windows.Data;
namespace Cardiopulmonarybypasssystems.Converters;
public sealed class TrendLastPointCoordinateConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length < 4
|| values[0] is not IEnumerable enumerable
|| values[1] is not double width
|| values[2] is not double height
|| values[3] is not double maxValue
|| width <= 0
|| height <= 0
|| maxValue <= 0)
{
return -100d;
}
var samples = enumerable.Cast<object>()
.Select(item => item is double value ? value : System.Convert.ToDouble(item, culture))
.ToList();
if (samples.Count == 0)
{
return -100d;
}
var lastIndex = samples.Count - 1;
var xStep = samples.Count > 1 ? width / Math.Max(samples.Count - 1, 1) : 0d;
var x = xStep * lastIndex;
var yRatio = Math.Clamp(samples[lastIndex] / maxValue, 0d, 1d);
var y = height - yRatio * height;
return string.Equals(parameter as string, "y", StringComparison.OrdinalIgnoreCase)
? y - 4d
: x - 4d;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
}

View File

@@ -13,6 +13,7 @@
WindowStartupLocation="CenterScreen"> WindowStartupLocation="CenterScreen">
<Window.Resources> <Window.Resources>
<converters:TrendPointCollectionConverter x:Key="TrendPointCollectionConverter" /> <converters:TrendPointCollectionConverter x:Key="TrendPointCollectionConverter" />
<converters:TrendLastPointCoordinateConverter x:Key="TrendLastPointCoordinateConverter" />
</Window.Resources> </Window.Resources>
<Grid Margin="12"> <Grid Margin="12">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -593,21 +594,133 @@
<Border Width="12" Height="12" Margin="0,2,6,0" Background="#FFD38A16" CornerRadius="6" /> <Border Width="12" Height="12" Margin="0,2,6,0" Background="#FFD38A16" CornerRadius="6" />
<TextBlock Style="{StaticResource CaptionStyle}" Text="ΔP" /> <TextBlock Style="{StaticResource CaptionStyle}" Text="ΔP" />
</WrapPanel> </WrapPanel>
<Grid Height="180" Background="#FFF7FBFC"> <Grid Height="220">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="84" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="180" />
<RowDefinition Height="*" /> <RowDefinition Height="28" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" /> <Grid Grid.Column="0" Margin="0,2,4,2">
<Border Grid.Row="1" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" /> <Grid.RowDefinitions>
<Border Grid.Row="2" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" /> <RowDefinition Height="*" />
<Canvas x:Name="PressureTrendCanvas"> <RowDefinition Height="*" />
<Polyline x:Name="ProximalPressureTrendPolyline" Stroke="#FF0B7A75" StrokeThickness="2" /> <RowDefinition Height="*" />
<Polyline x:Name="DistalPressureTrendPolyline" Stroke="#FF3C6FB6" StrokeThickness="2" /> </Grid.RowDefinitions>
<Polyline x:Name="DeltaPressureTrendPolyline" Stroke="#FFD38A16" StrokeThickness="2" /> <TextBlock Grid.Row="0"
</Canvas> VerticalAlignment="Top"
HorizontalAlignment="Right"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Margin="0,0,4,0"
Text="{Binding PressureTrendTopScaleDisplay}" />
<TextBlock Grid.Row="1"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Margin="0,0,4,0"
Text="{Binding PressureTrendMidScaleDisplay}" />
<TextBlock Grid.Row="2"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Margin="0,0,4,0"
Text="0" />
</Grid>
<Border Grid.Column="2"
BorderBrush="#FFDCE7EA"
BorderThickness="1"
Background="#FFF7FBFC"
CornerRadius="6">
<Grid Margin="6">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" />
<Border Grid.Row="1" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" />
<Border Grid.Row="2" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" />
<Canvas x:Name="PressureTrendCanvas">
<Polyline x:Name="ProximalPressureTrendPolyline" Stroke="#FF0B7A75" StrokeThickness="2" />
<Polyline x:Name="DistalPressureTrendPolyline" Stroke="#FF3C6FB6" StrokeThickness="2" />
<Polyline x:Name="DeltaPressureTrendPolyline" Stroke="#FFD38A16" StrokeThickness="2" />
<Ellipse Width="8" Height="8" Fill="#FF0B7A75" Stroke="White" StrokeThickness="1.5">
<Canvas.Left>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="x">
<Binding Path="ProximalPressureTrendValues" />
<Binding ElementName="PressureTrendCanvas" Path="ActualWidth" />
<Binding ElementName="PressureTrendCanvas" Path="ActualHeight" />
<Binding Path="PressureTrendMax" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="y">
<Binding Path="ProximalPressureTrendValues" />
<Binding ElementName="PressureTrendCanvas" Path="ActualWidth" />
<Binding ElementName="PressureTrendCanvas" Path="ActualHeight" />
<Binding Path="PressureTrendMax" />
</MultiBinding>
</Canvas.Top>
</Ellipse>
<Ellipse Width="8" Height="8" Fill="#FF3C6FB6" Stroke="White" StrokeThickness="1.5">
<Canvas.Left>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="x">
<Binding Path="DistalPressureTrendValues" />
<Binding ElementName="PressureTrendCanvas" Path="ActualWidth" />
<Binding ElementName="PressureTrendCanvas" Path="ActualHeight" />
<Binding Path="PressureTrendMax" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="y">
<Binding Path="DistalPressureTrendValues" />
<Binding ElementName="PressureTrendCanvas" Path="ActualWidth" />
<Binding ElementName="PressureTrendCanvas" Path="ActualHeight" />
<Binding Path="PressureTrendMax" />
</MultiBinding>
</Canvas.Top>
</Ellipse>
<Ellipse Width="8" Height="8" Fill="#FFD38A16" Stroke="White" StrokeThickness="1.5">
<Canvas.Left>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="x">
<Binding Path="DeltaPressureTrendValues" />
<Binding ElementName="PressureTrendCanvas" Path="ActualWidth" />
<Binding ElementName="PressureTrendCanvas" Path="ActualHeight" />
<Binding Path="PressureTrendMax" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="y">
<Binding Path="DeltaPressureTrendValues" />
<Binding ElementName="PressureTrendCanvas" Path="ActualWidth" />
<Binding ElementName="PressureTrendCanvas" Path="ActualHeight" />
<Binding Path="PressureTrendMax" />
</MultiBinding>
</Canvas.Top>
</Ellipse>
</Canvas>
</Grid>
</Border>
<DockPanel Grid.Row="1"
Grid.Column="2"
Margin="8,6,8,0"
LastChildFill="False">
<TextBlock DockPanel.Dock="Left"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Text="较早" />
<TextBlock DockPanel.Dock="Right"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Text="最新" />
</DockPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>
</Border> </Border>
@@ -668,43 +781,175 @@
</TextBlock.Style> </TextBlock.Style>
</TextBlock> </TextBlock>
</WrapPanel> </WrapPanel>
<Grid Height="180" Background="#FFF7FBFC"> <Grid Height="220">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="84" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="180" />
<RowDefinition Height="*" /> <RowDefinition Height="28" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" /> <Grid Grid.Column="0" Margin="0,2,4,2">
<Border Grid.Row="1" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" /> <Grid.RowDefinitions>
<Border Grid.Row="2" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" /> <RowDefinition Height="*" />
<Canvas x:Name="FlowTrendCanvas"> <RowDefinition Height="*" />
<Polyline x:Name="FlowTrendPrimaryPolyline" Stroke="#FF0B7A75" StrokeThickness="2" /> <RowDefinition Height="*" />
<Polyline x:Name="FlowTrendSecondaryPolyline" Stroke="#FF3C6FB6" StrokeThickness="2"> </Grid.RowDefinitions>
<Polyline.Style> <TextBlock Grid.Row="0"
<Style TargetType="Polyline"> VerticalAlignment="Top"
<Setter Property="Visibility" Value="Collapsed" /> HorizontalAlignment="Right"
<Style.Triggers> Style="{StaticResource CaptionStyle}"
<DataTrigger Binding="{Binding HasFlowTrendSecondary}" Value="True"> FontSize="11"
<Setter Property="Visibility" Value="Visible" /> Margin="0,0,4,0"
</DataTrigger> Text="{Binding FlowTrendTopScaleDisplay}" />
</Style.Triggers> <TextBlock Grid.Row="1"
</Style> VerticalAlignment="Center"
</Polyline.Style> HorizontalAlignment="Right"
</Polyline> Style="{StaticResource CaptionStyle}"
<Polyline x:Name="FlowTrendTertiaryPolyline" Stroke="#FFD38A16" StrokeThickness="2"> FontSize="11"
<Polyline.Style> Margin="0,0,4,0"
<Style TargetType="Polyline"> Text="{Binding FlowTrendMidScaleDisplay}" />
<Setter Property="Visibility" Value="Collapsed" /> <TextBlock Grid.Row="2"
<Style.Triggers> VerticalAlignment="Bottom"
<DataTrigger Binding="{Binding HasFlowTrendTertiary}" Value="True"> HorizontalAlignment="Right"
<Setter Property="Visibility" Value="Visible" /> Style="{StaticResource CaptionStyle}"
</DataTrigger> FontSize="11"
</Style.Triggers> Margin="0,0,4,0"
</Style> Text="0" />
</Polyline.Style> </Grid>
</Polyline> <Border Grid.Column="2"
</Canvas> BorderBrush="#FFDCE7EA"
BorderThickness="1"
Background="#FFF7FBFC"
CornerRadius="6">
<Grid Margin="6">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" />
<Border Grid.Row="1" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" />
<Border Grid.Row="2" BorderBrush="#FFE0EAEE" BorderThickness="0,0,0,1" />
<Canvas x:Name="FlowTrendCanvas">
<Polyline x:Name="FlowTrendPrimaryPolyline" Stroke="#FF0B7A75" StrokeThickness="2" />
<Polyline x:Name="FlowTrendSecondaryPolyline" Stroke="#FF3C6FB6" StrokeThickness="2">
<Polyline.Style>
<Style TargetType="Polyline">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding HasFlowTrendSecondary}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Polyline.Style>
</Polyline>
<Polyline x:Name="FlowTrendTertiaryPolyline" Stroke="#FFD38A16" StrokeThickness="2">
<Polyline.Style>
<Style TargetType="Polyline">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding HasFlowTrendTertiary}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Polyline.Style>
</Polyline>
<Ellipse Width="8" Height="8" Fill="#FF0B7A75" Stroke="White" StrokeThickness="1.5">
<Canvas.Left>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="x">
<Binding Path="ActiveFlowTrendPrimaryValues" />
<Binding ElementName="FlowTrendCanvas" Path="ActualWidth" />
<Binding ElementName="FlowTrendCanvas" Path="ActualHeight" />
<Binding Path="FlowTrendMax" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="y">
<Binding Path="ActiveFlowTrendPrimaryValues" />
<Binding ElementName="FlowTrendCanvas" Path="ActualWidth" />
<Binding ElementName="FlowTrendCanvas" Path="ActualHeight" />
<Binding Path="FlowTrendMax" />
</MultiBinding>
</Canvas.Top>
</Ellipse>
<Ellipse Width="8" Height="8" Fill="#FF3C6FB6" Stroke="White" StrokeThickness="1.5">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding HasFlowTrendSecondary}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
<Canvas.Left>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="x">
<Binding Path="ActiveFlowTrendSecondaryValues" />
<Binding ElementName="FlowTrendCanvas" Path="ActualWidth" />
<Binding ElementName="FlowTrendCanvas" Path="ActualHeight" />
<Binding Path="FlowTrendMax" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="y">
<Binding Path="ActiveFlowTrendSecondaryValues" />
<Binding ElementName="FlowTrendCanvas" Path="ActualWidth" />
<Binding ElementName="FlowTrendCanvas" Path="ActualHeight" />
<Binding Path="FlowTrendMax" />
</MultiBinding>
</Canvas.Top>
</Ellipse>
<Ellipse Width="8" Height="8" Fill="#FFD38A16" Stroke="White" StrokeThickness="1.5">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding HasFlowTrendTertiary}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
<Canvas.Left>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="x">
<Binding Path="ActiveFlowTrendTertiaryValues" />
<Binding ElementName="FlowTrendCanvas" Path="ActualWidth" />
<Binding ElementName="FlowTrendCanvas" Path="ActualHeight" />
<Binding Path="FlowTrendMax" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource TrendLastPointCoordinateConverter}" ConverterParameter="y">
<Binding Path="ActiveFlowTrendTertiaryValues" />
<Binding ElementName="FlowTrendCanvas" Path="ActualWidth" />
<Binding ElementName="FlowTrendCanvas" Path="ActualHeight" />
<Binding Path="FlowTrendMax" />
</MultiBinding>
</Canvas.Top>
</Ellipse>
</Canvas>
</Grid>
</Border>
<DockPanel Grid.Row="1"
Grid.Column="2"
Margin="8,6,8,0"
LastChildFill="False">
<TextBlock DockPanel.Dock="Left"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Text="较早" />
<TextBlock DockPanel.Dock="Right"
Style="{StaticResource CaptionStyle}"
FontSize="11"
Text="最新" />
</DockPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>
</Border> </Border>

View File

@@ -435,6 +435,10 @@ public partial class MainViewModel : ObservableObject, IDisposable
}; };
public double PressureTrendMax => MaxTrendValue([ProximalPressureTrendValues, DistalPressureTrendValues, DeltaPressureTrendValues], 40d); public double PressureTrendMax => MaxTrendValue([ProximalPressureTrendValues, DistalPressureTrendValues, DeltaPressureTrendValues], 40d);
public double FlowTrendMax => MaxTrendValue([ActiveFlowTrendPrimaryValues, ActiveFlowTrendSecondaryValues, ActiveFlowTrendTertiaryValues], Math.Max(RatedMaxFlow, 1d)); public double FlowTrendMax => MaxTrendValue([ActiveFlowTrendPrimaryValues, ActiveFlowTrendSecondaryValues, ActiveFlowTrendTertiaryValues], Math.Max(RatedMaxFlow, 1d));
public string PressureTrendTopScaleDisplay => $"{PressureTrendMax:F0}";
public string PressureTrendMidScaleDisplay => $"{PressureTrendMax / 2d:F0}";
public string FlowTrendTopScaleDisplay => $"{FlowTrendMax:F1}";
public string FlowTrendMidScaleDisplay => $"{FlowTrendMax / 2d:F1}";
public string ProximalPressureDisplay => PressureDisplay("近端压力", _proximalPressureRawKpa); public string ProximalPressureDisplay => PressureDisplay("近端压力", _proximalPressureRawKpa);
public string DistalPressureDisplay => PressureDisplay("远端压力", _distalPressureRawKpa); public string DistalPressureDisplay => PressureDisplay("远端压力", _distalPressureRawKpa);
public string FlowImbalanceDisplay => HasChannelTelemetry("主泵流量", "动脉回输流量") ? $"{Math.Abs(PumpFlow - ReturnFlow):F2} L/min" : "--"; public string FlowImbalanceDisplay => HasChannelTelemetry("主泵流量", "动脉回输流量") ? $"{Math.Abs(PumpFlow - ReturnFlow):F2} L/min" : "--";
@@ -1468,6 +1472,10 @@ public partial class MainViewModel : ObservableObject, IDisposable
OnPropertyChanged(nameof(ActiveFlowTrendTertiaryValues)); OnPropertyChanged(nameof(ActiveFlowTrendTertiaryValues));
OnPropertyChanged(nameof(PressureTrendMax)); OnPropertyChanged(nameof(PressureTrendMax));
OnPropertyChanged(nameof(FlowTrendMax)); OnPropertyChanged(nameof(FlowTrendMax));
OnPropertyChanged(nameof(PressureTrendTopScaleDisplay));
OnPropertyChanged(nameof(PressureTrendMidScaleDisplay));
OnPropertyChanged(nameof(FlowTrendTopScaleDisplay));
OnPropertyChanged(nameof(FlowTrendMidScaleDisplay));
OnPropertyChanged(nameof(PressureTrendCurrentSummary)); OnPropertyChanged(nameof(PressureTrendCurrentSummary));
OnPropertyChanged(nameof(FlowTrendCurrentSummary)); OnPropertyChanged(nameof(FlowTrendCurrentSummary));
} }