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

WinForms中如何通过ASP.NET Core Web API异步初始化类成员?

WinForms 异步加载DataGridView的优雅实现

针对你的需求(窗体立即打开,后台异步加载API数据填充DataGridView),结合异步编程最佳实践,给出以下实现方案:

核心思路

  1. 构造函数仅做同步初始化:完成控件创建、空集合绑定,确保窗体快速启动无阻塞。
  2. 利用窗体Load事件触发异步数据加载:在窗体显示后,后台发起API请求,避免阻塞UI线程。
  3. 并行处理多个API请求:减少总等待时间,提升加载效率。
  4. 线程安全更新UI:通过BindingSource通知控件刷新,确保操作在主线程执行。

完整代码实现

窗体成员定义

using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

public class MailForm : Form
{
    // 数据集合
    private readonly List<MailViewModel> _mails = new List<MailViewModel>();
    private readonly Dictionary<int, string> _employees = new Dictionary<int, string>();
    // 绑定源(用于DataGridView的高效刷新)
    private readonly BindingSource _mailBindingSource = new BindingSource();
    
    // 控件示例(假设你已有DataGridView和加载提示标签)
    private DataGridView dataGridViewMails;
    private Label labelLoading;

构造函数(同步初始化)

public MailForm()
    {
        InitializeComponent();
        
        // 绑定空集合,让DataGridView初始显示空白状态
        _mailBindingSource.DataSource = _mails;
        dataGridViewMails.DataSource = _mailBindingSource;
        
        // 初始化加载提示(默认隐藏)
        labelLoading.Text = "加载中...";
        labelLoading.Visible = false;
    }

异步数据加载逻辑

// 窗体Load事件触发异步初始化
    private async void MailForm_Load(object sender, EventArgs e)
    {
        await InitializeDataAsync();
    }

    // 核心异步加载方法
    private async Task InitializeDataAsync()
    {
        labelLoading.Visible = true;
        
        try
        {
            // 并行发起两个API请求,避免串行等待
            var getMailsTask = ApiClient.GetMailsAsync();
            var getEmployeesTask = ApiClient.GetEmployeesAsync();
            
            // 等待所有请求完成
            await Task.WhenAll(getMailsTask, getEmployeesTask);
            
            // 更新本地集合(此时仍在主线程,线程安全)
            _mails.Clear();
            _mails.AddRange(await getMailsTask);
            
            _employees.Clear();
            foreach (var employee in await getEmployeesTask)
            {
                _employees[employee.Id] = employee.Name;
            }
            
            // 通知DataGridView刷新数据
            _mailBindingSource.ResetBindings(false);
            
            // 可选:将Mail中的员工ID替换为显示名称
            UpdateEmployeeDisplayNames();
        }
        catch (Exception ex)
        {
            MessageBox.Show($"数据加载失败:{ex.Message}", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        finally
        {
            labelLoading.Visible = false;
        }
    }

    // 辅助方法:替换DataGridView中的员工ID为名称
    private void UpdateEmployeeDisplayNames()
    {
        foreach (DataGridViewRow row in dataGridViewMails.Rows)
        {
            if (row.DataBoundItem is MailViewModel mail)
            {
                if (_employees.TryGetValue(mail.SenderId, out var empName))
                {
                    row.Cells["SenderNameColumn"].Value = empName;
                }
            }
        }
    }
}

关键细节说明

  • 避免异步构造函数:Stephen Cleary提到的异步构造函数存在坑点,WinForms中直接在构造函数执行异步操作会导致窗体加载延迟,甚至引发线程问题,改用Load事件触发异步逻辑是更安全的选择。
  • BindingSource的作用:相比直接重新赋值DataGridView.DataSource,ResetBindings只会刷新数据而不会重建控件列,性能更优且避免布局闪烁。
  • 并行请求优化:用Task.WhenAll同时发起两个API请求,总耗时取决于最慢的那个请求,比串行请求节省时间。
  • 异常处理:捕获API请求可能的异常,给用户明确提示,避免窗体无响应或崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:38:01