Windows 8 - await Task<Bool> - async call back on completed listener required - c#-4.0

I have a function which opens a file from storage and returns back a Boolean specified that the file opened just fine.
private async Task<bool> SaveImage()
{
try
{
await filesave.openAsync(FileAccessMode.ReadWrite)
}
catch()
{
return false;
}
return true;
}
I want to call the await SaveImage() function, but somehow want a listener/event handler which tells me when this has completed.. upon completion I want to update my layout with new data. How is this possible using the new WINRT async/ await async methodology for windows 8? is there a work around/substitute.
How can I setup a event handler type scenario? (on complete)

You just await a call to your method, and follow it with the code that should run when it's completed. You don't need to manually register an event handler.
var succeeded = await SaveImage();
// Because of the "await" keyword in the above line, the current method
// will not continue until "SaveImage" has completed its async work and
// signaled its Task
if (succeeded) { ... }
Of course, since the above code uses the await keyword, it needs to be placed inside a method that's also marked async. If that method needs to signal its completion to its caller, then it should also return a Task or Task<T>; for example:
private async Task<string> MyHelperMethod() {
var succeeded = await SaveImage();
if (succeeded)
return "Success";
else
return "Failure";
}
// then, in some other method:
var message = await MyHelperMethod();
Or, if the method calling SaveImage is the end of the line -- say it's the handler for a Button's Click event -- then it can be async void:
private async void ButtonClick(object sender, EventArgs args) {
var succeeded = await SaveImage();
if (succeeded) { ... }
}

Joe's answer looks great, though if you insist on using an event - for example if your SaveImage() calls are in various areas of code unrelated to updating the layout - you can just raise an event when your operation completes. You can use the plain old CLR events or use a pub-sub pattern implementation like the EventAggregator from Prism or Messenger from MVVM Light. The POCE version could look like this
public event EventHandler<Tuple<StorageFile,bool>> SaveImageCompleted;
private async Task<bool> SaveImage(StorageFile file)
{
try
{
await file.OpenAsync(FileAccessMode.ReadWrite);
}
catch
{
if (SaveImageCompleted != null)
SaveImageCompleted(this, new Tuple<StorageFile, bool>(file, false));
return false;
}
if (SaveImageCompleted != null)
SaveImageCompleted(this, new Tuple<StorageFile, bool>(file, true));
return true;
}

This takes a little more code but is a VERY cool and useful way to deal with async operations, progress, cancellations and complete status in general. This was compiled in a VS2012 Winrt Store App and I ran it off a button click as you see here.
private void Save_File_Click(object sender, RoutedEventArgs e)
{
// create your op, bool = return type, string = progress report
IAsyncOperationWithProgress<bool, string> op;
// Call our async operation with progress sending the file name
op = OpenFileWithProgress("test.txt");
// not implemented here
//op.Cancel();
// when we get a progress update...
op.Progress = (info, progress) =>
{
// I'm just giving text feed back to user here
Debug.WriteLine(progress);
};
op.Completed = (info, status) =>
{
// check status for completion or cancellation...
switch (status)
{
case AsyncStatus.Completed:
// Do your completed work here
Debug.WriteLine("Completed");
break;
case AsyncStatus.Canceled:
// Operation canceled - not implemented...
Debug.WriteLine("Canceled");
break;
default:
// default stuff here
break;
}
};
}
public IAsyncOperationWithProgress<bool, string> OpenFileWithProgress(string fileName)
{
return System.Runtime.InteropServices.WindowsRuntime.AsyncInfo.Run<bool, string>((token, progress) =>
Task.Run<bool>(async () =>
{
progress.Report("Starting");
try
{
StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileName);
}
catch (Exception ex)
{
return false;
}
progress.Report("Finished");
return true;
}, token));
}

Related

JavaFX task waiting for another task to finish

