WPF应用中事件处理器任务的串行化入队实现需求
解决方案
核心思路是通过异步任务队列控制所有事件处理的串行执行,同时拆分事件处理器以移除async void。
修改后的Presenter代码
using System.Windows; using System.IO; public class Presenter { private readonly LongJobWorker _worker; private Task _processingQueue = Task.CompletedTask; private readonly object _queueLock = new object(); public Presenter() { _worker = new LongJobWorker(); } public void Start() { _worker.Event1 += OnEvent1Triggered; _worker.Event2 += OnEvent2Triggered; _ = Task.Run(async () => await _worker.DoSomething()); } // 同步事件回调,仅负责将处理逻辑加入串行队列 private void OnEvent1Triggered(object sender, MyEventArgs e) { lock (_queueLock) { _processingQueue = ProcessEvent1Async(sender, e); } } private void OnEvent2Triggered(object sender, MyEventArgs e) { lock (_queueLock) { _processingQueue = ProcessEvent2Async(sender, e); } } // 异步事件处理逻辑,替代原async void方法 private async Task ProcessEvent1Async(object sender, MyEventArgs e) { // 等待队列中前一个任务完全完成 await _processingQueue; // 切换回UI线程执行同步更新 await Application.Current.Dispatcher.InvokeAsync(() => UpdateSomethingInUI(e.Value)); // 执行异步IO操作 await WriteSomethingOnFile(e.Value); } private async Task ProcessEvent2Async(object sender, MyEventArgs e) { await _processingQueue; await Application.Current.Dispatcher.InvokeAsync(() => UpdateSomethingElseInUI(e.Value)); await WriteSomethingElseOnFile(e.Value); } // 示例UI更新方法 private void UpdateSomethingInUI(int value) { // 实际UI更新逻辑,如: // MyLabel.Content = $"Event1: {value}"; } // 示例异步文件写入方法 private Task WriteSomethingOnFile(int value) { return File.WriteAllTextAsync($"Event1_Log_{value}.txt", $"Event1 triggered with value: {value}"); } private void UpdateSomethingElseInUI(int value) { // 其他UI更新逻辑 // MyOtherLabel.Content = $"Event2: {value}"; } private Task WriteSomethingElseOnFile(int value) { return File.WriteAllTextAsync($"Event2_Log_{value}.txt", $"Event2 triggered with value: {value}"); } }
方案关键点说明
串行队列控制
- 维护
_processingQueue变量追踪当前执行的任务,每次新事件触发时,将新的处理任务追加到队列末尾 - 用
lock (_queueLock)确保多线程环境下的队列操作安全(事件可能从后台线程并发触发)
- 维护
移除
async void- 将原
async void事件处理器拆分为两部分:- 同步的事件回调(
OnEventXTriggered):仅负责将处理逻辑加入队列 - 异步的实际处理方法(
ProcessEventXAsync):包含所有业务逻辑,返回Task便于异常处理和等待
- 同步的事件回调(
- 将原
UI线程切换
- 使用
Application.Current.Dispatcher.InvokeAsync异步切换回UI线程执行更新,避免阻塞任务队列 - 如果需要等待UI更新完成再执行后续操作,
await该调用即可(如上代码所示)
- 使用
异常处理优化
- 可以在
ProcessEventXAsync方法中添加try/catch块捕获异常,避免未处理异常扩散 - 也可以在队列中统一处理,例如:
_processingQueue = _processingQueue.ContinueWith(async t => { if (t.Exception != null) { // 处理前一个任务的异常 } await ProcessEvent1Async(sender, e); }, TaskContinuationOptions.ExecuteSynchronously);
- 可以在
内容的提问来源于stack exchange,提问作者MaestroX
相关产品推荐
相关产品推荐

