.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();
});
};
}
}

浙公网安备 33010602011771号