Files
huadongmocaceshiyi/AlarmScrollingText.cs
2026-03-24 19:34:22 +08:00

178 lines
6.1 KiB
C#

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;
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);
// 添加一个简单的默认样式,以防找不到模板
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
// 确保获取到模板中的元素
ApplyTemplate();
_textBlock = GetTemplateChild("PART_TextBlock") as TextBlock;
_clipBorder = GetTemplateChild("PART_ClipBorder") as Border;
if (_textBlock != null && _clipBorder != null)
{
_textBlock.SizeChanged += (s, args) => CheckAndStartScrolling();
_clipBorder.SizeChanged += (s, args) => CheckAndStartScrolling();
// 初始化滚动动画
InitializeScrollAnimation();
// 检查是否需要滚动
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(CheckAndStartScrolling));
}
else
{
// 如果找不到模板元素,添加一个简单的 TextBlock 作为后备
CreateFallbackUI();
}
}
private void CreateFallbackUI()
{
var border = new Border
{
Background = this.Background,
CornerRadius = new CornerRadius(4),
ClipToBounds = true
};
_textBlock = new TextBlock
{
Text = this.Text,
FontSize = 14,
FontWeight = FontWeights.Bold,
Foreground = Brushes.Red,
TextWrapping = TextWrapping.NoWrap,
VerticalAlignment = VerticalAlignment.Center
};
border.Child = _textBlock;
this.Content = border;
_clipBorder = border;
_textBlock.SizeChanged += (s, args) => CheckAndStartScrolling();
_clipBorder.SizeChanged += (s, args) => CheckAndStartScrolling();
InitializeScrollAnimation();
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(CheckAndStartScrolling));
}
private void InitializeScrollAnimation()
{
if (_textBlock == null) return;
_scrollStoryboard = new Storyboard();
var doubleAnimation = new DoubleAnimation
{
From = 0,
To = -500, // 初始值,稍后在 CheckAndStartScrolling 中动态更新
Duration = TimeSpan.FromSeconds(5),
RepeatBehavior = RepeatBehavior.Forever
};
Storyboard.SetTarget(doubleAnimation, _textBlock);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"));
_scrollStoryboard.Children.Add(doubleAnimation);
}
private void OnTextChanged(string newText)
{
if (_textBlock != null)
{
_textBlock.Text = newText;
// 延迟一下,等待布局更新后再检查
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(CheckAndStartScrolling));
}
}
private void CheckAndStartScrolling()
{
if (_textBlock == null || _clipBorder == null || _scrollStoryboard == null)
return;
// 停止当前动画
_scrollStoryboard.Stop(_textBlock);
_textBlock.RenderTransform = null;
// 如果没有报警或报警文本为"无报警",不启动滚动
if (string.IsNullOrWhiteSpace(Text) || Text == "无报警")
{
return;
}
// 强制更新布局以获取准确宽度
_textBlock.UpdateLayout();
_clipBorder.UpdateLayout();
double textWidth = _textBlock.ActualWidth;
double containerWidth = _clipBorder.ActualWidth;
// 如果文本宽度小于等于容器宽度,不需要滚动
if (textWidth <= containerWidth)
{
return;
}
// 计算滚动目标位置
double targetOffset = -textWidth; // 滚动到文本的左边界
// 更新动画参数
var animation = _scrollStoryboard.Children[0] as DoubleAnimation;
if (animation != null)
{
animation.From = containerWidth; // 从容器右边开始
animation.To = targetOffset; // 滚动到文本的左边界
// 根据文本长度计算滚动速度
double speed = Math.Max(3, Math.Abs(textWidth + containerWidth) / 50.0);
animation.Duration = TimeSpan.FromSeconds(speed);
}
// 设置初始变换
_textBlock.RenderTransform = new TranslateTransform();
// 开始滚动动画
_scrollStoryboard.Begin(_textBlock, true);
}
}
}