How to be thread-safe using INotifyPropertyChanged with no SynchronizationContext?
c#, inotifypropertychanged, multithreading
Solution
So... turns out there's actually a very nice way if you don't mind relying on an extension generating some code for you at compile time. I was using Fody/PropertyChanged anyway, making this a very easy change. This avoids having to a reference to a `SynchronizationContext` in models that really have no business knowing about the UI.
First, install PropertyChanged.Fody, available from NuGet.
Every class that currently implements `INofityPropertyChanged` should instead have the attribute `[ImplementPropertyChanged]`. The manual implementation should be removed. See the readme and wiki for more information.
A PropertyChangedNotificationInterceptor needs to be implemented. They provide an example for WPF in the wiki; my implementation for a WinForms project:
public static class PropertyChangedNotificationInterceptor
{
public static SynchronizationContext UIContext { get; set; }
public static void Intercept(object target, Action onPropertyChangedAction, string propertyName)
{
if (UIContext != null)
{
UIContext.Post(_ =>
{
onPropertyChangedAction();
}, null);
}
else
{
onPropertyChangedAction();
}
}
}
Set `PropertyChangedNotificationInterceptor.UIContext` somewhere. You can put `PropertyChangedNotificationInterceptor.UIContext = WindowsFormsSynchronizationContext.Current;` in the constructor of your main form.
The `Form` constructor goes through the Control constructor and will eventually end up creating the `WindowsFormsSynchronizationContext` if one does not already exist. Therefore, it is safe to capture the `.Current` here. (Note: this might be an implementation detail, and could change in future .NET versions, different platforms, etc.)
Keep in mind that this only works if you only have a single sync context (a single UI thread). If you ever get into the mess of multiple UI threads, and require data-binding on more than one, this would get far more complicated. So please don't do that.
Thanks to Simon Cropp for writing `PropertyChanged` and also helping me find this particular feature of it.
Problem
How do you keep your objects thread-safe that implement INotifyPropertyChanged? I can't use a SynchronizationContext because I need to be able to serialize the object. ``` protected void OnPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) // What can I add here to make it thread-safe? handler(this, new PropertyChangedEventArgs(propertyName)); } ```