You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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}");
    }
}

方案关键点说明

  1. 串行队列控制

    • 维护_processingQueue变量追踪当前执行的任务,每次新事件触发时,将新的处理任务追加到队列末尾
    • 用lock (_queueLock)确保多线程环境下的队列操作安全(事件可能从后台线程并发触发)
  2. 移除async void

    • 将原async void事件处理器拆分为两部分:
      • 同步的事件回调(OnEventXTriggered):仅负责将处理逻辑加入队列
      • 异步的实际处理方法(ProcessEventXAsync):包含所有业务逻辑,返回Task便于异常处理和等待
  3. UI线程切换

    • 使用Application.Current.Dispatcher.InvokeAsync异步切换回UI线程执行更新,避免阻塞任务队列
    • 如果需要等待UI更新完成再执行后续操作,await该调用即可(如上代码所示)
  4. 异常处理优化

    • 可以在ProcessEventXAsync方法中添加try/catch块捕获异常,避免未处理异常扩散
    • 也可以在队列中统一处理,例如:
      _processingQueue = _processingQueue.ContinueWith(async t => 
      {
          if (t.Exception != null)
          {
              // 处理前一个任务的异常
          }
          await ProcessEvent1Async(sender, e);
      }, TaskContinuationOptions.ExecuteSynchronously);
      

内容的提问来源于stack exchange,提问作者MaestroX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 08:07:05