Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does setting a ViewModel property have thread affinity in Xamarin Forms?

The other day, in a code review, I saw some questions about the safety of setting a property from a worker thread. A coworker made the comment, "This property is bound to the UI, and data binding is thread-safe."

I've been using XF for a while, but always assumed this wasn't true: that if I wanted to update ViewModel properties bound to the UI I'd have to make those changes on the UI thread. I just spent a few minutes poking around the documentation, and I don't see an obvious answer other than that directly manipulating BindableProperties has thread affinity. It also matters to me if that's a blocking UI thread execution or not.

I could make a project to test it out myself, but these kind of issues always seem to be intermittent so I'd like to know I'm just missing the right documentation.

(It's relevant to investigating a crash we're seeing that happen within mainly Xamarin call stacks. We raise an event from a worker thread, a VM handles that event and updates some properties. If that's being scheduled for the UI thread, there could be some interleaving issues we didn't prepare for and I'm that much closer to addressing the crash. If it's not being scheduled for the UI thread... I'm surprised it's worked this long.)

like image 840
OwenP Avatar asked Oct 03 '16 19:10

OwenP


People also ask

What is thread in Xamarin forms?

Xamarin - Working with threads. Mobile devices are optimised to run complex tasks on multiple threads. Running any form of complex task on the UI thread (the main thread) will cause the UI of your application to hang (or at least seem to anyway) until the operation is complete.

What is MVVM in Xamarin forms?

The MVVM pattern enforces a separation between three software layers — the XAML user interface, called the View; the underlying data, called the Model; and an intermediary between the View and the Model, called the ViewModel.

How does binding work in Xamarin forms?

Data binding is the technique of linking properties of two objects so that changes in one property are automatically reflected in the other property. Data binding is an integral part of the Model-View-ViewModel (MVVM) application architecture.


2 Answers

I've been using XF for a while, but always assumed this wasn't true: that if I wanted to update ViewModel properties bound to the UI I'd have to make those changes on the UI thread.

You're right. 100% right. You can use Device.InvokeOnMainThread() for this.

To be complete, there is one case where it doesn't matter: PropertyChanged

https://github.com/xamarin/Xamarin.Forms/blob/b645064/Xamarin.Forms.Core/BindingExpression.cs#L542

In that case, the Binding is applied on the main (UI) thread.

like image 115
Stephane Delcroix Avatar answered Nov 04 '22 13:11

Stephane Delcroix


Assumptions

We interact with the UI exclusively via binding. So only setters and getters are playing.

Getters

The code referred to in github by @Stephane, only means, that your bound getter(s) will be called in the UI thread. No more no less.

Btw, I would not rely on the source code (I mean: implementation), instead the specification what matters. Implementation can change anytime, and if the specification does not requires this, then unit tests will not check this, so there will be a big surprise...

Setters

However it is still not clear, if can you call your setter(s) in a background thread. Regardless the answer is yes or no, it implies further tasks to solve.

a) If you can call setters in any thread: This means, that your viewmodel internal data is exposed to race conditions, because will be called from the UI thread, and you will access them in a background thread. Conclusion: You must guard the data with the usual concurrency patterns, or use thread safe classes, plus: your getter and setter must be atomic.

b) If it turns out you can not call setters in any thread: Then you must use Device.InvokeOnMainThread(). But this is only the half of the story. In methods of your background thread, you are modifying say a List instance. This will be accessed in the UI thread by the getter, and you are modifying it in a background thread concurrently when you say populate it. Theoretically it is possible the user interacts with the UI during the population period, what let the binding evaluated, getter is called.

Conclusions:

If there are multiple threads accessing to the very same data, you must always lock you data.

Regardless what the current source code implies the safest way to marshall the getter and setter to the UI thread. This will not cause significant overhead: If the executions is already in the UI thread, marshall will do nothing.

Note: Even you marshall both you getters and setter to the UI thread, you will access the data in background threads so guard against race conditions or using thread safe classes are essential.

like image 40
g.pickardou Avatar answered Nov 04 '22 14:11

g.pickardou