Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could creating an event be a valid way to make a XF OnAppearing into an async method?

I recently saw this suggestion on how to make an app OnStart into an async OnStart:

    protected override void OnStart()
    {
        this.started += onStarted;      //Subscribe to event
        started(this, EventArgs.Empty); //Raise event
    }

    protected async void onStarted(object sender, EventArgs args)
    {
        try
        {
            await // do things
        }
        catch (Exception ex)
        {
            var ignore = ex;
        }
        this.started -= onStarted;
    }

Can anyone see any possible issues with this and if not then could something similar be applied to the OnAppearing and if so would there be any changes needed.

like image 551
Alan2 Avatar asked Mar 01 '20 05:03

Alan2


1 Answers

OnAppearing is simply a void method on Page class

Xamarin.Forms.Page

//...

protected virtual void OnAppearing()
{
}

//...

Source

that is called as part of the Page's life cycle.

//...

[EditorBrowsable(EditorBrowsableState.Never)]
public void SendAppearing()
{
    if (_hasAppeared)
        return;

    _hasAppeared = true;

    if (IsBusy)
    {
        if (IsPlatformEnabled)
            MessagingCenter.Send(this, BusySetSignalName, true);
        else
            _pendingActions.Add(() => MessagingCenter.Send(this, BusySetSignalName, true));
    }

    OnAppearing(); //<---
    Appearing?.Invoke(this, EventArgs.Empty); //NOTE HOW ACTUAL EVENT IS RAISED AFTER

    var pageContainer = this as IPageContainer<Page>;
    pageContainer?.CurrentPage?.SendAppearing();

    FindApplication(this)?.OnPageAppearing(this);
}

//...

Source

They are not to be mistaken for event handlers, that are the one exception allowed to use async void.

Reference Async/Await - Best Practices in Asynchronous Programming

The approach shown in your OnStart example can also be applied to OnAppearing

For example

public partial class SomePage : ContentPage {
    public SomelPage() {
        InitializeComponent();
        appearing += onAppearing;
    }

    protected override void OnAppearing() {
        appearing(this, EventArgs.Empty);
        appearing -= onAppearing;
    }

    event EventHandler appearing = delegate { };

    private async void onAppearing(object sender, EventArgs args) {
        try {
            var locator = CrossGeolocator.Current;
            var position = await locator.GetPositionAsync();

            var places = await SomeService.getPlacesOfInterest(position.Latitude, position.Longitude);
            placesListView.ItemsSource = places;
        } catch( Exception ex) {
            //handler error (Log?)
        }
    }
}

Or you could subscribe to the actual Appearing event directly

//...

public event EventHandler Appearing;

//...

Source

and forgo overriding the OnAppearing() method

public partial class SomePage : ContentPage {
    public SomelPage() {
        InitializeComponent();
        Appearing += onAppearing;
    }

    private async void onAppearing(object sender, EventArgs args) {
        try {
            var locator = CrossGeolocator.Current;
            var position = await locator.GetPositionAsync();

            var places = await SomeService.getPlacesOfInterest(position.Latitude, position.Longitude);
            placesListView.ItemsSource = places;
        } catch( Exception ex) {
            //handler error (Log?)
        }
    }
}
like image 78
Nkosi Avatar answered Oct 17 '22 09:10

Nkosi