Używam klasy WeakEventManager<TEventSource, TEventArgs>
do subskrybowania zdarzeń w języku C#. Subskrypcja zdarzeń działa dobrze, jednak wywoływanie WeakEventManager<TEventSource, TEventArgs>.RemoveHandler
z Task
nie zawsze usuwa program obsługi - większość (ale nie wszystkie) czasu, w którym program obsługi jest nadal wykonywany po wywołaniu zdarzenia.WeakEventManager RemoveHandler nie zawsze działa, gdy jest asynchronicznie używany
Zostało to zilustrowane w następującym przykładzie.
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;
}
}
Handler jest usuwany przez cały czas, jednak w większości przypadków zdarzenie jest jeszcze obsługiwane.
Czy popełniam błąd w sposobie wywoływania tych metod? Czy te metody obsługują wywoływanie asynchroniczne? Czy istnieje alternatywne podejście, które zadziałałoby?
Dziękujemy za pomoc z góry.
Dzięki, to wyjaśnia, dlaczego widzę to zachowanie. Jak zmienić sposób wywoływania Add/RemoveHandler, aby programy obsługi zostały usunięte w tym samym wątku? – mickeyt
Użyj 'Application.Current.Dispatcher', aby wywołać metody' AddHandler' i 'RemoveHandler'. –
W tym przykładzie nie ma aplikacji "Application.Current". Dzięki za podpowiedź o 'DispatcherObject' choć - bardzo pomocne! – mickeyt