2015-03-09 19 views
8

C# içindeki olaylara abone olmak için WeakEventManager<TEventSource, TEventArgs> sınıfını kullanıyorum. Olay aboneliği iyi çalışıyor, ancak numaralı telefondan WeakEventManager<TEventSource, TEventArgs>.RemoveHandler numaralı çağrıları her zaman işleyiciyi kaldırmaz - çoğu olay işleyicisi işlendikten sonra yürütülürken gerçekleşen çoğu (ama hepsi değil).WeakEventManager RemoveHandler, zaman uyumsuz olarak çağrıldığında her zaman çalışmaz

Bu, aşağıdaki örnekte gösterilmiştir.

public class EventSource 
{ 
    public event EventHandler Fired = delegate { }; 

    public void FireEvent() 
    { 
     Fired(this, EventArgs.Empty); 
    } 
} 

class Program 
{ 
    private static bool added, removed, handled; 

    static void Main(string[] args) 
    { 
     for (int i = 1; i <= 100; i++) 
     { 
      added = removed = handled = false; 

      var source = new EventSource(); 

      AddHandlerAsync(source).Wait(); 

      RemoveHandlerAsync(source).Wait(); 

      source.FireEvent(); 

      if (removed && handled) Console.WriteLine("Event handled after removal!"); 
      else     Console.WriteLine("----------------------------"); 
     } 

     Console.ReadKey(); 
    } 

    private async static Task AddHandlerAsync(EventSource source) 
    { 
     await Task.Run(() => 
     { 
      System.Windows.WeakEventManager<EventSource, EventArgs>.AddHandler(source, "Fired", HandleEvent); 
      added = true; 
     }); 
    } 

    private async static Task RemoveHandlerAsync(EventSource source) 
    { 
     await Task.Run(() => 
     { 
      System.Windows.WeakEventManager<EventSource, EventArgs>.RemoveHandler(source, "Fired", HandleEvent); 
      removed = true; 
     }); 
    } 

    private static void HandleEvent(object sender, EventArgs e) 
    { 
     handled = true; 
    } 
} 

işleyicisi

ancak çoğu durumda olay hala işlenir, tüm zaman kaldırılır.

Bu yöntemlerin çağrılma biçiminde bir hata mı yapıyorum? Bu yöntemler senkronize olmayan olarak adlandırılmayı destekliyor mu? Çalışacak alternatif bir yaklaşım var mı?

Yardımlarınız için şimdiden teşekkür ederiz.

[ThreadStatic] 
private static WeakEventTable _currentTable; // one table per thread 

Ve varsayılan sheduler olan iş parçacığı havuzu görev sheduler kullanın:

cevap

6

WeakEventManager 'ın geçerli iş parçacığı (source) için başlatılmış bir akım WeakEventTable saklanır çünkü. Bazen aynı iş parçacığında AddHandler ve RemoveHandler'u çağırır. Ancak bazen farklı bir iş parçacığı üzerinde RemoveHandler çağırır ve EventSource isteği olmadan başka bir WeakEventManager var.

Not: Bir tür, DispatcherObject öğesinden devralınırsa, bu tür örnekleri, oluşturuldukları iş parçacığına bağlıdır. Bir DispatcherObject tekilse, iş parçacığı başına bir tane oluşturulur.

DispatcherObject görürseniz, yöntemlerini yalnızca oluşturulduğu iş parçacığından arayın. Aksi halde, sorunların olacak.

+0

Teşekkürler, neden bu davranışı görüyorum açıklıyor. İşleyicilerin aynı iş parçacığı üzerinde kaldırılması için Add/RemoveHandler aramamı nasıl değiştiririm? – mickeyt

+0

'AddHandler' ve' RemoveHandler' yöntemlerini çağırmak için 'Application.Current.Dispatcher' kullanın. –

+0

Bu örnekte 'Application.Current' yoktur. 'DispatcherObject' hakkında ipucu için teşekkürler - çok yararlı! – mickeyt