问题
I'm creating a silverlight application for CRM as follow:
1- A usercontrol which is a form is filled with data retrieved from the CRM using async/await
2- A Print button that creates an instance of that usercontrol and prints it
I have a problem in the sequence of execution that causes the Print button to print the usercontrol with no data, meaning, it's executed before the async method finishes.
My code is as follows:
User control:
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
...
}
}
My Print Button:
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");
}
When I click Print, a new instance of ManagerContact user control is created and execution goes through all the functions in the user control till it reaches the line
var response = await service.RetrieveMultiple(query);
and then it returns back to the Print Button function and proceeds to print the page. The problem is it skips the rest of the functions where I fill the form controls with the data and so the form is printed with no data.
I need to find a way to force execution to wait for the response to be returned and only after it gets teh response execution would go back to the main page for the rest of the print button.
回答1:
Your problem is due to async void
. As a general guideline, avoid async void
; it should only be used for event handlers. For more information, see my MSDN article on asynchronous best practices.
So, your getData
method should look like this:
private async Task getDataAsync(string contactid)
And whatever calls it should await
the Task
it returns, which means that function also needs to be async
and return Task
or Task<T>
, etc.
Eventually, you'll find that your constructor cannot be async
, so I recommend you create an asynchronous factory method 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;
}
}
Which you can then use like this:
private async void PrintOrExport(object sender, RoutedEventArgs e)
{
ManagerContact mymanager = await Common.ManagerContact.CreateAsync(mycontactid);
...
}
来源:https://stackoverflow.com/questions/22808475/how-to-force-execution-to-stop-till-asynchronous-function-is-fully-executed