Detecting whether on UI thread in WPF and Winforms - c#

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

Related

Using BindingOperations.EnableCollectionNotifications and suspending notifications

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

How to read/write from a global variable in main thread

I have a C# Windows IoT Background application I have created. That application has multiple threads in the ThreadPool that run indefinitely.
These threads need to be able to read/write to global variables in the main thread, but I am not sure how to accomplish this. Here is an example of what I am trying to do:
// main task
public sealed class StartupTask : IBackgroundTask
{
private static BackgroundTaskDeferral _Deferral = null;
private static MyThreadClass1 thread1 = null;
private static MyThreadClass2 thread2 = null;
private static MyThreadClass3 thread3 = null;
List<Object> MyDevices = null;
public async void Run(IBackgroundTaskInstance taskInstance)
{
_Deferral = taskInstance.GetDeferral();
MyDevices = GetDeviceList();
thread1 = new MyThreadClass1();
await ThreadPool.RunAsync(workItem =>
{
thread1.Start();
});
thread2 = new MyThreadClass2();
await ThreadPool.RunAsync(workItem =>
{
thread2.Start();
});
thread3 = new MyThreadClass3();
await ThreadPool.RunAsync(workItem =>
{
thread3.Start();
});
}
}
internal class MyThreadClass1
{
public async void Start()
{ }
}
internal class MyThreadClass2
{
public async void Start()
{ }
}
internal class MyThreadClass3
{
public async void Start()
{ }
}
In any of the three threads that are running, I need to be able to read and write to List<Object> MyDevices.
The threads all have different functions, but they all interact with "MyDevices", so if one thread makes a change to that list, the other threads need to know about the change right away.
What is the best way to go about doing this?
Thanks!
These threads need to be able to read/write to global variables in the main thread
The easiest way to deal with this requirement is to remove it. Is it possible to code the solution so that each thread owns a device? Or is it possible to rethink the thread's responsibilities so that they communicate by message passing instead of updating shared data? Usually these alternative approaches result in much cleaner and less buggy code. But not always.
You will need locks to protect shared data. The easiest way to do this is with the lock statement, e.g.:
object _mutex = new object();
List<Object> MyDevices = null;
...
var device = ...;
lock (_mutex)
{
MyDevices.Add(device);
}
Generally, you want to minimize the code in the lock statement. Also, you may want to have one lock for the List<Object> and a separate lock for each item in the list, depending on how your thread use those devices.
One thing you might want to consider using is an ObservableCollection. This class implements the INotifyPropertyChanged interface, which notifies any listeners of changes to the underlying collection.
Next, you'll want to implement an event handler for PropertyChanged in your Thread classes like so (I recommend making either an interface or base class that handles this since you appear to be using different classes for each Thread):
public sealed class MyThreadBase
{
private ObservableCollection<object> MyDevices;
public MyThreadBase(ObservableCollection<object> deviceList)
{
MyDevices = deviceList;
MyDevices.PropertyChanged += MyDevices_PropertyChanged; // Register listener
}
private void MyDevices_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
lock (MyDevices)
{
// Do something with the data...
}
}
}
The lock statement is used so that the thread is blocked when another thread is reading or writing to MyDevices. This is typically important in synchronization and is known as the readers-writers problem. I'd suggest reading up on that and possible solutions as well.
If you intend, however, for each thread to iterate over the devices and do something with each one, then you will run into issues, as iterating over a changing collection is not a good idea (and when using a foreach loop, will actually throw an exception), so keep that in mind too.
other threads need to know about the change right away
If you want low latency notifications, threads must spend the majority of time sleeping on something. E.g. executing Dispatcher.Run() that will sleep waiting for messages/tasks to process.
If that’s your case, you can use ObservableCollection instead of List, and write CollectionChanged handler that forwards notifications for your 3 threads. Or if that’s what you want, forward notifications to 2 other threads, excluding the current one, if you won’t want the thread that initiated the change to process changed event.
I'm not sure if the Dispatcher class is available on Windows IoT platform. Definitely not the case for .NET core. Even if not, high-level building blocks to create one are available. Here’s an example implementation that also implements synchronization context, very simple because relies on high-level ConcurrentQueue and BlockingCollection generic classes.
using kvp = KeyValuePair<SendOrPostCallback, object>;
enum eShutdownReason : byte
{
Completed,
Failed,
Unexpected,
}
class Dispatcher : IDisposable
{
const int maxQueueLength = 100;
readonly ConcurrentQueue<kvp> m_queue;
readonly BlockingCollection<kvp> m_block;
public Dispatcher()
{
m_queue = new ConcurrentQueue<kvp>();
m_block = new BlockingCollection<kvp>( m_queue, maxQueueLength );
createdThreadId = Thread.CurrentThread.ManagedThreadId;
prevContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext( new SyncContext( this ) );
}
readonly SynchronizationContext prevContext;
readonly int createdThreadId;
class SyncContext : SynchronizationContext
{
readonly Dispatcher dispatcher;
public SyncContext( Dispatcher dispatcher )
{
this.dispatcher = dispatcher;
}
// https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps/
public override void Post( SendOrPostCallback cb, object state )
{
dispatcher.Post( cb, state );
}
}
/// <summary>Run the dispatcher. Must be called on the same thread that constructed the object.</summary>
public eShutdownReason Run()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
while( true )
{
kvp h;
try
{
h = m_block.Take();
}
catch( Exception ex )
{
ex.logError( "Dispatcher crashed" );
return eShutdownReason.Unexpected;
}
if( null == h.Key )
return (eShutdownReason)h.Value;
try
{
h.Key( h.Value );
}
catch( Exception ex )
{
ex.logError( "Exception in Dispatcher.Run" );
}
}
}
/// <summary>Signal dispatcher to shut down. Can be called from any thread.</summary>
public void Stop( eShutdownReason why )
{
Logger.Info( "Shutting down, because {0}", why );
Post( null, why );
}
/// <summary>Post a callback to the queue. Can be called from any thread.</summary>
public void Post( SendOrPostCallback cb, object state = null )
{
if( !m_block.TryAdd( new kvp( cb, state ) ) )
throw new ApplicationException( "Unable to post a callback to the dispatcher: the dispatcher queue is full" );
}
void IDisposable.Dispose()
{
Debug.Assert( Thread.CurrentThread.ManagedThreadId == createdThreadId );
SynchronizationContext.SetSynchronizationContext( prevContext );
}
}
Regardless on whether you’ll use built-in Dispatcher or my custom one, all threads must call it’s Run method, then use asynchronous posted tasks, or async methods, to run code within the dispatcher.

