异步调用 - 如何在 UI 线程上等待它们

本文关键字:线程 等待 UI 调用 异步 | 更新日期: 2023-09-27 18:34:54

我在我正在处理的网站上有一个登录页面,并且在调用该页面的操作时,会进行一些异步Web调用,以便缓存结果以供以后使用。不过,我想做的是等待调用完成,然后再转到下一个操作。 基本上我有:

GetParticipantInfo(planID, partID );
SetCurrentInvestments(partID, planID);
GetLoanFunds(planID, partID);

其中每个都像这样拆分:

public void GetParticipantInfo(string planNumber, string participantID)
    {
        IAsyncResult _IAsyncResult;
        List<string> parameter = new List<string>();
        parameter.Add(planNumber);
        parameter.Add(participantID);
        GetParticipantInfo_A _GetParticipantInfo_A = new GetParticipantInfo_A(GetParticipantInfoAsync);
        _IAsyncResult = _GetParticipantInfo_A.BeginInvoke(participantID, planNumber, serviceContext, GetParticipantInfoAsyncCallBack, parameter);
    }
    public ParticipantDataModel GetParticipantInfoAsync(string planNumber, string partId, ServiceContext esfSC)
    {
        ParticipantDataModel pdm = new ParticipantDataModel();
        return pdm;
    }
    private void GetParticipantInfoAsyncCallBack(IAsyncResult ar)
    {
        try
        {
            AsyncResult result;              
            result = (AsyncResult)ar;
            string planID = ((List<string>)ar.AsyncState)[0];
            GetParticipantInfo_A caller = (GetParticipantInfo_A)result.AsyncDelegate;
            ParticipantDataModel pdm = caller.EndInvoke(ar);
            _cacheManager.SetCache(planID, CacheKeyName.GetPartInfo.ToString(), pdm);
        }
        catch (Exception ex)
        { }
    }

所以问题是,如何设置 UI 线程以等待调用完成,然后再继续其他操作?

回应乔:

好的,所以假设它们都返回异步结果,我可以做这样的事情吗:

List<IAsyncResult> results;
//After each call
result = OneOfTheAsyncCalls();
results.Add(result);
foreach(IAsyncResult result in results)
{
     result.AsyncWaitHandle.WaitOne();
}

还是顺序很重要?

异步调用 - 如何在 UI 线程上等待它们

您是否能够在调用方和异步回调之间使用 AutoResetEvent?

您可以使用

IAsyncResult.AsyncWaitHandle等待异步操作完成。

您的示例代码(例如 GetParticipantInfo(会丢弃IAsyncResult。 相反,请将其返回给调用方。

查看我对原始问题的编辑

是的,您的编辑看起来可以工作(或者您可以使用WaitAll而不是循环WaitOne(。

重构方法,使其使用 Task.FromAsync 方法。例如,GetParticipantInfo如下所示。我基本上将所有内容合并到这种方法中。

public Task<ParticipantDataModel> GetParticipantInfo(string planNumber, string participantID)
{
  var instance = new GetParticipantInfo_A(
    (planNumber, partID, esfSC) =>
    {
      return new ParticipantDataModel();
    }
  );
  var main = Task<ParticipantDataModel>.Factory.FromAsync(
    instance.BeginInvoke, 
    instance.EndInvoke, 
    participantID, 
    planNumber, 
    serviceContext,
    null);
  var continuation = main.ContinueWith(
    task =>
    {
      lock (_cacheManager)
      {
        _cacheManager.SetCache(planNumber, CacheKeyName.GetPartInfo.ToString(), task.Result);
      }
    });
  return continuation;
}

然后,您的页面请求代码将如下所示。我使用 Task.WaitAll 来阻止页面请求线程,直到每个单独的任务完成。

private void YourButton_Click(object sender, EventArgs args)
{
  var t1 = GetParticipantInfo(partID, plantID);
  var t2 = SetCurrentInvestments(partID, planID);
  var t3 = GetLoanFunds(planID, partID);
  Task.WaitAll(t1, t2, t3);
}