.NET事件--EventHandler

业务逻辑组件间的事件驱动

一个模块的状态发生变化,需要立即同步地通知另一个模块

// 1. 定义一个订单处理服务
public class OrderProcessor
{
    // 2. 声明一个标准事件,约定当订单处理成功时触发
    public event EventHandler<OrderProcessedEventArgs> OrderProcessed;

    public void ProcessOrder(Order order)
    {
        // ... 处理订单的业务逻辑 ...
        bool isSuccess = true;

        if (isSuccess)
        {
            // 3. 构造包含业务数据的事件参数
            var args = new OrderProcessedEventArgs 
            { 
                OrderId = order.Id, 
                ProcessTime = DateTime.Now 
            };
            // 4. 安全地触发事件(如果有订阅者)
            OnOrderProcessed(args);
        }
    }

    protected virtual void OnOrderProcessed(OrderProcessedEventArgs e)
    {
        OrderProcessed?.Invoke(this, e); // 关键行:触发事件
    }
}

// 5. 自定义事件参数,用于传递业务数据
public class OrderProcessedEventArgs : EventArgs
{
    public int OrderId { get; set; }
    public DateTime ProcessTime { get; set; }
}

// 6. 在另一个类(如邮件服务)中订阅事件
public class EmailService
{
    public EmailService(OrderProcessor processor)
    {
        // 订阅事件,关联处理方法
        processor.OrderProcessed += OnOrderProcessed;
    }

    private void OnOrderProcessed(object sender, OrderProcessedEventArgs e)
    {
        // 当订单处理成功后,自动发送确认邮件
        SendConfirmationEmail(e.OrderId);
    }
}

自定义UI控件或组件

在创建可重用的WinForms自定义控件或非WPF组件时,标准事件去暴露交互行为

public class ValidationTextBox : TextBox
{
    // 1. 定义一个事件,在输入验证通过后触发
    public event EventHandler ValidatedInputChanged;

    protected override void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);
        
        // 2. 进行自定义验证逻辑
        if (IsInputValid(this.Text))
        {
            // 3. 触发自定义事件
            ValidatedInputChanged?.Invoke(this, EventArgs.Empty);
        }
    }

    private bool IsInputValid(string text) => !string.IsNullOrWhiteSpace(text);
}

// 使用该控件
public partial class MyForm : Form
{
    public MyForm()
    {
        InitializeComponent();
        var customTextBox = new ValidationTextBox();
        customTextBox.ValidatedInputChanged += (sender, e) =>
        {
            // 当用户输入有效文本时,立即启用提交按钮
            submitButton.Enabled = true;
        };
    }
}

后台任务或服务的进度报告

public class ReportGenerator
{
    // 1. 声明一个用于报告进度的事件
    public event EventHandler<ProgressEventArgs> ProgressChanged;

    public void GenerateReport()
    {
        for (int i = 0; i <= 100; i++)
        {
            // 模拟耗时工作
            Thread.Sleep(50);
            
            // 2. 触发进度更新事件
            ProgressChanged?.Invoke(this, new ProgressEventArgs { Percentage = i });
        }
    }
}

// 在 WinForms 的 UI 层订阅和更新进度条
public partial class MainForm : Form
{
    private void btnGenerate_Click(object sender, EventArgs e)
    {
        var generator = new ReportGenerator();
        // 3. 订阅进度事件(注意跨线程问题)
        generator.ProgressChanged += (s, args) =>
        {
            // 使用 Invoke 确保在 UI 线程上更新控件
            this.Invoke(new Action(() => 
            {
                progressBar.Value = args.Percentage;
                labelProgress.Text = $"{args.Percentage}%";
            }));
        };

        // 在后台线程运行任务
        Task.Run(() => generator.GenerateReport());
    }
}

跨层或模块间通信(非MVVM)

在WInForms中(或中等复杂度的应用程序中),事件用于连接不同的业务层

// 数据访问层
public class DataRepository
{
    public event EventHandler<DataChangedEventArgs> DataChanged;

    public void UpdateRecord(Record record)
    {
        // ... 数据库更新逻辑 ...
        _database.Save(record);
        
        // 通知系统:数据已变更
        DataChanged?.Invoke(this, new DataChangedEventArgs 
        { 
            ChangedRecordId = record.Id, 
            ChangeType = ChangeType.Update 
        });
    }
}

// 业务逻辑层
public class CacheService
{
    public CacheService(DataRepository repository)
    {
        repository.DataChanged += (sender, args) =>
        {
            // 当数据库变更时,自动清理或更新相关缓存
            InvalidateCache(args.ChangedRecordId);
        };
    }
}

// 表示层(如窗体)
public class RecordGridForm : Form
{
    public RecordGridForm(DataRepository repository)
    {
        repository.DataChanged += (sender, args) =>
        {
            this.Invoke(new Action(() => RefreshGrid()));
        };
    }
}

与ScottPlot类似的库或框架集成

// 假设一个自定义数据加载器
public class RealtimeDataFeed
{
    public event EventHandler<NewDataArrivedEventArgs> NewDataArrived;

    public void Start()
    {
        _timer = new System.Timers.Timer(1000);
        _timer.Elapsed += (s, e) =>
        {
            var newData = FetchNewData();
            NewDataArrived?.Invoke(this, new NewDataArrivedEventArgs 
            { 
                DataPoints = newData 
            });
        };
        _timer.Start();
    }
}
// 自定义事件
public class NewDataArrivedEventArgs :EventArgs
{
     public IReadOnlyList<(double X, double Y)> DataPoints { get; }
    //构造函数
     public NewDataArrivedEventArgs(IEnumerable<(double X, double Y)> dataPoints)
    {
        // 这里为了安全,可以复制数据或使用不可变集合
        // 我们转换为列表并包装为只读
        DataPoints = new List<(double X, double Y)>(dataPoints).AsReadOnly();
    }
     // 也可以提供其他构造函数,例如传递单个点
    public NewDataArrivedEventArgs(double x, double y)
    {
        DataPoints = new List<(double X, double Y)> { (x, y) }.AsReadOnly();
    }
    
}
// 在图表应用程序中使用
public class ChartApp
{
    public ChartApp(RealtimeDataFeed feed, ScottPlot.WpfPlot plotControl)
    {
        feed.NewDataArrived += (sender, args) =>
        {
            plotControl.Dispatcher.Invoke(() =>
            {
                plotControl.Plot.Add.Scatter(args.DataPoints.Xs, args.DataPoints.Ys);
                plotControl.Refresh();
            });
        };
    }
}

 

posted @ 2026-01-16 12:56  菜loulou  阅读(2)  评论(0)    收藏  举报