In short, I've implemented a class that derives from SynchronizationContext to make it easy for GUI applications to consume events raised on threads other than the GUI thread. I'd very much appreciate comments on my implementation. Specifically, is there anything you would recommend against or that might cause problems that I haven't foreseen? My initial tests have been successful.
The long version:
I'm currently developing the business layer of a distributed system (WCF) that uses callbacks to propagate events from the server to clients. One of my design objectives is to provide bindable business objects (i.e. INotifyPropertyChanged/IEditableObject, etc.) to make it easy to consume these on the client-side. As part of this I provide an implementation of the callback interface that handles events as they come in, updates the business objects which, in turn, raise property changed events. I therefore need these events to be raised on the GUI thread (to avoid cross-thread operation exceptions). Hence my attempt at providing a custom SynchronizationContext, which is used by the class implementing the callback interface to propagate events to the GUI thread. In addition, I want this implementation to be independent of the client environment - e.g. a WinForms GUI app or a ConsoleApp or something else. In other words, I don't want to assume that the static SynchronizationContext.Current is available. Hence my use of the ExecutionContext as a fallback strategy.
public class ImplicitSynchronisationContext : SynchronizationContext
{
private readonly ExecutionContext m_ExecContext;
private readonly SynchronizationContext m_SyncContext;
public ImplicitSynchronisationContext()
{
// Default to the current sync context if available.
if (SynchronizationContext.Current != null)
{
m_SyncContext = SynchronizationContext.Current;
}
else
{
m_ExecContext = ExecutionContext.Capture();
}
}
public override void Post(SendOrPostCallback d, object state)
{
if (m_SyncContext != null)
{
m_SyncContext.Post(d, state);
}
else
{
ExecutionContext.Run(
m_ExecContext.CreateCopy(),
(object args) =>
{
ThreadPool.QueueUserWorkItem(new WaitCallback(this.Invoker), args);
},
new object[] { d, state });
}
}
public override void Send(SendOrPostCallback d, object state)
{
if (m_SyncContext != null)
{
m_SyncContext.Send(d, state);
}
else
{
ExecutionContext.Run(
m_ExecContext.CreateCopy(),
new ContextCallback(this.Invoker),
new object[] { d, state });
}
}
private void Invoker(object args)
{
Debug.Assert(args != null);
Debug.Assert(args is object[]);
object[] parts = (object[])args;
Debug.Assert(parts.Length == 2);
Debug.Assert(parts[0] is SendOrPostCallback);
SendOrPostCallback d = (parts[0] as SendOrPostCallback);
d(parts[1]);
}
}
Unfortunately you wrote something that already exists. The SynchronizationContext class does exactly what you do. Add a property to your main class, similar to this:
public static SynchronizationContext SynchronizationContext {
get {
if (SynchronizationContext.Current == null) {
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
return SynchronizationContext.Current;
}
}
Or use AsyncOperationManager.SynchronizationContext, it does the exact same thing. Preferable of course.
I see nothing technically wrong with the code above..
However, it is more complicated than really necessary. There is no real reason to copy the ExecutionContext and run the operations within it. This happens automatically with a call to ThreadPool.QueueUserWorkItem. For details, see the docs of ExecutionContext:
Within an application domain, the entire execution context must be transferred whenever a thread is transferred. This situation occurs during transfers made by the Thread.Start method, most thread pool operations, and Windows Forms thread marshaling through the Windows message pump.
Personally, I would abandon tracking of the ExecutionContext unless there is a real need for it, and just simplify this to:
public class ImplicitSynchronisationContext : SynchronizationContext
{
private readonly SynchronizationContext m_SyncContext;
public ImplicitSynchronisationContext()
{
// Default to the current sync context if available.
m_SyncContext = SynchronizationContext.Current;
}
public override void Post(SendOrPostCallback d, object state)
{
if (m_SyncContext != null)
{
m_SyncContext.Post(d, state);
}
else
{
ThreadPool.QueueUserWorkItem(_ => d(state));
}
}
public override void Send(SendOrPostCallback d, object state)
{
if (m_SyncContext != null)
{
m_SyncContext.Send(d, state);
}
else
{
d(state);
}
}
}
I'm a little unsure about your motivation for writing this class.
If you're using WinForms or WPF, they provide implementations that are available using SynchronizationContext.Current.
If you're in a Console application, then you control the main thread. How are you communicating with this thread?
If you're running a windows message loop, presumably you are using WinForms or WPF.
If you're waiting on a producer/consumer queue, your main thread will be the one consuming the events, so by definition you will be on the main thread.
Nick
Thanks very much for the feedback everyone.
Hans Passant's answer led me to evolve/change my solution.
Just to recap, my problem was essentially how to get async callbacks from my WCF service to propagate to the UI thread of a client (WinForms or WPF) without requiring any work on the part of the client developer.
I've dropped the implementation offered above because it is redundant. My implementation of the service callback contract now simply has an overloaded constructor that takes bool synchroniseCallbacks. When it is true I store a reference to AsyncOperationManager.SynchronizationContext. When events come in from my service I post or send them using that sync context.
As Hans pointed out, the benefit if using the sync context exposed by AsyncOperationManager is that it will never be null and, also, in GUI apps such as WinForms and WPF it will return the sync context of the UI thread - problem solved!
Cheers!
Related
So we have this class implementing IValueTaskSource This code cannot be written as async-await because there's nothing to await on. We send a message to another running thread and get back a ValueTask that can be awaited by the caller to get the notification that the other thread has finished processing the message. However the other thread is pre-existing and already doing work. It receives the message by a completely other way; processes the message, then needs to tell the threadpool-origin thread that it finished. Thus; IValueTaskSource
There is no stock ValueTaskSource (not getting into whether or not there should be; however in this case a stock version would be of questionable utility). What we actully have looks very much like this:
class Message : IValueTaskSource {
public ValueTask Send()
{
/* how the message is sent is irrelevant */
return new ValueTask(this, 0);
}
private Action<object> continuation;
private object continuationState;
void IValueTaskSource.OnCompleted(Action<object> continuation, object state, short _, ValueTaskSourceOnCompletedFlags __)
{
lock(this) {
if (GetStatus(_) == ValueTaskSourceStatus.Pending)
{
this.continuation = continuation;
this.continuationState = state;
return;
}
continuation(continuationState); /* Suspect */
}
}
public void SetCompleted()
{
lock (this)
{
/* set state completed omitted for brevity */
continuation?.Invoke(continuationState); /* Suspect */
}
}
}
I think I'm doing this wrong. Imagine a large chain of these; it seems like it would build up too much stack. In particular, the lines marked /* Suspect */ are exactly that; and ValueTaskSourceOnCompletionFlags is unused. Although it does have the nicety in that an exception thrown by continuation always goes somewhere; assuming that's even a real issue.
Right now, the code works because there are only three of them and the continuations that use them are very much thread agnostic which thread they are on.
Based on the link to ManualResetValueTaskSource provided by Stephen Cleary and the corresponding source code I was able to produce an answer.
ManualResetValueTaskSourceCore<T> provides a complete implementation of IValueTaskSource<T> and IValueTaskSource<T>. This is currently a case of there's no void implementation so create a void implementation with a dummy type. There's some generalized debate on whether bool or object is the best dummy type but I think it doesn't really matter because member padding of T will force alignment anyway.
So the answer is to forward all the methods.
public ValueTask Send()
{
/* how the message is sent is irrelevant */
return CraeteValueTask();
}
private ManualResetValueTaskSourceCore<object> taskSource;
private ValueTask CreateValueTask() => new ValueTask(this, taskSource.Version);
public ValueTaskSourceStatus GetStatus(short version) => taskSource.GetStatus(version);
public void OnCompleted(Action<object> continuation, object state, short version, ValueTaskSourceOnCompletedFlags flags) => taskSource.OnCompleted(continuation, state, version, flags);
public void SetCompleted() => taskSource.SetResult(null);
In this case each message is in its own object so there's no pooling. Doesn't matter. Calling the existing implementation is so much easier than trying to write down the smallest correct implementation that it's still the better way.
I'm pretty sure if I were pooling value task sources the correct way would be to call Reset() inside CreateValueTask().
Here is an example using the INotifyCompletion interface to get the notification, instead of the heavier IValueTaskSource+ValueTask mechanism. The Message class is amended with just one additional instance field, an Action, and it has become awaitable by exposing a GetAwaiter method. Each Message instance is intended to be awaited only once.
public class Message : INotifyCompletion
{
private static readonly Action _completedSentinel = new(() => { });
private Action _continuation;
public Message GetAwaiter() { return this; }
public bool IsCompleted
=> ReferenceEquals(Volatile.Read(ref _continuation), _completedSentinel);
public void OnCompleted(Action continuation)
{
Action original = Interlocked.CompareExchange(ref _continuation,
continuation, null);
if (original is null) return; // Normal case
if (ReferenceEquals(original, _completedSentinel))
continuation(); // Rare case
else
throw new InvalidOperationException("Double await");
}
public void GetResult() { }
public void SetCompleted()
{
Action continuation = Interlocked.Exchange(ref _continuation,
_completedSentinel);
if (continuation is null) return;
ThreadPool.QueueUserWorkItem(state => ((Action)state).Invoke(), continuation);
}
}
Online demo.
The static _completedSentinel field is used in order to resolve a race condition that might occur, between the thread that awaits and the thread that invokes the SetCompleted method. Normally the await will happen first, but the implementation above will not break if it happens after the SetCompleted, or even if the SetCompleted is invoked between the IsCompleted/OnCompleted calls (these are called by the async/await machinery).
I'm struggling with NotifyCollectionChangedAction.Reset on a separate thread.
I have the following class which overrides the ObservavbleCollection so that I can suspend notifications when doing bulk updates. In the constructor I also make a call to support modifying the collection on different thread using BindingOperations.EnableCollectionSyncronization
The issue I have is when doing the NotifyCollectionChangedAction.Reset not on the UI thread I get an exception (regular Add/Remove to the collection work). I thought BindingOperations.EnableCollectionSyncronization enabled cross thread notifications?
public class ObservableDataCollection<T> : ObservableCollection<T>
{
private bool _suppressNotification = false;
private object _lock = new object();
public ObservableDataCollection(IEnumerable<T> collection) : base(collection) { BindingOperations.EnableCollectionSynchronization(Items, _lock); }
public ObservableDataCollection() { BindingOperations.EnableCollectionSynchronization(Items, _lock); }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!_suppressNotification)
base.OnCollectionChanged(e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (!_suppressNotification)
base.OnPropertyChanged(e);
}
public void SuppressNotifications(bool suppressNotification)
{
_suppressNotification = suppressNotification;
if (_suppressNotification == false)
base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
Then when I make changes
// On UI thread
var synchronizedCollection = new ObservableDataCollection();
BindingOperations.EnableCollectionSynchronization(synchronizedCollection, synchronizedCollection.SyncLock);
// Background thread
syncronizedCollection.SupressNotifications(true);
synchronizedCollection.Clear();
synchronizedCollection.Add/Remove etc
syncronizedCollection.SupressNotifications(false); // throws
I had assumed that BindingOperations.EnableCollectionSynchronization would take care of dispatching base.OnCollectionChanged in my SupressNotifications call on the UI thread.
So I need to take care of dispatching it on the UI thread.
I know I have to call BindingOperations.EnableCollectionSynchronization` from each UI thread.
The bigger question then becomes what happens and how do I manage notifications when the collection is bound on multiple UI threads?
As I have said before, the method BindingOperations.EnableCollectionSynchronization must be called on the thread that the CollectionView of ObservableDataCollection is associated with.
CollectionView has Dispatcher affinity, which is the root of all problems and the reason you must marshal theINotifyCollectionChanged handler invocation to the correct Dispatcher thread. Taking care of this should fix your problem.
The fact that you are calling BindingOperations.EnableCollectionSynchronization in the constructor may also be a reason that lead to the issue.
Consider a scenario, where the instance of the collection is created on a different thread than it is actually used: you are going to experience a cross-thread exception. It's best practice to let the user of your class handle this.
Another important point is that BindingOperations.EnableCollectionSynchronization is only applied to the CollectionView of the collection passed as the argument. This means you are currently synchronizing the view of the internal collection Items. This is not the view that is returned when setting up a Binding that has the owning ObservableDataCollection as Binding.Source. You are synchronizing the wrong collection view and must synchronize ObservableDataCollection instead:
public ObservableDataCollection()
=> BindingOperations.EnableCollectionSynchronization(this, _lock);
But since you should remove the call to BindingOperations.EnableCollectionSynchronization from the constructor and should expose the sync lock object:
public class ObservableDataCollection<T> : ObservableCollection<T>
{
public object SyncLock { get; } = new object();
private bool _suppressNotification = false;
public ObservableDataCollection(IEnumerable<T> collection) : base(collection) {}
public ObservableDataCollection() {}
}
, the proper way to mark the collection as synchronized would be:
// On UI thread
var synchronizedCollection = new ObservableDataCollection();
BindingOperations.EnableCollectionSynchronization(synchronizedCollection, synchronizedCollection.SyncLock);
// Background thread
synchronizedCollection.Clear(); // Won't throw
Summary
I have a class that uses lock to provide thread-safe access to a private field. However, for reasons detailed below I'm considering switching to using SemaphoreSlim to implement thread-safety. I know that if I surround all access to this field with lock (_lock) (as I currently do), I'm guaranteed that writes to the field will be atomic and that all threads will see the most recently-written value (source). I'm wondering if I get both of these guarantees with SemaphoreSlim, or only the guarantee about atomic writes.
Details
I have an interface I wrote a while back to represent services that can be used for communicating with external devices:
public interface ICommunicationService : IDisposable
{
event EventHandler<ReceivedMessageEventArgs> MessageReceived;
void SendMessage(GenericMessage message);
void Start();
}
I've recently come across a situation where I'd prefer to have an async implementation of these methods, and apparently when you start doing async you need to sort of go the whole hog with it to avoid deadlocks, etc., so I'm planning on updating the interface and all existing implementations that I've written to support asynchronous operation:
public interface ICommunicationService : IDisposable
{
event EventHandler<ReceivedMessageEventArgs> MessageReceived;
Task SendMessage(GenericMessage message);
Task Start();
}
One of my classes that implemented this interface did a bunch of locking in its implementations of SendMessage() and Start():
public virtual void SendMessage(GenericMessage message)
{
CheckDisposed();
lock (_lock)
{
if (CommunicationState != CommunicationState.Up)
{
throw new InvalidOperationException("Message cannot be sent as communication is not established.");
}
try
{
_currentDelegate.SendMessage(message);
}
catch (Exception)
{
TerminateCommunication();
}
}
}
Trying to switch this code to an async implementation, I noticed I couldn't await a task within a lock statement. According to async guru Stephen Cleary's blog post on the subject, the async way of doing this is to use SemaphoreSlim.
Based on that post, I've changed my SendMessage implementation to this:
public virtual async Task SendMessage(GenericMessage message)
{
CheckDisposed();
if (CommunicationState != CommunicationState.Up)
{
throw new InvalidOperationException("Message cannot be sent as communication is not established.");
}
// _mutex = new SemaphoreSlim(0, 1)
await _mutex.WaitAsync().ConfigureAwait(false);
try
{
await _currentDelegate.SendMessage(message);
}
catch (Exception)
{
TerminateCommunication();
}
finally
{
_mutex.Release();
}
}
What I'm wondering though is whether I'm guaranteed that any given thread will see the most recent value of _currentDelegate when it executes await _currentDelegate.SendMessage(message), or whether I need to use another construct to ensure writes are immediately visible to other threads.
In particular, this class has another method TryRestartCommunication:
private bool TryRestartCommunication(bool initialStart)
{
// ...
lock (_lock)
{
// ...
try
{
_currentDelegate = _factory();
_currentDelegate.Start();
_currentDelegate.MessageReceived += MessageReceived;
CommunicationState = CommunicationState.Up;
return true;
}
// ...
}
}
If I re-implement this method to lock on the semaphore and have some Thread A call TryRestartCommunication() and immediately after Thread B call SendMessage(), am I guaranteed that Thread B will see the new value of _currentDelegate set by Thread A?
If not, would a decent solution be to just make _currentDelegate volatile, or to use Interlocked to update its value?
Edit
Got a close vote because apparently this question isn't clear enough. Let me try to make it as clear as possible: if I switch from protecting my critical regions with lock to SemaphoreSlim, do I then need to mark the shared fields as volatile (or something similar) to ensure the same level of thread safety?
If you switch from protecting your critical regions/data by lock() to SemaphoreSlim(1), you will end up with the same level of thread safety.
We have done it several times and never encounter single data protection bug there.
However, be aware that after await xxx.ConfigureAwait(false); you might end in different synchronization context (thread) and the method await _currentDelegate.SendMessage(message); might not be ok with it. For example, if that method access Webform UI controls.
I am working on a VS project/solution that is used by different applications. My job is to refactor the project and change it from using xxxAsync method to using BeginInvoke.
I came up to something similar to the following code:
public class AsyncTestModel {
private delegate string DoTaskDelegate();
public static EventHandler<TaskCompletedEventArgs> OnTaskCompleted;
public static void InvokeTask() {
DoTaskDelegate taskDelegate = Task;
taskDelegate.BeginInvoke(new AsyncCallback(TaskCallback), null);
}
private static string Task() {
Thread.Sleep(5000);
return "Thread Task successfully completed.";
}
private static void TaskCallback(IAsyncResult ar) {
string result = ((DoTaskDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate).EndInvoke(ar);
if (OnTaskCompleted != null) {
OnTaskCompleted(null, new TaskCompletedEventArgs(result));
}
}
}
public class TaskCompletedEventArgs : EventArgs {
private string _message;
public TaskCompletedEventArgs(string message) : base() {
_message = message;
}
public string Message {
get {
return _message;
}
}
}
I've tested this on a new UI project I've created. The UI project contains a button and a label controls. The UI has the following code:
private void button1_Click(object sender, EventArgs e) {
AsyncTestModel.OnTaskCompleted += OnTaskCompleted;
AsyncTestModel.InvokeTask();
}
private void OnTaskCompleted(object sender, TaskCompletedEventArgs e) {
UpdateLabel(e.Message);
}
private void UpdateLabel(string message) {
this.label1.Text = message;
}
After running this, I've encountered the cross-thread exception saying the the control 'label1' is being accessed from other thread aside the thread that it was created.
Is there a way for me to invoke the OnTaskCompleted event handler on the same thread that calls the BeginInvoke method? I know I could just use the form's InvokeRequired and call the form's BeginInvoke like the following:
private delegate void DoUpdateLabelDelegate(string message);
private void UpdateLabel(string message) {
if (this.InvokeRequired) {
IAsyncResult ar = this.BeginInvoke(new DoUpdateLabelDelegate(UpdateLabel), message);
this.EndInvoke(ar);
return;
}
this.label1.Text = message;
}
But the solution above will require me to ask and apply that solution to the other development team handling applications that uses my project/solution. Those other developers shouldn't be required to know that the methods hooked to the event handler are running from different thread.
Thanks, in advance.
As designed, no, you have absolutely no idea which thread is the one on which the client's UI runs.
You can arbitrarily demand that your InvokeTask() is to be called from that UI thread. Now you know, you can copy SynchronizationContext.Current in the InvokeTask() method and, later, call its Post() or Send() method to call a method that fires the event. This is the pattern used by, for example, BackgroundWorker and async/await. Do note that copying the Current property is required to make this work, don't skip it.
That of course still won't work when your InvokeTask() method is not called from the UI thread, you'll see that Synchronization.Current is null and have no hope to marshal the call. If that's a concern then you could expose a property of type ISynchronizeInvoke, call it SynchronizingObject. Now it is up to the client code to make the call, they'll have no trouble setting the property, they'll simply assign this in their form class constructor. And you use the property's Post or Send method to call the method that raises the event. This is the pattern used by for example the Process and FileSystemWatcher classes. Don't use it if you expect your library to be used by non-Winforms client apps, unfortunately later GUI libraries like WPF and Silverlight don't implement the interface. Otherwise the exact same problem with approaches like calling Control.Begin/Invoke() yourself.
try to use this, maybe it can help you.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
//Do something...
});
I've written an assertion method Ensure.CurrentlyOnUiThread(), below, that checks that the current thread is a UI thread.
Is this going to be reliable in detecting the Winforms UI thread?
Our app is mixed WPF and Winforms, how best to detect a valid WPF UI thread?
Is there a better way to do this? Perhaps code contracts?
Ensure.cs
using System.Diagnostics;
using System.Windows.Forms;
public static class Ensure
{
[Conditional("DEBUG")]
public static void CurrentlyOnUiThread()
{
if (!Application.MessageLoop)
{
throw new ThreadStateException("Assertion failed: not on the UI thread");
}
}
}
Don't use
if(Dispatcher.CurrentDispatcher.Thread == Thread.CurrentThread)
{
// Do something
}
Dispatcher.CurrentDispatcher will, if the current thread do not have a dispatcher, create and return a new Dispatcher associated with the current thread.
Instead do like this
Dispatcher dispatcher = Dispatcher.FromThread(Thread.CurrentThread);
if (dispatcher != null)
{
// We know the thread have a dispatcher that we can use.
}
To be sure you have the correct dispatcher or are on the correct thread you have the following options
Dispatcher _myDispatcher;
public void UnknownThreadCalling()
{
if (_myDispatcher.CheckAccess())
{
// Calling thread is associated with the Dispatcher
}
try
{
_myDispatcher.VerifyAccess();
// Calling thread is associated with the Dispatcher
}
catch (InvalidOperationException)
{
// Thread can't use dispatcher
}
}
CheckAccess() and VerifyAccess() do not show up in intellisense.
Also, if you have to resort to these kinds of things its likely due to bad design. You should know which threads run what code in your program.
For WPF, I use the following:
public static void InvokeIfNecessary (Action action)
{
if (Thread.CurrentThread == Application.Current.Dispatcher.Thread)
action ();
else {
Application.Current.Dispatcher.Invoke(action);
}
}
The key is instead of checking Dispatcher.CurrentDispatcher (which will give you the dispatcher for the current thread), you need to check if the current thread matches the dispatcher of the application or another control.
Within WinForms you would normally use
if(control.InvokeRequired)
{
// Do non UI thread stuff
}
for WPF
if (!control.Dispatcher.CheckAccess())
{
// Do non UI Thread stuff
}
I would probably write a little method that uses a Generic constraint to determine which of these you should be calling. e.g.
public static bool CurrentlyOnUiThread<T>(T control)
{
if(T is System.Windows.Forms.Control)
{
System.Windows.Forms.Control c = control as System.Windows.Forms.Control;
return !c.InvokeRequired;
}
else if(T is System.Windows.Controls.Control)
{
System.Windows.Controls.Control c = control as System.Windows.Control.Control;
return c.Dispatcher.CheckAccess()
}
}
For WPF:
// You are on WPF UI thread!
if (Thread.CurrentThread == System.Windows.Threading.Dispatcher.CurrentDispatcher.Thread)
For WinForms:
// You are NOT on WinForms UI thread for this control!
if (someControlOrWindow.InvokeRequired)
Maybe Control.InvokeRequired (WinForms) and Dispatcher.CheckAccess (WPF) are OK for you?
You're pushing knowledge of your UI down into your logic. This is not a good design.
Your UI layer should be handling threading, as ensuring the UI thread isn't abused is within the purview of the UI.
This also allows you to use IsInvokeRequired in winforms and Dispatcher.Invoke in WPF... and allows you to use your code within synchronous and asynchronous asp.net requests as well...
I've found in practice that trying to handle threading at a lower level within your application logic often adds lots of unneeded complexity. In fact, practically the entire framework is written with this point conceded--almost nothing in the framework is thread safe. Its up to callers (at a higher level) to ensure thread safety.
Here is a snippet of code I use in WPF to catch attempts to modify UI Properties (that implement INotifyPropertyChanged) from a non-UI thread:
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
// Uncomment this to catch attempts to modify UI properties from a non-UI thread
//bool oopsie = false;
//if (Thread.CurrentThread != Application.Current.Dispatcher.Thread)
//{
// oopsie = true; // place to set a breakpt
//}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
For WPF:
I've needed to know is Dispatcher on my thread is actually started, or not. Because if you create any WPF class on the thread, the accepted answer will state that the dispatcher is there, even if you never do the Dispatcher.Run(). I've ended up with some reflection:
public static class WpfDispatcherUtils
{
private static readonly Type dispatcherType = typeof(Dispatcher);
private static readonly FieldInfo frameDepthField = dispatcherType.GetField("_frameDepth", BindingFlags.Instance | BindingFlags.NonPublic);
public static bool IsInsideDispatcher()
{
// get dispatcher for current thread
Dispatcher currentThreadDispatcher = Dispatcher.FromThread(Thread.CurrentThread);
if (currentThreadDispatcher == null)
{
// no dispatcher for current thread, we're definitely outside
return false;
}
// get current dispatcher frame depth
int currentFrameDepth = (int) frameDepthField.GetValue(currentThreadDispatcher);
return currentFrameDepth != 0;
}
}
You can compare thread ids like this :
var managedThreadId = System.Windows.Threading.Dispatcher.FromThread(System.Threading.Thread.CurrentThread)?.Thread.ManagedThreadId;
var dispatcherManagedThreadId = System.Windows.Application.Current.Dispatcher.Thread.ManagedThreadId;
if (managedThreadId == dispatcherManagedThreadId)
{
//works in ui dispatcher thread
}
Using MVVM it is actually fairly easy. What I do is put something like the following in, say, ViewModelBase...
protected readonly SynchronizationContext SyncContext = SynchronizationContext.Current;
or...
protected readonly TaskScheduler Scheduler = TaskScheduler.Current;
Then when a particular ViewModel needs to touch anything "observable", you can check the context and react accordingly...
public void RefreshData(object state = null /* for direct calls */)
{
if (SyncContext != SynchronizationContext.Current)
{
SyncContext.Post(RefreshData, null); // SendOrPostCallback
return;
}
// ...
}
or do something else in the background before returning to context ...
public void RefreshData()
{
Task<MyData>.Factory.StartNew(() => GetData())
.ContinueWith(t => {/* Do something with t.Result */}, Scheduler);
}
Normally, if you follow MVVM (or any other architecture) in an orderly fashion, it is easy to tell where the responsibility for UI synchronization will be situated. But you can basically do this anywhere to return to the context where your objects are created. I'm sure it would be easy to create a "Guard" to handle this cleanly and consistently in a large and complex system.
I think it makes sense to say that your only responsibility is to get back to your own original context. It is a client's responsibility to do the same.
FOR WPF:
Here's a snippet based on the top answer, using a delegate meaning it is very generic.
/// <summary>
/// Invokes the Delegate directly on the main UI thread, based on the calling threads' <see cref="Dispatcher"/>.
/// NOTE this is a blocking call.
/// </summary>
/// <param name="method">Method to invoke on the Main ui thread</param>
/// <param name="args">Argumens to pass to the method</param>
/// <returns>The return object of the called object, which can be null.</returns>
private object InvokeForUiIfNeeded(Delegate method, params object[] args)
{
if (method == null) throw new ArgumentNullException(nameof(method));
var dispatcher = Application.Current.Dispatcher;
if (dispatcher.Thread != Thread.CurrentThread)
{
// We're on some other thread, Invoke it directly on the main ui thread.
return dispatcher.Invoke(method, args);
}
else
{
// We're on the dispatchers' thread, which (in wpf) is the main UI thread.
// We can safely update ui here, and not going through the dispatcher which safes some (minor) overhead.
return method.DynamicInvoke(args);
}
}
/// <inheritdoc cref="InvokeForUiIfNeeded(Delegate, object[])"/>
public TReturn InvokeForUiIfNeeded<TReturn>(Delegate method, params object[] args)
=> (TReturn) InvokeForUiIfNeeded(method, args);
The second method allows for a more type safe return type.
I've also added some overloads that automatically take the Func and Action parameters in my code, e.g:
/// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
private void InvokeForUiIfNeeded(Action action)
=> InvokeForUiIfNeeded((Delegate) action);
Note; the Func and Action inherit from Delegate so we can just cast it.
You could also add your own generic overloads that take actions, i did not bother creating a bunch of overloads but you definitely could e.g;
/// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
private void InvokeForUiIfNeeded<T1>(Action<T1> action, T1 p1)
=> InvokeForUiIfNeeded((Delegate)action, p1);
/// <inheritdoc cref="InvokeForUiIfNeeded(System.Delegate, object[])"/>
private TReturn InvokeForUiIfNeeded<T1, TReturn>(Func<T1, TReturn> action, T1 p1)
=> (TReturn)InvokeForUiIfNeeded((Delegate)action, p1);
Thread.CurrentThread.ManagedThreadId == Dispatcher.Thread.ManagedThreadId
Is a better way to check this