2

I have a WPF application that is updating its data model within a timer which updates its data at 1 Hz. As I understand it, a Timer works on a separate thread from the GUI. Everything seems to work great, but I'm reading around and see conflicting reports on whether it's ok to update data on a thread different from the GUI thread. We are running with .NET framework 4 Client Profile. The below article says things are fixed in 4.5 but it still isn't clear to me that it is. Can someone clarify this for me? We aren't using collections in our binding as of yet. Is that why we're not having trouble.

WPF Databinding thread safety?

Community
  • 1
  • 1
bsh152s
  • 3,178
  • 6
  • 51
  • 77

2 Answers2

2

yeah. It is thread safe. INotifyPropertyChanged is always marshalized to UI thread from other threads.

There is no need to dispatch PropertyChanged from another thread to UI thread, as the PropertyChanged event is automatically marshalled to the UI dispatcher.

As a MSDN article says:

Note that in WPF, things are different and the code shown in Figure 5 works even if the Status property is data-bound to a TextBlock. This is because WPF automatically dispatches the PropertyChanged event to the main thread, unlike all the other XAML frameworks. In all other frameworks, a dispatching solution is needed.

However, it is only true for change notifications on scalar properties (i.e. PropertyChanged event). Collection change notifications (INotifyCollectionChanged.CollectionChanged event) don't work that way, they must be raised on the UI thread manually. That is, when using INotifyCollectionChanged (such as with an ObservableCollection), these changes are not marshaled to the UI thread. This means that if you modify collection from non UI thread, you’ll take an exception. For example, there is some ViewModel We’re in the ViewModel class and we don’t use the Dispatcher to update UI. So I advise to you to use David Rickard's approach:

public static class DispatchService
{
    public static void Invoke(Action action)
    {
        Dispatcher dispatchObject = Application.Current.Dispatcher;
        if (dispatchObject == null || dispatchObject.CheckAccess())
    {
            action();
        }
        else
        {
            dispatchObject.Invoke(action);
        }
    }
}

and:

DispatchService.Invoke(() =>
{
    this.MyCollection.Add("new value");
});

David Rickard article at msdn blog.

Update:

yeah, the article uses MVVMLight framework. However, it is not correct that MVVM Light uses Dispatcher to marshal scalar property to UI thread. It can be seen from source code of ViewModelBase class from MVVM Light that there is no marshal between threads to update scalar property. Please, see RaisePropertuChanged() method.

In order to dispel any doubts on dispatching scalar properties I've made a test:

XAML:

<TextBlock Text="{Binding Number}" FontSize="188" Foreground="Red" />

ViewModel:

public int Number { get; set; }

private void UpdateNumber()
{
        Task.Run(() => 
        {
            System.Timers.Timer timer = new System.Timers.Timer(250);
            timer.Elapsed += (sender, eventArgs) =>
            { 
                Number++;
                OnPropertyChanged("Number");//No exceptions, no errors
            };
            timer.Enabled = true;
        });
}

Update 1:

There is no doubt that INotifyProperyChanged event is automatically dispatched by WPF to UI Thread. I believe a MSDN article and the link you've shown in your question:).

Pay attention to this: This is because WPF automatically dispatches the PropertyChanged event to the main thread, unlike all the other XAML frameworks.

Community
  • 1
  • 1
StepUp
  • 36,391
  • 15
  • 88
  • 148
  • Note that the article is using the MVVM Light frameworks which switches to the UI thread. So this answer is not correct for all WPF application – Emond Apr 12 '16 at 16:34
  • 1
    Very interesting. Thank you. – 15ee8f99-57ff-4f92-890c-b56153 Apr 12 '16 at 16:37
  • @ErnodeWeerd, can you clarify what doesn't work for WPF. We are not using the MVVM Light framework. – bsh152s Apr 12 '16 at 16:45
  • @bsh152s - The code that is being referred to uses the MVVM Light framework `Set(StatusPropertyName, ref _status, value);` Also I have never seen any code that proves that WPF automatically switches to the UI thread when you raise the NotifyPropertyChanged event. I would be very happy to be corrected on this but the article is not proof of this. – Emond Apr 12 '16 at 17:25
  • @StepUp - Ya, it seems to work. Our UI updates correctly when the data is updated within our Timer event (on another thread). It just still bothers me with all these articles/comments out there saying that it is not safe to do. I'm still waiting on a clear answer as to why all those people are right/wrong. Is there something that we may not be doing that could break it? – bsh152s Apr 13 '16 at 19:42
  • 1
    There seems to be so much misinformation out there regarding this. I believe the key here is that "INotifyProperyChanged event is automatically dispatched by WPF to UI Thread". So, the framework does the hard stuff for you. – bsh152s Apr 15 '16 at 14:12
  • I cannot remember a name of the book of programming, but I remember this words "it is better to test one time, than you've been heard 100 times about that". And I believe msdn:). – StepUp Apr 15 '16 at 14:28
1

No, it is not thread safe. A common way to fix that is by switching to the UI thread in the raiser of the notify property changed event.

Updating the view or viewmodel 1000 times per second is, in general, useless because the display is only updated 60 times per second or so and the average user is not able to read a thousand values per second in text.

The same code that raises the notification event could throttle the number of times the event gets raised per second.

Emond
  • 50,210
  • 11
  • 84
  • 115