2016-04-16 89 views
3

當我需要收集已通過包含異步調用的事件hadnler更改的事件參數數據時,出現問題。正如您在下面的代碼中看到的,MessageReceiver引發事件並從屬性「Change」收集數據,並繼續處理。問題在於事件處理程序是異步的,因爲它使用「await」來調用asny方法。在方法OnMyEvent代碼在調用處理程序後立即繼續,它不會等待處理程序完成,所以「更改」屬性沒有設置...如何使更多的東西「同步」?通過事件參數的異步事件處理函數回調

public class MyEventArgs:EventArgs 
{ 
    public bool Change { get; set; } 
} 

public delegate void MyEventHandler(object sender, MyEventArgs e); 

public class MessageReceiver 
{ 
    public event MyEventHandler MyEvent; 

    public void RaiseEvent() 
    { 
     OnMyEvent(); 
    } 

    protected void OnMyEvent() 
    { 
     MyEventArgs e = new MyEventArgs(); 
     if (MyEvent != null) 
      MyEvent(this, e); 
     if (e.Change) 
      Console.WriteLine("Change occured"); 
    } 
} 
public class Form 
{ 
    MessageReceiver mr; 
    public Form(MessageReceiver MR) 
    { 
     mr = MR; 
     mr.MyEvent += Mr_MyEvent; 
    } 

    private async void Mr_MyEvent(object sender, MyEventArgs e) 
    { 
     string s = await GetString(); 
     e.Change = true; 
    } 

    public async Task<string> GetString() 
    { 
     return await Task.Factory.StartNew(() => 
     { 
      return Guid.NewGuid().ToString(); 
     } 
      ); 
    } 
} 
public class Program 
{ 
    static void Main(string[] args) 
    { 
     MessageReceiver mr = new MessageReceiver(); 
     Form frm = new Form(mr); 
     mr.RaiseEvent(); 
    } 
} 
+0

Bacause我寫一個處理程序,我可以設法得到這樣的異步方法GetString的結果: 私人無效Mr_MyEvent(對象發件人,MyEventArgs e) {s} s = GetString()。 e.Change = true; }但如果其他人寫一個處理程序呢?如何等待事件處理程序在「OnMyEvent」方法中完成? – vpetrovic

回答

2

我在我的博客上討論a variety of approaches for asynchronous events。我建議延期的做法,您可以實現使用DeferralManagerIDeferralSource類型從我Nito.AsyncEx.Coordination library

public class MyEventArgs: EventArgs, IDeferralSource 
{ 
    private readonly DeferralManager _deferralManager; 
    public MyEventArgs(DeferralManager deferralManager) 
    { 
    _deferralManager = deferralManager; 
    } 
    public bool Change { get; set; } 
    public IDisposable GetDeferral() { return _deferralManager.GetDeferral(); } 
} 

public class MessageReceiver 
{ 
    protected async Task OnMyEventAsync() 
    { 
    if (MyEvent != null) 
    { 
     DeferralManager deferralManager = new DeferralManager(); 
     MyEventArgs e = new MyEventArgs(deferralManager); 
     MyEvent(this, e); 
     await deferralManager.WaitForDeferralsAsync(); 
    } 
    if (e.Change) 
     Console.WriteLine("Change occured"); 
    } 
} 

public class Form 
{ 
    private async void Mr_MyEvent(object sender, MyEventArgs e) 
    { 
    using (e.GetDeferral()) 
    { 
     string s = await GetString(); 
     e.Change = true; 
    } 
    } 
} 
+0

用這種方法幹得好,我會盡力在我的項目中實現這一點。所以我們必須意識到「邪惡」異步事件處理程序並自己處理這些情況。 – vpetrovic