Skip to main content
 首页 » 编程设计

c#之如何在来自 Web API 的窗体加载事件上预填充 Windows 窗体控件

2024年04月12日38bhlsheji

我有一个包含两个项目的解决方案:一个是 Web API,另一个是 Windows 窗体应用程序。在 Windows 窗体应用程序中,我发送一个获取请求来检索一些数据。所以我有这样的方法:

private async Task StartFillingEvent() 
{ 
    var path = "api/Windows/GetEventNames/"; 
    List<EventItemDto> events = null; 
    HttpResponseMessage response = await client.GetAsync(path); 
    if (response.IsSuccessStatusCode) 
    { 
        events = await response.Content.ReadAsAsync<List<EventItemDto>>(); 
        var eventList = (from c in events 
                            select new ListItemVm<Guid>() 
                            { 
                                Id = c.EventId, 
                                Name = c.Title 
                            }).ToList(); 
 
        eventsDrp.FillDropDownList<Guid>("Please choose one", eventList, null); 
    } 
} 

获取我的数据并在 form_Load 中调用此方法:

private void frmOnlineBadge_Load(object sender, EventArgs e) 
{ 
    StartFillingEvent().Wait(); 
} 

我跟踪我的应用程序,它转到 Web API 并将数据检索到 Windows 窗体应用程序。但是应用程序在 if 语句中休眠。我对多线程一无所知。我的目标是与 Web API 交互。我用谷歌搜索,发现很多教程都是关于 Windows 控制台应用程序的,而不是关于 Windows 窗体的。我用控制台应用程序检查了我的程序,但我必须使用 Forms 应用程序中的控件。

我如何管理此数据检索?

请您参考如下方法:

等待 async 方法时要小心。由于它与您执行 Wait 时在同一个线程上运行,因此您会遇到死锁。 async/await 多任务处理是协作的。这意味着 await 正在等待调用者返回控制权。如果调用者现在调用 Wait,它将永远不会返回控制权。

解决方案是在任务中运行您的辅助方法:

private void frmOnlineBadge_Load(object sender, EventArgs e) 
{ 
    Task.Run(() => StartFillingEvent()).Wait(); 
} 

这会将任务包装到代理中,代理将作为真正的任务运行。因此,您必须修改填充组合框的部分:

Action fillAction = delegate() { 
    eventsDrp.FillDropDownList<Guid>("Please choose one", eventList, null); 
}; 
dropDownList.BeginInvoke(fillAction); 

原因是因为您现在在后台运行您的操作,您必须确保在 UI 线程中执行访问 UI 的部分。这是通过 Control.BeginInvoke 完成的。

更新:

我最初写道你应该使用 Control.Invoke。这是错误的,因为这个方法会阻塞,直到 UI 线程执行完 Action 为止。由于 UI 线程正在等待,这也会导致死锁。所以你必须使用 BeginInvoke。