2

I have a situation where I'm inside an event handler, and I need to change certain state information. However, it's not safe to change while I'm still in the handler, hence I need to execute it after I've exited. It does have to execute on the same thread however. It just has to happen in the future, not right then.

Now back in the Win32 days, you had two choices to send messages to a window:

  1. SendMessage, which means 'Process the message right now!', usually because you needed the result right then, or...
  2. PostMessage, which only said 'Add the message to the Window's queue so the run-loop can pick it up.

Option 2 is the equivalent of what I'm after: 'posting' (scheduling) some code to be executed sometime in the future.

Note: Searching here for 'C# equivalent of PostMessage' gives you this seemingly-related question. However, as most questions about PostMessage are, they too are asking about background threads and getting notifications back on the main thread, which again is not what I'm asking. I'm specifically talking about the same thread, just not right now. Anyway, just trying to stave off duplicate votes since that seems like an exact match. It's not.

So what's the C#/WPF equivalent of PostMessage where I don't need the result of the call, but it has to still happen on the same thread, and sometime after the current event has been fully handled?

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • 2
    How about Dispatcher.BeginInvoke with a priority lower than Normal? – Clemens Sep 03 '18 at 07:21
  • 1
    Interesting! This sounds promising. Checking out the docs now. Can you post a quick answer with an example? Would help others too. – Mark A. Donohoe Sep 03 '18 at 07:24
  • @Clemens, `SynchronizationContext.Current` is the suggested way it is an abstraction over `Dispatcher.BeginInvoke`. `SynchronizationContext.Current` will call internally, for WPF, `Dispatcher.BeginInvoke` – Hasan Emrah Süngü Sep 03 '18 at 07:25
  • 1
    Ok, then that's the way to go. No need for an example that explicitly uses the Dispatcher. See also [this Q/A](https://stackoverflow.com/q/24671883/1136211) for details. Using Dispatcher explicitly is easier when you do a cross-thread invocation. – Clemens Sep 03 '18 at 07:31
  • 1
    Here is [another example](https://stackoverflow.com/a/21185153/17034) of using BeginInvoke to solve a re-entrancy problem. – Hans Passant Sep 03 '18 at 08:54

2 Answers2

3

If I understood correctly then what you are after is

//Will work sync
SynchronizationContext.Current.Send(...);
//Will work async
SynchronizationContext.Current.Post(...);

methods respectively.

Please have a look at this marvelous article as well https://blogs.msdn.microsoft.com/pfxteam/2012/06/15/executioncontext-vs-synchronizationcontext/

Hasan Emrah Süngü
  • 3,488
  • 1
  • 15
  • 33
  • You can post to your current thread's `SynchronizationContext`. It will work on the same thread as well. You do not need to create synchronization between threads either by using `SynchronizationContext` – Hasan Emrah Süngü Sep 03 '18 at 07:27
  • If you create a new thread of task, then `SynchronizationContext.Current` returns `null` for those. You have to capture the sync context in a variable. Which is what they do in the article you posted. – Dirk Sep 03 '18 at 07:35
  • @Dirk, Depends on the way you create task, or thread. SynchronizationContext can be captured or be set to null. For example If you are running on threadpool with `Task.Run` then you will get null for `SynchronizationContext.Current` – Hasan Emrah Süngü Sep 03 '18 at 07:37
  • 1
    Just giving you a heads-up. This was perfect! Here's what it was used for... Using a Binding with Dynamic Resources: https://stackoverflow.com/q/33816511/168179 – Mark A. Donohoe Sep 03 '18 at 20:19
  • @MarqueIV, I am glad I was of help to you :) – Hasan Emrah Süngü Sep 04 '18 at 02:32
  • As I said, it worked perfectly. If you do any WPF programming, you should check out the link to my other post here. Your piece was a key component to helping me solve something that I've literally been trying to address for over three years. Today was a good day! :) – Mark A. Donohoe Sep 04 '18 at 02:35
0

A crude but easy to understand method is to enable a timer, and then do your work when the timer fires.

Robin Bennett
  • 3,192
  • 1
  • 8
  • 18
  • I needed to trigger the update of a description, based on a selection in a treeview. The need to update could be triggered by control Enter, but just posting the message would be before the treeview selection had potentially changed. Using a timer with a short timeout was superior to Posting in this case – Kirk Bates Feb 09 '21 at 13:05