You can see that the magic happens thanks to the ViewModelLoader property bound to the ViewModel's SillyPeopleLoader.
The task loader is in fact a ContentView processing all the states of your asynchrounous initialization code wraped in a "loader". You know, the one you put shamelessly in an a async void IntializeAsync method ? uh ? remember? Right. Stop that, this is silly. But we'll go into details later.

Styling

Now the style applied to this loader that can be applied to all my TaskLoaderView through my app:

So we have some styling stuff like the custom font FontFamily, TextColor, AccentColor you want to use. We also have the images you want to display when you are in Error or Empty state, but we'll discuss it later.

TaskLoaderView states

So your async initialization code state could be either equal to:

Loading (async code is running)

Success (async code ran succesfully)

Empty (returned null or a empty collection)

Error (the async code threw an exception)

Refreshing (last async code execution was succesfull)

Wait but how does it work ??

Remark: Well if you don't want to know how it works, but just use it, just goto: Man, just tell me how to use the thing

The idea is simply to wrap our initialization code in an object responsible for its asynchronous loading.

Introducing the ViewModelLoader

Now for the loading part, the issue has been tackled years ago by Stephen Cleary. You should use a NotifyTask object to wrap your async initialization. It garantees that the exception is correctly caught, and it will notify you (it implements INotifyPropertyChanged).