1

I've solved some problem with a slow UI update, and I want to hear an explanation why my code modification actually improved the performance.

I develop a WPF application, MVVM Architecture. I have a property in the view model:

public DateTime MyDate
    {
        get
        {
            return _myDate;
        }
        set
        {
            _myDate= value;
            OnPropertyChanged()
            OnPropertyChanged(() => MyDateFormatted);
        }
    }

and the MyDateFormatted looks as follows:

public string MyDateFormatted
    {
        get { return _myDate.ToString("MMMM dd, yyyy"); }
    }

The setter of MyDate does NOT happen on the UI Thread. The getter of MyDateFormatted happens on the UI Thread, because, as I've read, WPF automatically marshals property changes to the UI thread.

Making sure OnPropertyChanged() is called on UI thread in MVVM WPF app

And indeed, the UI was updated, but very slowly. Once, I've manually attached the OnPropertyChanged(() => MyDateFormatted); to the UI Dispacher, by surrounding it with the invoke: Application.Current.Dispatcher, the UI updates now as quickly as I wanted, and the performance has improved dramatically. Can you please explain why? Thank you!

Cod Fish
  • 917
  • 1
  • 8
  • 37
  • And how often do you update that property so that it causes perfomance problems? – Evk Apr 23 '18 at 09:20
  • @Evk Very very very often. Something like every millisecond – Cod Fish Apr 23 '18 at 09:28
  • With both implementations you posted, it's clear that you don't need to call the method `OnPropertyChanged` twice. The both calls do the same - the first one uses the .NET 4.5+ feature for obtaining the property name, the second one a (definitely slower) feature using Expressions. Call it only once, I would prefer the first one. – dymanoid Apr 23 '18 at 09:36

1 Answers1

2

One possible reason is that Dispatcher.Invoke throttles (slows down) your algorithm which updates MyDate, and that allows UI thread to keep up with those updates. Suppose you have the following code:

new Thread(() => {
    while (true) {
        this.MyDate = DateTime.UtcNow;
    }
})
{ 
   IsBackground = true 
}.Start();

This is an extreme case where value is updated constantly without any delay. What happens is when OnPropertyChanged on MyDate is invoked, WPF will queue binding update on UI thread via Dispatcher.BeginInvoke (note Begin).

In that extreme case, it will flood UI thread queue very fast and UI thread will not be able to keep up with the number of pending actions to process. That's because Dispatcher.BeginInvoke does not slow down that while (true) thread, since it's asynchronous.

Now suppose you wrapped this.MyDate = DateTime.UtcNow in Dispatcher.Invoke instead. Invoke is synchronous and will not return until UI thread will actually perform this operation. Now loop is throttled and runs much slower, because updating UI is now part of the loop and UI actions queue does not grow without bound.

In real life scenario it worth throttling UI updates yourself. So if you have a tight loop - don't update UI bound properties on every iteration but instead update on every X (100, 1000) iteration, to not put much burden on UI thread (too fast updates are useless anyway, since person eye cannot catch your 1ms updates anyway). Your "fix" might be ok if you are fine with the fact it slows down your algorithm without much reason (for performing UI updates).

Evk
  • 98,527
  • 8
  • 141
  • 191