如何强制执行停止直到异步功能完全执行?

时间:2014-04-02 10:25:22

标签: c# silverlight asynchronous dynamics-crm-2011 async-await

我正在为CRM创建一个silverlight应用程序,如下所示:

1- usercontrol 这是一个表单,其中填充了使用async / await从CRM检索到的数据

2- 打印按钮,用于创建该用户控件的实例并将其打印

我在执行序列中遇到问题导致Print按钮打印没有数据的用户控件,这意味着它在异步方法完成之前执行。

我的代码如下:

用户控制:

   Public partial class ManagerContact : UserControl
     // constructor and functions
     ... 
   async private  void getData(string contactid)
    {
        // get some details of the contact 

            QueryExpression query = new QueryExpression();
            query.EntityName = "contact";
            ColumnSet cset = new ColumnSet();
            cset.Columns = new System.Collections.ObjectModel.ObservableCollection<string>(new String[] { "emailaddress1","fullname"  });  
            query.ColumnSet = cset;


            IOrganizationService service = SilverlightUtility.GetSoapService();
            var response = await service.RetrieveMultiple(query);

           /// PROBLEM HERE

            List<contacts> mycontactlist= new List<contacts>();
           // a function to fill the controls in the form with the retrieved data
            ...
         }
     }

我的打印按钮:

   private  void PrintOrExport(object sender, RoutedEventArgs e)
    {
        PrintDocument document = new PrintDocument();

       ManagerContact mymanager= new Common.ManagerContact(mycontactid);

             document.PrintPage += (s, args) =>
            {
              // code here to prepare the pagevisual
            }
       document.Print("title");
     } 

当我单击Print时,会创建一个新的ManagerContact用户控件实例,执行将遍历用户控件中的所有功能,直到到达该行

   var response = await service.RetrieveMultiple(query);

然后返回打印按钮功能并继续打印页面。问题是它跳过了我用数据填充表单控件的其余函数,因此表单打印时没有数据。

我需要找到一种方法来强制执行以等待响应被返回,并且只有在它获得响应之后才会返回到主页以继续打印按钮。

1 个答案:

答案 0 :(得分:3)

您的问题归因于async void。作为一般准则,请避免async void;它应该只用于事件处理程序。有关详细信息,请参阅我的MSDN article on asynchronous best practices

因此,您的getData方法应如下所示:

private async Task getDataAsync(string contactid)

无论调用它应该await它返回Task,这意味着 函数也需要async并返回Task或者Task<T>等等。

最终,您发现您的构造函数不能是async,因此我建议您创建一个异步工厂方法as I describe on my blog

class ManagerContact
{
  private ManagerContact(int contactId)
  {
    ...
  }

  private async Task InitializeAsync()
  {
    await getDataAsync();
    ...
  }

  public static async Task<ManagerContact> CreateAsync(int id)
  {
    var result = new ManagerContact(id);
    await result.InitializeAsync();
    return result;
  }
}

然后你可以这样使用:

private async void PrintOrExport(object sender, RoutedEventArgs e)
{
  ManagerContact mymanager = await Common.ManagerContact.CreateAsync(mycontactid);
  ...
}