This commit is contained in:
164
AlarmScrollingText.cs
Normal file
164
AlarmScrollingText.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace PLCDataMonitor
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义滚动报警控件(跑马灯效果 + 闪烁)
|
||||
/// </summary>
|
||||
public class AlarmScrollingText : ContentControl
|
||||
{
|
||||
private TextBlock _textBlock;
|
||||
private Border _clipBorder;
|
||||
private Storyboard _scrollStoryboard;
|
||||
private Storyboard _blinkStoryboard;
|
||||
private double _currentOffset = 0;
|
||||
private DispatcherTimer _resetTimer;
|
||||
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register("Text", typeof(string), typeof(AlarmScrollingText),
|
||||
new FrameworkPropertyMetadata(string.Empty, OnTextChanged));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get { return (string)GetValue(TextProperty); }
|
||||
set { SetValue(TextProperty, value); }
|
||||
}
|
||||
|
||||
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = d as AlarmScrollingText;
|
||||
string newText = e.NewValue as string ?? string.Empty;
|
||||
control?.OnTextChanged(newText);
|
||||
}
|
||||
|
||||
public AlarmScrollingText()
|
||||
{
|
||||
// 默认样式
|
||||
DefaultStyleKey = typeof(AlarmScrollingText);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
_textBlock = GetTemplateChild("PART_TextBlock") as TextBlock;
|
||||
_clipBorder = GetTemplateChild("PART_ClipBorder") as Border;
|
||||
|
||||
if (_textBlock != null && _clipBorder != null)
|
||||
{
|
||||
_textBlock.Loaded += OnTextBlockLoaded;
|
||||
_textBlock.SizeChanged += OnTextBlockSizeChanged;
|
||||
InitializeAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTextBlockLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
StartScrollingIfNeeded();
|
||||
}
|
||||
|
||||
private void OnTextBlockSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
StartScrollingIfNeeded();
|
||||
}
|
||||
|
||||
private void OnTextChanged(string newText)
|
||||
{
|
||||
if (_textBlock != null)
|
||||
{
|
||||
_textBlock.Text = newText;
|
||||
StartScrollingIfNeeded();
|
||||
StartBlinking(newText);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeAnimations()
|
||||
{
|
||||
// 滚动动画
|
||||
_scrollStoryboard = new Storyboard();
|
||||
var doubleAnimation = new DoubleAnimation
|
||||
{
|
||||
From = 0,
|
||||
To = -500, // 临时值,后面动态计算
|
||||
Duration = TimeSpan.FromSeconds(8),
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
};
|
||||
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
|
||||
_scrollStoryboard.Children.Add(doubleAnimation);
|
||||
|
||||
// 闪烁动画(前景色交替变化)
|
||||
_blinkStoryboard = new Storyboard { RepeatBehavior = RepeatBehavior.Forever };
|
||||
var colorAnimation = new ColorAnimation
|
||||
{
|
||||
From = Colors.Red,
|
||||
To = Colors.Orange,
|
||||
Duration = TimeSpan.FromSeconds(0.5),
|
||||
AutoReverse = true,
|
||||
RepeatBehavior = RepeatBehavior.Forever
|
||||
};
|
||||
Storyboard.SetTargetProperty(colorAnimation, new PropertyPath("Foreground.Color"));
|
||||
_blinkStoryboard.Children.Add(colorAnimation);
|
||||
}
|
||||
|
||||
private void StartScrollingIfNeeded()
|
||||
{
|
||||
if (_textBlock == null || _clipBorder == null) return;
|
||||
|
||||
// 停止当前动画
|
||||
_scrollStoryboard?.Stop(_textBlock);
|
||||
_textBlock.RenderTransform = new TranslateTransform();
|
||||
|
||||
// 如果没有报警或报警文本为空,不启动滚动
|
||||
if (string.IsNullOrWhiteSpace(Text) || Text == "无报警")
|
||||
return;
|
||||
|
||||
// 等待布局完成后获取实际宽度
|
||||
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() =>
|
||||
{
|
||||
double textWidth = _textBlock.ActualWidth;
|
||||
double containerWidth = _clipBorder.ActualWidth;
|
||||
|
||||
if (textWidth <= containerWidth)
|
||||
{
|
||||
// 文本不够长,不需要滚动,但保持静止
|
||||
return;
|
||||
}
|
||||
|
||||
// 重新设置动画的目标偏移量
|
||||
double targetOffset = containerWidth - textWidth;
|
||||
var animation = _scrollStoryboard.Children[0] as DoubleAnimation;
|
||||
if (animation != null)
|
||||
{
|
||||
animation.From = 0;
|
||||
animation.To = targetOffset;
|
||||
animation.Duration = TimeSpan.FromSeconds(Math.Max(4, textWidth / 50.0)); // 速度自适应
|
||||
}
|
||||
|
||||
_textBlock.RenderTransform = new TranslateTransform();
|
||||
_scrollStoryboard.Begin(_textBlock, true);
|
||||
}));
|
||||
}
|
||||
|
||||
private void StartBlinking(string alarmText)
|
||||
{
|
||||
if (_textBlock == null) return;
|
||||
|
||||
// 停止当前闪烁
|
||||
_blinkStoryboard?.Stop(_textBlock);
|
||||
|
||||
// 如果是无效报警或无报警,恢复正常颜色并停止闪烁
|
||||
if (string.IsNullOrWhiteSpace(alarmText) || alarmText == "无报警")
|
||||
{
|
||||
_textBlock.Foreground = SystemColors.ControlTextBrush;
|
||||
return;
|
||||
}
|
||||
|
||||
// 开始闪烁动画
|
||||
_blinkStoryboard.Begin(_textBlock, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<!--<add key="PLC_IP" value="192.168.1.170" />-->
|
||||
<add key="PLC_IP" value="127.0.0.1" />
|
||||
<add key="PLC_IP" value="192.168.1.170" />
|
||||
<!--<add key="PLC_IP" value="127.0.0.1" />-->
|
||||
<add key="PLC_PORT" value="502" />
|
||||
</appSettings>
|
||||
</configuration>
|
||||
|
||||
10
App.xaml
10
App.xaml
@@ -1,9 +1,13 @@
|
||||
<Application x:Class="滑动摩擦测试仪.App"
|
||||
<Application x:Class="PLCDataMonitor.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:滑动摩擦测试仪"
|
||||
xmlns:local="clr-namespace:PLCDataMonitor"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Themes/Generic.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Data;
|
||||
using System.Windows;
|
||||
|
||||
namespace 滑动摩擦测试仪
|
||||
namespace PLCDataMonitor
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
|
||||
|
||||
<!-- 在 ResumeButton 后添加 -->
|
||||
<TextBlock x:Name="AlarmTextBlock"
|
||||
|
||||
<local:AlarmScrollingText x:Name="AlarmScrollingCtrl"
|
||||
Text="无报警"
|
||||
FontSize="10"
|
||||
Foreground="Red"
|
||||
Margin="15,0,0,0"
|
||||
VerticalAlignment="Center"/>
|
||||
Background="#FFF0F0F0"
|
||||
Height="40"
|
||||
Margin="5"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -31,7 +31,9 @@ namespace PLCDataMonitor
|
||||
|
||||
public void UpdateAlarms(string alarmMessage)
|
||||
{
|
||||
Dispatcher.Invoke(() => AlarmTextBlock.Text = alarmMessage);
|
||||
|
||||
Dispatcher.Invoke(() => // 更新滚动报警控件的文本
|
||||
AlarmScrollingCtrl.Text = alarmMessage);
|
||||
}
|
||||
|
||||
// 更新数据显示
|
||||
|
||||
31
Themes/Generic.xaml
Normal file
31
Themes/Generic.xaml
Normal file
@@ -0,0 +1,31 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PLCDataMonitor">
|
||||
|
||||
<Style TargetType="{x:Type local:AlarmScrollingText}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type local:AlarmScrollingText}">
|
||||
<Border Name="PART_ClipBorder"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
ClipToBounds="True"
|
||||
Height="40">
|
||||
<TextBlock Name="PART_TextBlock"
|
||||
Text="{TemplateBinding Text}"
|
||||
FontSize="18"
|
||||
FontWeight="Bold"
|
||||
Foreground="Red"
|
||||
VerticalAlignment="Center"
|
||||
RenderTransformOrigin="0,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
<TranslateTransform X="0"/>
|
||||
</TextBlock.RenderTransform>
|
||||
</TextBlock>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -20,4 +20,10 @@
|
||||
<PackageReference Include="WinForms.DataVisualization" Version="1.10.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="AlarmScrollingText.cs">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user