I'm pretty new with concurency and I'v hit the wall several times already.
Code pretty much describes everything, but just to clarify: user press the button, application send query to db and in the meantime statusLabel is set to:
Veryfing.
200ms
Veryfing..
200ms
Veryfing...
200ms
Result of query
I'v managed to achieve that, but now, I need to use result of query in another class (if it succeed, another window is opened), but It never does. I came to conclusion that it just checks the result before Task is finished so result is always false, I have no idea how to work around this, so another class checks condition once Task is done.
First, my Authorization class
public class Authorization {
private static String query = "";
private static boolean isValid;
private static Task<Void> task;
public static void verifyLogin(String username, String password) throws SQLException{
Status.get().unbind();
isValid = false;
task = new Task<Void>() {
#Override
protected Void call() throws SQLException {
while(!isCancelled()) {
try {
updateMessage("Weryfikacja.");
Thread.sleep(200);
updateMessage("Weryfikacja..");
Thread.sleep(200);
updateMessage("Weryfikacja...");
Thread.sleep(200);
if(username.equals("") || password.equals("")) {
task.cancel();
updateMessage("Pola nie mogą być puste");
} else {
query = "SELECT login FROM users WHERE login = ?";
Query.execute(query, username);
if(!Query.resultSet.next()) {
task.cancel();
updateMessage("Nie ma takiego użytkownika");
} else {
query = "SELECT password FROM users WHERE login = ?";
Query.execute(query, username);
if(Query.resultSet.next()) {
String passwordValue = Query.resultSet.getString(1);
if(!password.equals(passwordValue)) {
task.cancel();
updateMessage("Podane hasło jest błędne");
} else {
task.cancel();
updateMessage("");
isValid = true;
}
}
}
}
} catch(InterruptedException e) {
if(isCancelled()) {
break;
}
}
}
return null;
}
};
Status.get().bind(task.messageProperty());
new Thread(task).start();
}
public static boolean isValid() {
return isValid;
}
}
called from another class
private void login() {
if( SqlConnection.isConnected()) {
try{
Authorization.verifyLogin(String.valueOf(loginInput.getText()), String.valueOf(passwordInput.getText()));
if(Authorization.isValid()) {
//should go to next menu
//but never does
}
} catch (SQLException e) {
e.printStackTrace();
Debug.log(e.toString());
}
}
}
edit#
Sorry for polish in updateMessage().
Your verifyLogin() method simply starts the verification process in another thread, and then exits immediately. The isValid flag will not be changed until that thread completes, which happens quite a lot later. If you want to do the verification process and then do something else, it doesn't really make sense to manage the threads in verifyLogin().
I don't really understand a lot of what your code is supposed to be doing; you have a while(...) loop, which as far as I can tell can only be executed once (so is redundant). You also seem to execute two SQL queries which are essentially the same. (The first checks to see if there is a row with a certain condition, then if there is, the second retrieves that row. Why not just retrieve the row and check if it is there?)
I would refactor this so that the validateLogin() method doesn't handle the threading at all, and just returns the result of the validation (e.g. a status string, but maybe something else would be appropriate).
/**
* #return An empty string if the login is valid, or an error message otherwise
*/
public static String verifyLogin(String username, String password) throws SQLException{
isValid = false ;
if(username.equals("") || password.equals("")) {
return "Pola nie mogą być puste";
}
query = "SELECT login, password FROM users WHERE login = ?";
Query.execute(query, username);
if(!Query.resultSet.next()) {
return "Nie ma takiego użytkownika";
}
String passwordValue = Query.resultSet.getString(2);
if(!password.equals(passwordValue)) {
return "Podane hasło jest błędne" ;
}
isValid = true;
return "" ;
}
Now I would manage the threads from the login() method. That way you can use the task's onSucceeded handler to execute code when the task completes:
private void login() {
if( SqlConnection.isConnected()) {
Task<String> verifyTask = new Task<String>() {
#Override
protected String call() throws SQLException {
return Authorization.verifyLogin(loginInput.getText(), passwordInput.getText());
}
};
// probably better to use a progress indicator or similar here, but:
Animation animation = new Timeline(
new KeyFrame(Duration.ZERO, e -> Status.get().set("Weryfikacja.")),
new KeyFrame(Duration.millis(200), e -> Status.get().set("Weryfikacja..")),
new KeyFrame(Duration.millis(400), e -> Status.get().set("Weryfikacja...")),
new KeyFrame(Duration.millis(600)));
animation.setCycleCount(Animation.INDEFINITE);
verifyTask.setOnSucceeded(event -> {
animation.stop();
Status.get().set(verifyTask.getValue());
if(Authorization.isValid()) { // or if (verifyTask.getValue().isEmpty())
// go to next menu
}
});
verifyTask.setOnFailed(event -> {
animation.stop();
verifyTask.getException().printStackTrace();
Debug.log(verifyTask.getException().toString());
}
animation.play();
new Thread(verifyTask()).start();
}
}

MultipleResumeHandlerExeption when forwarding from LuisDialog to IDialog [duplicate]

I'm creating a bot for FAQ . When bot start conversations send a PromptDialog with 2 options: english, french.
I want to forward the dialog to EnglishLuis when user chooses English button, and FrenchLuis when choosing French.
Here is my code :
Rootdialog.cs
public class RootDialog : IDialog<object>
{
private const string EnglishMenu = "English";
private const string FrenchMenu = "French";
private const string QAMenu = "Q&A";
private List<string> mainMenuList = new List<string>() { EnglishMenu, FrenchMenu, QAMenu };
private string location;
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Welcome to Root Dialog");
context.Wait(MessageReceiveAsync);
}
private async Task MessageReceiveAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var reply = await result;
if (reply.Text.ToLower().Contains("help"))
{
await context.PostAsync("You can implement help menu here");
}
else
{
await ShowMainmenu(context);
}
}
private async Task ShowMainmenu(IDialogContext context)
{
//Show menues
PromptDialog.Choice(context, this.CallDialog, this.mainMenuList, "What do you want to do?");
}
private async Task CallDialog(IDialogContext context, IAwaitable<string> result)
{
//This method is resume after user choise menu
// this.luisResult = result;
// var message = await result;
var selectedMenu = await result;
var message = await result;
switch (selectedMenu)
{
case EnglishMenu:
//Call child dialog without data
// context.Call(new EnglishLuis(),ResumeAfterDialog);
// context.Call(new EnglishLuis(), ResumeAfterDialog);
await Conversation.SendAsync(context.MakeMessage(), () => new EnglishLuis());
break;
case FrenchMenu:
//Call child dialog with data
context.Call(new HotelDialog(location), ResumeAfterDialog);
break;
case QAMenu:
context.Call(new LuisCallDialog(),ResumeAfterDialog);
break;
}
}
private async Task ResumeAfterDialog(IDialogContext context, IAwaitable<object> result)
{
//Resume this method after child Dialog is done.
var test = await result;
if (test != null)
{
location = test.ToString();
}
else
{
location = null;
}
await this.ShowMainmenu(context);
}
}
}
EnglishLuis.cs :
public class EnglishLuis : LuisDialog<object>
{
private string location;
// string message = $"welcome to english dialog";
public async Task None(IDialogContext context, LuisResult result)
{
string message = $"Sorry, I did not understand '{result.Query}'. Please try again";
await context.PostAsync(message);
context.Wait(this.MessageReceived);
context.Done(true);
}
[LuisIntent("gretting")]
[LuisIntent("intentfr")]
public async Task Greeting(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
{
await context.PostAsync("Welcome :) ");
context.Wait(MessageReceived);
context.Done(true);
}
[LuisIntent("test")]
public async Task test(IDialogContext context, IAwaitable<IMessageActivity> activity, LuisResult result)
{
await context.PostAsync("Do you want to test our bot ? We suggest to type : hi or who are you, help etc..");
// context.Done(true);
context.Wait(MessageReceived);
context.Done(true);
}
My problem is that when i choose English ( even French ) i got this error : here was an error sending this message to your bot: HTTP status code InternalServerError
Can you please help me how to start luis dialog ?
P.S if i start from MessagesController.cs directly works good...but my intentions is to let people choose between two languages.
I try to call the luis using : await context.Forward(new EnglishLuis(), ResumeAfterDialog, message, CancellationToken.None); but without result .
new file RootDialog.cs ( updated ) :
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using System.Threading;
namespace TeamsBot.Dialogs
{
[Serializable]
public class RootDialog : IDialog<object>
{
private const string EnglishMenu = "English";
private const string FrenchMenu = "French";
private const string QAMenu = "Q&A";
private List<string> mainMenuList = new List<string>() { EnglishMenu,
FrenchMenu, QAMenu };
private string location;
private string originalMessage;
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync("Welcome to Root Dialog");
context.Wait(MessageReceiveAsync);
}
private async Task MessageReceiveAsync(IDialogContext context,
IAwaitable<IMessageActivity> result)
{
var reply = await result;
this.originalMessage = reply.Text;
if (reply.Text.ToLower().Contains("help"))
{
await context.PostAsync("You can implement help menu here");
}
else
{
await ShowMainmenu(context);
}
}
private async Task ShowMainmenu(IDialogContext context)
{
//Show menues
PromptDialog.Choice(context, this.CallDialog, this.mainMenuList,
"What do you want to do?");
}
private async Task CallDialog(IDialogContext context, IAwaitable<string>
result)
{
var selectedMenu = await result;
switch (selectedMenu)
{
case EnglishMenu:
//Call child dialog without data
var newMessage = context.MakeMessage();
newMessage.Text = reply.Text;
await context.Forward(new EnglishLuis(), ResumeAfterDialog, newMessage, CancellationToken.None);
break;
case FrenchMenu:
//Call child dialog with data
// context.Call(new HotelDialog(location), ResumeAfterDialog);
var frenchLuis = new FrenchLuis();
var messageToForward = await result;
// await context.Forward(new FrenchLuis(), ResumeAfterDialog, messageToForward, CancellationToken.None);
break;
case QAMenu:
context.Call(new LuisCallDialog(),ResumeAfterDialog);
break;
}
}
private async Task ResumeAfterDialog(IDialogContext context, IAwaitable<object> result)
{
//Resume this method after child Dialog is done.
var test = await result;
if (test != null)
{
location = test.ToString();
}
else
{
location = null;
}
await this.ShowMainmenu(context);
}
}
}
First, doing
context.Wait(this.MessageReceived);
context.Done(true);
it's wrong. You need to choose: or you wait for a new message in the EnglishDialog or you end the EnglishDialog (with Done)
Then, you are trying to send a string in the context.Forward and you need to forward an IMessageActivity. And I suspect you want to send the original message, so you will need to save that in global variable before continuing with the prompt. Try with:
var newMessage = context.MakeMessage();
newMessage.Text = this.originalMessageText //the variable that contains the text of the original message that you will have to save at MessageReceiveAsync
await context.Forward(new EnglishLuis(), ResumeAfterDialog, newMessage, CancellationToken.None);
MessageReceivedAsync in RootDialog should looks like:
private async Task MessageReceiveAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var reply = await result;
if (reply.Text.ToLower().Contains("help"))
{
await context.PostAsync("You can implement help menu here");
}
else
{
this.originalMessage = reply.Text;
await ShowMainmenu(context);
}
}
This is how I would have implemented your method for calling the different dialogs. I tend to use dependency injection of dialogs so I don't have to constantly new them up.
private async Task CallDialog(IDialogContext context, IAwaitable<string> result)
{
//These two variables will be exactly the same, you only need one
//var selectedMenu = await result;
var message = await result;
switch (selectedMenu)
{
case EnglishMenu:
// Forward the context to the new LuisDialog to bring it to the top of the stack.
// This will also send your message to it so it gets processed there.
await context.Forward<object>(new EnglishLuis(), ResumeAfterDialog, message , CancellationToken.None);
break;
case FrenchMenu:
await context.Forward<object>(new HotelDialog(location), ResumeAfterDialog, message , CancellationToken.None);
break;
case QAMenu:
await context.Forward<object>(new LuisCallDialog(), ResumeAfterDialog, message , CancellationToken.None);
context.Call(new LuisCallDialog(),ResumeAfterDialog);
break;
}
}
There is an issue in your EnglishLuis dialog where you are using:
context.Wait(this.MessageReceived);
context.Done(true);
The issue is that both of these lines will execute when it passes through the dialog. The context.Done will cause this dialog to leave the stack so you'll end up going to the previous dialog instead, which clashes with the fact you're trying to wait for a response.
There shouldn't really be a context.Done in your luis dialog unless you want to go back to the previous Dialog. So if you're choosing to use context.Done either put it in the resumeAfter method with an appropriate condition or under a single intent for exiting this part of your program.
You didn't include a stack trace, but something that can cause issues when using Luis is if you're using one from a region other than the US. In which case you need to set the properties accordingly where the domain points to the right Luis service.
public EnglishLuis(ConstructorParameters parameters)
: base(new LuisService(new LuisModelAttribute(
"<AppId>",
"<SubscriptionKey>",
domain: "westeurope.api.cognitive.microsoft.com")))
{
// Constructor Stuff...
}

