简体   繁体   中英

Running C# WPF events asynchronously

I've been trying to wrap my head around how the WPF application's events are handled. This has probably been answered before but all my searches have been resulting in answers too complex for me to understand or just a bit off topic. My understanding is however that these events are run synchronously.

What is the reason for this? And why are they not just made asynchronous? Would it be possible to force the application to run them all of just some of them asynchronously?

Thanks!

When an event is raised, its handlers are called in sequence. The reason they are not asynchronous by default is that it would create an unnecessary overhead and would be difficult to implement. This behaviour works like this for all events in .NET and has nothing to do with WPF.

Only a single thread can access the UI in WPF. All UI events in WPF are raised from this UI thread. If a handler takes a long time to execute, the UI thread will be blocked until the handler finishes executing, resulting in the app being in the "hanging" state. The reason for this is not in scope of this question and deserves a whole separate explanation.

It's not really correct to think of events as synchronous or not. It's the handlers that are synchronous or asynchronous. So it's not possible to just specify in your app that all events are asynchronous by default. But it is possible to make all (or some) event handlers asynchronous.

It's very easy to make an event handler asynchronous - just mark it as async and await a long-running action. You can read more about async and await here .

Asynchronous event handlers don't block the UI thread because they are executed in other threads (well, it's actually a little more complicated than that, but that's the general idea).

When you say "The 'Application' Events" to you specifically mean only those DEFINED on System.Windows.Application ? OR do you JUST mean any declared event member in ANY class?

The event is a collection of method delegates: when the class raises some event it just starts invoking the handlers. If that was asynchronous then the producer of that event would not know anything about who MIGHT have handled it, and a cancellable event like Window.Closing could not be implemented --- no handler would be guaranteed to run synchronously and the producer could always get through an un-cancelled event; making that useless.

The consumers also would not know WHEN they GOT the event! If a property changed event is raised they might get invoked long after that property has then changed many more times and who knows where the application would be at that time!

A great deal of events are DESIGNED to BE handled synchronously: the application has just reached some state, and if you are not able to handle the event synchronously then it is useless --- that was why the event WAS raised to begin with.

If events were async by "default" then they become an easily accessed async "message bus", and I think if you look back at that then you will find that that is a type of "waste of time". If all you could do as an event producer was fire off some async unknown notification, then why would you bother?! At that point the producer can also be "whined at" to implement some async message for EVERY activity --- ie how would you come up with the definition of what should raise an event? (Where would you stop short of every activity; which you COULD conceive of implementing with instrumentation.)

There are lots of libraries with "Application Message Bus" implementations in them. With a singular application-wide async message bus, then you could have some notion of a service to which you could "provide" an event notification. If you have more clearly defined this thing as a place where producers post up messages and consumers can come subscribe for them, then you have some more notion of a service that you can implement and use. You could create one for your application, subscribe to existing events, and post them there for async consumers to come handle ...

Instead of async by default, you CAN now opt in to defining async events yourself if you can design that particular event to be useful in an async implementation. --- Repeating: you will NOT reliably know by default WHO handles the event at what time, if EVER.

You could also redefine any existing event with a new Async version, and add a synchronous handler that re-posts each event to the async service ... But it's all becoming down to a design that requires the events in some async manner; and a "default" async event would start to become forgotten and a buggy-maintained nightmare for the producer who will never know what happens to the events they raise (and cannot debug them in an invariant way).

... The "Mvvm" libraries have event busses in them; like MVVM Light.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM