第六节、C# 上位机委托 & 事件详解(异步通信与 UI 更新实战版

C# 上位机委托 & 事件详解(异步通信与 UI 更新实战版)

在 C# 上位机开发中,委托 & 事件是实现 “通信层与 UI 层解耦”、“异步数据回调” 的核心机制,尤其在串口 / 网口异步通信、多设备数据反馈、UI 实时更新场景中不可或缺。本文将从委托基础到事件实战,结合工控上位机场景,详解委托 & 事件的使用逻辑、Action/Func泛型委托的简化技巧,以及如何通过它们实现通信层与 UI 层的解耦和异步 UI 更新。

一、 委托:定义方法模板,实现方法 “间接调用”

1. 委托的核心定义(工控场景解读)

委托(Delegate)是 C# 中的类型安全的方法指针,本质是 “方法模板的定义”—— 它规定了方法的返回值类型、参数列表格式,任何符合该格式的方法都可以被委托引用,实现 “通过委托间接调用方法”,无需直接依赖方法所属类。

对于上位机开发,委托的核心价值:

  • 解耦:通信层(如串口类)无需知道 UI 层的具体更新方法,只需通过委托调用,实现两层分离;
  • 灵活:一个委托可以引用多个方法(多播委托),实现 “一处触发,多处响应”(如串口接收数据后,同时更新 UI、存储数据库、触发报警);
  • 异步支撑:配合异步操作(如Task),实现异步通信数据的回调通知(如串口异步接收数据后,通过委托回调到 UI 层)。

2. 委托的基础使用:自定义委托(理解方法模板)

先通过自定义委托理解核心逻辑,再过渡到Action/Func泛型委托的简化使用。

(1) 自定义委托语法

// 定义委托:规定方法模板(返回值void,参数:int(设备ID)、string(数据内容))
// 对应工控场景:串口接收数据后,传递设备ID和数据内容给UI层
public delegate void SerialDataReceivedDelegate(int deviceId, string data);

(2) 工控场景实战:串口通信层使用自定义委托

using System;
using System.IO.Ports;

namespace UpperComputerDelegateEvent
{
    /// <summary>
    /// 串口通信层(底层:仅负责数据收发,不关心UI层如何处理)
    /// </summary>
    public class SerialCommunicator
    {
        private SerialPort _serialPort;
        // 声明委托字段:用于引用符合模板的方法(如UI层的更新方法)
        public SerialDataReceivedDelegate? OnDataReceived;

        public SerialCommunicator(string portName, int baudRate)
        {
            _serialPort = new SerialPort
            {
                PortName = portName,
                BaudRate = baudRate,
                Parity = Parity.None,
                DataBits = 8,
                StopBits = StopBits.One,
                ReadTimeout = 1000,
                WriteTimeout = 1000
            };

            // 绑定串口异步接收数据事件
            _serialPort.DataReceived += SerialPort_DataReceived;
        }

        /// <summary>
        /// 打开串口
        /// </summary>
        public bool OpenPort()
        {
            try
            {
                if (!_serialPort.IsOpen)
                {
                    _serialPort.Open();
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"串口打开失败:{ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 关闭串口
        /// </summary>
        public bool ClosePort()
        {
            try
            {
                if (_serialPort.IsOpen)
                {
                    _serialPort.Close();
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"串口关闭失败:{ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 串口异步接收数据(底层逻辑)
        /// </summary>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // 读取串口接收的数据
                string recvData = _serialPort.ReadExisting();
                int deviceId = 1; // 模拟设备ID

                // 委托不为空时,间接调用引用的方法(如UI层更新方法)
                OnDataReceived?.Invoke(deviceId, recvData);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"数据接收失败:{ex.Message}");
            }
        }
    }
}

(3) UI 层绑定委托,实现数据更新

/// <summary>
/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工业程序猿老赵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值