Creating a class with thread safe functions using InvokeRequired property and Invoke method

I have a class that I created and in the class I do some multi-threading. Usually to do my multi-threading on a form I would use the following method...
//Thread Safe Functions
delegate void Thread_Safe_SendMessage_Progress_Callback(string sProgress);
private void Thread_Safe_SendMessage_Progress(string sProgress)
{
if (this.InvokeRequired)
{
Thread_Safe_SendMessage_Progress_Callback d =
new Thread_Safe_SendMessage_Progress_Callback(Thread_Safe_SendMessage_Progress);
try
{
this.Invoke(d, new object[] { sProgress });
}
catch
{
//ObjectDisposedException
}
}
else
{
//Fire up the thread event
SendMessageThread_Progress(sProgress);
}
}
Now that works perfect! At this point I try to bring the multi-threading into a class i made. When I do that everything seems to be great with the exception of the InvokeRequired property and the Invoke method do not exist within my class. So using this.InvokeRequired throws an error... To give my class that property I do this... (Note that m_iThreadID is set in the constructor and when the thread is created to start with)
private bool InvokeRequired
{
get
{
//Get the current thread id
int iThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
//Compare and return results
return (iThreadID != m_iThreadID);
}
}
Now the only thing left is the Invoke method... How do I get that to work?
Invoke method isn't so "easy" to replicate (side question: why don't you use BeginInvoke? I guess you may don't need to raise the event synchronously). You can get the first form in Application.OpenForms (copy before use!) and inspect that to check for InvokeRequired and BeginInvoke/Invoke.

keeping the thread safe UI accessors in a separate class in c#

