工控上位机中 WPF 跑马灯组件的实现

230 阅读3分钟

前言

在工业控制软件开发中,用户界面(UI)的设计不仅要求功能完善,更需要具备良好的可视化效果和交互体验。跑马灯组件作为主界面中不可或缺的一部分,常用于实时展示检测结果、状态变化等信息。

本文基于 WPF 详细讲解如何实现一个高效、可扩展的跑马灯控件,并结合实际项目代码进行说明。适用于工控上位机开发、自动化监控系统等场景。

介绍

跑马灯组件通常用于动态显示一系列条目信息,如检测结果、任务状态、报警信息等。它通过从右向左滚动或轮替的方式更新内容,使得用户能快速获取最新的信息。

本文将围绕以下内容展开:

  • 跑马灯的使用方式

  • 跑马灯组件的核心实现逻辑

  • 控件结构设计与数据绑定

跑马灯的效果如下图所示:

如何使用

在主界面上添加跑马灯控件

首先,在 WPF 主界面 XAML 中引入自定义用户控件 CellBlockList,并将其放置在合适的布局容器中:

<Border Grid.Row="3">
    <local:CellBlockList x:Name="cellBlockList" Margin="4"></local:CellBlockList>
</Border>

注:local 是指向你项目命名空间的别名,确保已正确声明。

初始化控件数量

在主界面构造函数中,根据视窗大小初始化跑马灯中显示的条目数量:

cellBlockList.InitControl(9);

新增一条跑马灯信息

当软件完成一个检测任务后,调用如下方法将新信息插入到跑马灯列表中:

Dispatcher.Invoke(new Action(() =>
{
    cellBlockList.AddCellToHorseRaceLamp(cell);
}));

使用 Dispatcher.Invoke 确保操作发生在 UI 线程,避免跨线程异常。

如何实现

核心控件:CellBlockList

CellBlockList 是一个继承自 UserControl 的自定义控件,负责管理多个 CellBlock 实例,并实现跑马灯的数据更新和动画效果。

XAML 定义

<UserControl x:Class="AOI.CellBlockList"
             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:local="clr-namespace:AOI"
             mc:Ignorable="d" 
             d:DesignHeight="80" d:DesignWidth="700">
    <Grid x:Name="listGrid" ShowGridLines="False" Margin="0">
        <!-- 根据用户控件的构造函数,代码创建子控件 -->
    </Grid>
</UserControl>

后台逻辑

namespace AOI
{
    public partial class CellBlockList : UserControl
    {
        private List<CellBlockViewModel> _cellBlockModels = new List<CellBlockViewModel>();
        private List<CellBlock> _cellBlock = new List<CellBlock>();

        public CellBlockList()
        {
            InitializeComponent();
            InitCellBlock();
        }

        public void InitControl(int count)
        {
            for (int i = 0; i < count; i++)
            {
                listGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
                CellBlock cellBlock = new CellBlock();
                Grid.SetColumn(cellBlock, i);
                listGrid.Children.Add(cellBlock);
                _cellBlock.Add(cellBlock);
            }

            InitCellBlock();
        }

        private void InitCellBlock()
        {
            _cellBlockModels = new List<CellBlockViewModel>(_cellBlock.Count);
            for (int i = 0; i < _cellBlock.Count; i++)
            {
                CellBlockViewModel model = new CellBlockViewModel()
                {
                    Quality = string.Empty,
                    Color = string.Empty,
                    BgColor = "Gray",
                    CellID = string.Empty
                };
                _cellBlockModels.Add(model);
                _cellBlock[i].SetValue(model);
            }
        }

        public void AddCellToHorseRaceLamp(Cell cell)
        {
            for (int i = _cellBlockModels.Count - 1; i > 0; i--)
            {
                _cellBlockModels[i] = _cellBlockModels[i - 1];
            }
            _cellBlockModels[0] = GetCellBlockViewModel(cell);

            for (int i = 0; i < _cellBlockModels.Count; i++)
            {
                _cellBlock[i].SetValue(_cellBlockModels[i]);
            }
        }

        private CellBlockViewModel GetCellBlockViewModel(Cell cell)
        {
            ConfigItemEntity qualityItem = Config.XMLConfig.CellConfig.Qualitys.Find(o => { return o.Label == cell.QualityName; });
            string colorName = qualityItem != null ? qualityItem.Unit : "Green";
            string color = Config.XMLConfig.CellConfig.Colors.Count == 0 ? "---" : Config.XMLConfig.CellConfig.Colors[cell.Color].Label;

            return new CellBlockViewModel
            {
                CellID = cell.ID.Replace("\0", ""),
                Quality = cell.QualityName,
                Color = color,
                BgColor = colorName
            };
        }
    }
}

单元格控件:CellBlock

CellBlock 是每个跑马灯条目的具体显示控件,包含 ID、颜色、质量等字段,并支持背景色设置。

XAML 设计预览图

代码实现

namespace AOI
{
    public partial class CellBlock : UserControl
    {
        public string Quality
        {
            set { lblQuality.Content = value; }
        }

        public string Color
        {
            set { lblColor.Content = value; }
        }

        public string CellID
        {
            set { lblCellID.Content = value; }
        }

        public string BgColor
        {
            set
            {
                System.Drawing.Color bgColor = System.Drawing.Color.FromName(value);
                cellBlockBorder.Background = new SolidColorBrush(System.Windows.Media.Color.FromRgb(bgColor.R, bgColor.G, bgColor.B));
            }
        }

        public CellBlock()
        {
            InitializeComponent();
        }

        public void SetValue(CellBlockViewModel model)
        {
            Quality = model.Quality;
            Color = model.Color;
            CellID = model.CellID;
            BgColor = model.BgColor;
        }
    }
}

总结

本文详细介绍了在 WPF 平台上实现一个工业控制软件中常用的跑马灯组件的方法。

通过 CellBlockListCellBlock 的组合设计,实现了条目的动态更新、数据绑定以及灵活的样式控制。

该实现具有以下优点:

  • 结构清晰,易于维护和扩展

  • 支持多字段信息展示

  • 可以根据需求调整列数和动画效果

  • 符合工控软件对实时性和稳定性的要求

对于希望提升界面交互体验的工控开发者而言,本方案提供了一个实用的参考。

关键词

WPF、跑马灯、工控上位机、自定义控件、CellBlockList、CellBlock、数据绑定、用户控件、工业软件、UI设计