C# Parse how to wait until Query returns a value

I'm trying to retrieve user data from Parse (xamarin.ios using c#). I'm using an async method with await. My challenge is,each time I navigate to the tableView in the app, which should populate the user data in question,the table is always empty.
I would like to wait until the results have been returned before proceeding with the other portion of code.I have tried to use the ContinueWith() function but constantly ran into a build error -
Cannot implicitly convert type 'void' to System.Collections.Generic.IEnumerable<Parse.ParseObject>
My Questions:
Is this the best way to wait for the result?
How do I solve the build error?
Here is my current implementation:
public async void retrieveData(string username)
{
try
{
this.requests.ClearRequests();
refreshed = false;
var query = ParseObject.GetQuery("Requests").WhereEqualTo("username", username);
IEnumerable<ParseObject> results = await query.FindAsync().ContinueWith(t =>{
if(results != null)
{
foreach(ParseObject parseObject in results)
{
UserRequest request = new UserRequest();
request.objectId = parseObject.ObjectId;
request.make = parseObject.Get<string> ("item1");
request.model = parseObject.Get<string> ("item2");
request.year = parseObject.Get<string> ("item3");
request.userName = parseObject.Get<string> ("username");
this.requests.addRequest (request);
}
refreshed = true;
}
});
}
catch(ParseException e) {
Console.WriteLine (e.Message + e.StackTrace);
}
}
You shouldn't need a ContinueWith...that's what the await should handle.
await waits on a Task and then brings back the result with the proper return type. ContinueWith returns a Task, so you would have to grab the Result from the task to make it usable.
For more on this type of thing, you may want to check out Difference between await and ContinueWith
You can try something like this.
public async void retrieveData(string username, )
{
try
{
this.requests.ClearRequests();
refreshed = false;
var query = ParseObject.GetQuery("Requests").WhereEqualTo("username", username);
IEnumerable<ParseObject> results = await query.FindAsync();
if(results != null)
{
foreach(ParseObject parseObject in results)
{
UserRequest request = new UserRequest();
request.objectId = parseObject.ObjectId;
request.make = parseObject.Get<string> ("item1");
request.model = parseObject.Get<string> ("item2");
request.year = parseObject.Get<string> ("item3");
request.userName = parseObject.Get<string> ("username");
this.requests.addRequest (request);
}
refreshed = true;
}
//This is your refresh method for your TableView
this.RefreshTableView();
//or, if in iOS
NSNotificationCenter.DefaultCenter.PostNotificationName("resultsRetrieved", null);
}
catch(ParseException e) {
Console.WriteLine (e.Message + e.StackTrace);
}
}
To show the results in the tableView, I would recommend moving the refreshing of the tableView to a separate method that gets triggered synchronously after the results have been retrieved and parsed. This is shown with the this.RefreshTableView() call above.
If in iOS on Xamarin, another option is to post a notification to the NSNotificationCenter (the Xamarin documentation for which is here). Use the PostNotificationName part seen above instead and then add an observer in the ViewControllers that you want to be dependent on the data. This is done as follows:
Make a notificationToken object:
NSObject notificationToken;
Then in your setup method (you could put this inside of your ViewDidLoad):
void Setup ()
{
notificationToken = NSNotificationCenter.DefaultCenter.AddObserver ("resultsRetrieved", RefreshData);
}
Make your RefeshData method:
void RefreshData (NSString notifString)
{
this.tableView.ReloadData();
}
And then, make sure you dispose of the notification observer when you tear down the class
void Teardown ()
{
NSNotificationCenter.DefaultCenter.RemoveObserver (notificationToken);
}
I had a similar issue so started using callbacks. I'm using them in Xamarin.Android, pretty sure they're available in Xamarin.iOS.
Method that starts the task method - Note I am passing in a method of this class as a parameter
private async void updatedData()
{
await Utils.DataTasks.getNewLiveTips(populateTipsList);
}
Method that calls for data from server
public class DataTasks
{
public static async Task getAllData(Action<IEnumerable<ParseObjects>> callback) {
var query = new ParseQuery<ParseObjects>().OrderByDescending("updatedAt").Limit(5);
IEnumerable<ParseObjects> parseTips = await query.FindAsync();
foreach (var tip in parseTips)
{
// Save data to DB if needed
}
callback(parseTips);
}
Method I passed as parameter in the first instance is now called
private void populateTipsList(IEnumerable<ParseObjects> results)
{
mAdapter = new TipAdapter(this.Activity, results);
mRecyclerView.SetAdapter(mAdapter);
refresher.Refreshing = false;
}

Run swingworkers sequentially with semaphore

I have a panel with a JTabbedpane and in every tab you can set parameters to execute a query. When one query is busy retrieving his data from the database, you can already open a new tab to set the new parameters. To avoid overload on the database only one query may be executed at once. But when you click execute the program must remember which queries to execute in the right order. During the execution a loader icon is shown and the GUI may not be frozen, because there is a stop button you can click to stop the execution.
I used a swingworker to avoid the GUI from blocking while executing the query and that works fine. But now I want to prevent the next query to start before the previous has finished. In a model, common for the whole panel, I initialized a semaphore: private final Semaphore semaphore = new Semaphore(1, true);
This is the code which starts the swingworker (I've added println commands to see which is started, stopped or finished)
private void doStoredQuery() {
try {
semaphore.acquire();
System.out.println(queryName + "started");
worker.execute();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
And this is my swingworker (initializeWorker() is called from the constructor of the main class):
private SwingWorker<StoredQueryDataModel, Integer> initializeWorker() {
worker = new SwingWorker<StoredQueryDataModel, Integer>() {
#Override
protected StoredQueryDataModel doInBackground() throws Exception {
try {
StoredQueryDataModel dataModel = null;
publish(0);
try {
dataModel = new StoredQueryDataModel(queryRunner, ldbName, queryName, params);
} catch (S9SQLException e) {
//
} catch (Throwable e) {
showErrorMessage(e);
}
return dataModel;
}
finally {
semaphore.release();
System.out.println(queryName + "finished");
}
}
#Override
protected void process(List<Integer> chunks) {
//ignore chunks, just reload loader icon
panel.repaint();
}
#Override
protected void done() {
String error;
try {
result = get();
error = null;
} catch (Exception e) {
error = e.getMessage();
}
if(result == null) {
semaphore.release();
System.out.println(queryName + " stopped");
}
if(error == null) {
// process result
}
else {
showErrorMessage(new Throwable(error));
}
}
};
return worker;
}
I've tried putting the acquire and release on other positions in the code, but nothing seems to work. I am bot in Swingworker and sempahores quite new... Can someone help?
I have found the problem: the semaphore had to be a static variable. In my code there were as many semaphores as there are tabs, which caused them to run at the same time instead of sequentially.

Problem with execution async method

I have a problem with this code
if(Handlers.Count==0)
{
GetHandlers();
while (_handlers.Count == 0)
{
Thread.Sleep(100);
}
}
return _showroomLogs;
This method executes:
private void GetHandlers()
{
WebSerive.GetHandlersCompleted += new EventHandler<GetHandlersCompletedEventArgs>(OnGetHandlersCompleted);
WebSerive.GetHandlersAsync(_app.HandlerId);
}
but to this method:
private void OnGetHandlersCompleted(object sender, GetHandlersCompletedEventArgs e)
{
WebSerive.GetHandlersCompleted -= new EventHandler<GetHandlersCompletedEventArgs>(OnGetHandlersCompleted);
_handlers = e.Result;
}
I fall into afterd execution of
return _showroomLogs;
of cource if I remove this piece with While
What I must to do, to have executed OnGetHandlersAsync before
return _showroomLogs;
?
You need to recognise that as soon as you introduce an asynchronous operation to a sequence the whole sequence becomes asynchronous. Using blocking techniques like Sleep is 99.99999% the wrong choice.
Restructure as:-
private void GetHandlers(int handlerID, Action<IList<Handler>> returnResult)
{
EventHandler<GetHandlersCompletedEventArgs> eh = null;
eh = (s, args) =>
{
WebSerive.GetHandlersCompleted -= eh;
returnResult(args.Result);
};
WebSerive.GetHandlersCompleted += eh;
WebSerive.GetHandlersAsync(handerlID);
}
you then call with:-
GetHandlers(_app.HandlerId, handlers =>
{
_handlers = handlers;
// Do other stuff
});
Edit
Let me outline at a conceptual level what the fundemental problem is here. Lets say I have button click event, which calls FuncA. FuncA calls FuncB, FuncB calls FuncC.
click -> FuncA -> FuncB -> FuncC
This whole sequence is synchronous it might look like:-
void Button_Click(object sender, EventArgs e)
{
FuncA();
//Do other stuff
}
void FuncA()
{
var result = FuncB();
//Do stuff with result;
}
string FuncB()
{
return FuncC() + " World";
}
string FuncC()
{
return "Hello";
}
But now lets change FuncC into something that operates asynchronously. It returns immediately but its return value is not available until later, it calls a callback method when done that carries the result as parameter. The problem for FuncB is that it wants to return a value but can't until the async operation of FuncC has completed. Rather than have FuncB block the thread, we need to turn FuncB into an asynchronous operation in the same manner as FuncC. This whole process needs to bubble all the way to the event. It becomes:-
void Button_Click(object sender, EventArgs e)
{
FuncA(() =>
{
//Do other stuff after FuncA has completed
});
}
void FuncA(Action callback)
{
FuncB(result =>
{
//Do stuff with result
// then finally
callback();
});
}
void FuncB(Action<string> returnResult)
{
FuncC(result => returnResult(result + " World"));
}
void FuncC(Action<string> returnResult)
{
Dispatcher.BeginInvoke(() => returnResult("Hello"));
}
This pattern will do when there is only one actual asynchronous operation involved. Things start to get really funky when you have a series of actual async calls to make within the same operation. To avoid excessive callback nesting a little framework help is needed. I call mine the AsyncOperationService which you can read about here.

Resources