In my multi threaded apps i need to do cross thread access on UI elements and i am using the thread safe methods to do that. I am repeatedly using this a lot in many of my projects and keeping them in the form file itself is making the file look ugly. So i want to create a seprate class where i can put all this and call them whenever needed but i am having trouble with it. For instace for changing the text element of a control i am using the following
delegate void SetTextCallback(string text, Control ctrl);
public void SetText(string text, Control ctrl)
{
if (ctrl.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text, ctrl });
}
else
{
if (ctrl.GetType() == typeof(Label))
{
ctrl.Text = text;
}
else
{
ctrl.Text += Environment.NewLine + text;
}
}
}
and call this function as
SetText("some text",label1);
This works fine if it is in the form class, if i put it into another class i am getting an error in the line
this.Invoke(d, new object[] { text, ctrl });
Can some one tell me how can i do this properly.
Also is it possible to have one UI accessor method do all the stuff, that is right now i am having multiple methods like this one to change the text one to change the enabled property one to change the back color and one to change the fore color. Is it possible to do it with something like
public void ChangePropert(Control ctrl,Property prop,Value val)
The problem with all this is you are starting to leak UI code outside of the form where the controls actually reside. A thread should not have to know about controls, it should do work and update the main thread and let the main thread worry about what needs to be done in the UI.
The way to accomplish this is have a callback that a second thread can call, but force that callback to actually be executed on the main thread instead of executed on the second thread. You can accomplish this by using the Synchronization context.
You need to wrap your secondary threads in a class that can keep a reference to the main thread synchronization context. Then the secondary threads can use this for call backs.
Example:
public partial class Form1 : Form
{
private SynchronizationContext _synchronizationContext;
public Form1()
{
InitializeComponent();
//Client must be careful to create sync context somehwere they are sure to be on main thread
_synchronizationContext = AsyncOperationManager.SynchronizationContext;
}
//Callback method implementation - must be of this form
public void ReceiveThreadData(object threadData)
{
// This callback now exeutes on the main thread.
// Can use directly in UI without error
this.listBoxMain.Items.Add((string)threadData);
}
private void DoSomeThreadWork()
{
// Thread needs callback and sync context so it must be wrapped in a class.
SendOrPostCallback callback = new SendOrPostCallback(ReceiveThreadData);
SomeThreadTask task = new SomeThreadTask(_synchronizationContext, callback);
Thread thread = new Thread(task.ExecuteThreadTask);
thread.Start();
}
private void button1_Click(object sender, EventArgs e)
{
DoSomeThreadWork();
}
}
And your thread class will look something like this:
/// SomeThreadTask defines the work a thread needs to do and also provides any data ///required along with callback pointers etc.
/// Populate a new SomeThreadTask instance with a synch context and callnbackl along with ///any data the thread needs
/// then start the thread to execute the task.
/// </summary>
public class SomeThreadTask
{
private string _taskId;
private SendOrPostCallback _completedCallback;
private SynchronizationContext _synchronizationContext;
/// <summary>
/// Get instance of a delegate used to notify the main thread when done.
/// </summary>
internal SendOrPostCallback CompletedCallback
{
get { return _completedCallback; }
}
/// <summary>
/// Get SynchronizationContext for main thread.
/// </summary>
internal SynchronizationContext SynchronizationContext
{
get { return _synchronizationContext; }
}
/// <summary>
/// Thread entry point function.
/// </summary>
public void ExecuteThreadTask()
{
//Just sleep instead of doing any real work
Thread.Sleep(5000);
string message = "This is some spoof data from thread work.";
// Execute callback on synch context to tell main thread this task is done.
SynchronizationContext.Post(CompletedCallback, (object)message);
}
public SomeThreadTask(SynchronizationContext synchronizationContext, SendOrPostCallback callback)
{
_synchronizationContext = synchronizationContext;
_completedCallback = callback;
}
}
Now you can just get rid of all the invoke crap on every control.
You could separate this stuff out as Extension methods. That would allow you to call methods in the object itself instead of passing it in as a parameter like you do now.
So you could do: label1.SetText("some text"); instad of SetText("some text", label1);
An additional gain would be that you could have separate implementations for each control type, so you could have one for label and one for the text box. This would make the code somewhat cleaner.
Finally, regarding your question about using reflection to set the properties. You can get a reference to the property using the Type.GetProperty() method. This returns a PropertyInfo object that you can use to set the property value like this:
var textProperty = label1.GetType().GetProperty("Text");
textProperty.SetValue(label1, "some text", null);
It is just while you debugging your project, right?
anyway, if you had another option not to create a separate class to manipulate this, you can set this CheckForIllegalCrossThreadCalls property to false on each form that calls threads other than its own thread.
CheckForIllegalCrossThreadCalls - MSDN

Deriving from SynchonizationContext

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!

Categories