Xamarin Forms – Set ViewModel Property during Click for Push Notification in iOS – Not working prope

JimTyminskiJimTyminski USUniversity ✭✭

Xamarin Forms – Set ViewModel Property during Click for Push Notification in iOS – Not working properly Using MessagingCenter

Implemented Push Notification in my Xamarin Forms iOS app. Push works great, I receive the notification when the user taps the Push Notification popup.
So, I wanted to implement a long(ish) running process when the user clicks the notification. Therefore, I wanted to show the Activity Indicator when the app is activated, run my long process, then hide the Activity Indicator.

I use a property called IsBusy in my ViewModel (using MVVM, FreshMVVM specifically) and bind the Activity Indicator IsVisible to the IsBusy property for the page that is being displayed when the user clicks the Push Notification. BTW – the app only has one page. This all works when I test the app from OUTSIDE the Push Notification lifecycle. If I put a button on my page, then set IsBusy when the button is clicked, the binding works perfectly and the Activity Indicator is displayed.

However, since I do not have access to the ViewModel from within the DidReceiveRemoteNotification/ ReceivedRemoteNotification functions, I decided to use the MessagingCenter. I send a message that I subscribe to in the ViewModel and the code on the receiving end sets the IsBusy = true;.

Seems simple enough and seems like it should just work. But it does not. The Subscribed To function DOES get called, the IsBusy property is set, but the binding to IsVisible never happens (seemingly) and the Activity Indicator never displays.

So, my question is, Why? Here is my code:

In AppDelegate.cs:

public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
    // ReceivedRemoteNotification is used when the app is backgrounded

    // Send the message to the subscribed MessagingCenter event, it sends a 
    // string to change the Activity Indicator message, and the message identifier
    Xamarin.Forms.MessagingCenter.Send("Retrieving Data...", "DisplayBusyIndicator");

    // Process the push notification click.  I left this code out for brevity, but it simply
    // calls a function that runs for about 5-7 seconds.  
    // This is where I want the Activity Indicator displayed.
    { ... }

    // Send the message to Hide the Activity Indicator
    Xamarin.Forms.MessagingCenter.Send<string>("string.Empty", "HideBusyIndicator");
}

In MainPageModel.cs:

public bool IsBusy { get; set; }
public string LoadingMessage { get; set; } = "Loading...";

protected override void OnPageAppearing(Page page)
{
    base.OnPageAppearing(page);

    Debug.WriteLine("OnPageAppearing!");
    MessagingCenter.Subscribe<string>(this, "DisplayBusyIndicator", (args) => { LoadingMessage = args; page.IsBusy = true; Debug.WriteLine("DisplayBusyIndicator!"); });
    MessagingCenter.Subscribe<string>(this, "HideBusyIndicator", (args) => { IsBusy = false; Debug.WriteLine("HideBusyIndicator!"); });
}
protected override void OnPageDisappearing(Xamarin.Forms.Page page)
{
    base.OnPageDisappearing(page);

    MessagingCenter.Unsubscribe<string>(this, "DisplayBusyIndicator");
    MessagingCenter.Unsubscribe<string>(this, "HideBusyIndicator");
}

In BusyIndicator.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:xxxxxxxx.Controls;assembly= xxxxxxxx"
             IsVisible="{Binding IsBusy}"
             AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" BackgroundColor="#20FFFFFF" 
             x:Class="xxxxxxxx.Controls.BusyIndicator">

  <AbsoluteLayout>
    <Grid AbsoluteLayout.LayoutFlags="PositionProportional"
        AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
      <Grid.RowDefinitions>
        <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <StackLayout IsVisible="{Binding IsBusy}"
                   VerticalOptions="Center"
                   HorizontalOptions="Center"
                   Padding="32"
                   BackgroundColor="#90000000">
        <ActivityIndicator IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}" Color="White"/>
        <Label Text="{Binding LoadingMessage}" HorizontalOptions="Center" TextColor="White"/>
      </StackLayout>
    </Grid>
  </AbsoluteLayout>
</ContentView>

Posts

  • Sahadev_GuptaSahadev_Gupta INMember ✭✭✭
    edited June 2017

    @JimTyminski Instead of using MessagingCenter you can directly navigate to any page you want.
    Just create the static method in Portable project's App.Xaml.Cs. N inside that method you can redirect to any page you want. So you can set IsBusy Property while navigating to the page

  • JimTyminskiJimTyminski USUniversity ✭✭

    Thanks, but I tried that. Check this out:

            public async static Task SetIsBusy(bool isBusy)
            {
                var page = FreshPageModelResolver.ResolvePageModel<MainPageModel>();
                MainPageModel context = page.BindingContext as MainPageModel;
                context.IsBusy = isBusy;
            }
    

    So, I call this function to set the bound property IsBusy on my MainPage. The context is correct, and the IsBusy property gets set, BUT the Activity Indicator does not display. Very weird.

    This function gets called from within the ReceivedRemoteNotification method in AppDelegate.cs. I set some Debug.Write statements to check out the life cycle, and the OnResume does not get fired until AFTER this function is complete. Does that make sense? Could this be the issue?

Sign In or Register to comment.