In c# how should an async completed event access properties of the calling class?
We have been using lamda events like this:
bookMarkClient.wmdeleteCompleted += (s, ea) =>
{
if (ea.Result = "Success")
{
foreach (BookMark bookMark in BookMarks)
{
if (bookMarkId == bookMark.bm_id)
{
BookMarks.Remove(bookMark);
OnNotifyPropertyChanged("BookMarks");
break;
}
}
}
};
bookMarkClient.wmdeleteBookMarkAsync(bookMarkId);
However according to many answers on stackoverflow these can not be removed, such that if I call this code again my event is fired twice. So I want to remove the lambda code and do this:
//in the class constructor
bookMarkClient.wmdeleteBookMarkCompleted += new EventHandler<wmdeleteBookMarkCompletedEventArgs>(bookMarkClient_wmdeleteBookMarkCompleted);
//Proc on the same class
void bookMarkClient_wmdeleteBookMarkCompleted(object sender, wmdeleteBookMarkCompletedEventArgs e)
{
if (ea.Result = "Success")
{
foreach (BookMark bookMark in BookMarks)
{
if (bookMarkId == bookMark.bm_id)
{
BookMarks.Remove(bookMark);
OnNotifyPropertyChanged("BookMarks");
break;
}
}
}
}
//on button click
bookMarkClient.wmdeleteBookMarkAsync(bookMarkId);
HOWEVER: the variable bookMarkId is no longer available. I understand this is because the lambda event copies the variable in to the constructed class and keeps it alive for the duration of the event. So how do I do the same?
I've tried setting a private variable but test show this can be changed before the call back is received! This would also apply to the collection called Bookmarks.
Note, This is a Silverlight client and I'd rather not pass back the Id/collection in the event args as this would mean reworking lots of wcf code.
Many Thanks, Matt
ps first post to stack so take it easy 开发者_如何学Con me...
Store the event handler in a local variable; then you can add and remove the same event handler:
EventHandler<wmdeleteBookMarkCompletedEventArgs> handler = (s, ea) => { .... }
bookMarkClient.wmdeleteBookMarkCompleted += handler;
// ...
bookMarkClient.wmdeleteBookMarkCompleted -= handler;
Alternatively, a lambda expression is just syntactic sugar for a compiler-generated nested class. If you can't add the bookmark ID to the EventArgs, simulate a lambda by creating your own class:
BookmarkDeletedListener listener = new BookmarkDeletedListener(this, bookMarkId);
bookMarkClient.wmdeleteBookMarkCompleted += listener.DeleteBookmarkCompleted;
bookMarkClient.wmdeleteBookMarkCompleted -= listener.DeleteBookmarkCompleted;
// ...
class BookmarkDeletedListener
{
public BookmarkDeletedListener(ParentClass parent, string bookmarkId)
{
_parent = parent;
_bookmarkId = bookmarkId;
}
public DeleteBookmarkCompleted(object sender, wmdeleteBookMarkCompletedEventArgs e)
{
if (ea.Result = "Success")
{
foreach (BookMark bookMark in BookMarks)
{
if (_bookmarkId == bookMark.bm_id)
{
_parent.BookMarks.Remove(bookMark);
_parent.OnNotifyPropertyChanged("BookMarks");
break;
}
}
}
}
readonly ParentClass _parent;
readonly string _bookmarkId;
}
You can remove a lambda, AFAIK, as long as you hold onto it. It can even remove itself when fired:
Action<object, wmdeleteBookMarkCompletedEventArgs> handler;
handler =
(s, ea) =>
{
bookMarkClient.wmdeleteCompleted -= handler;
if (ea.Result == "Success")
...
};
bookMarkClient.wmdeleteCompleted += handler;
精彩评论