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:
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"); }
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"); }
<?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
@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
Thanks, but I tried that. Check this out:
So, I call this function to set the bound property
IsBusy
on myMainPage
. The context is correct, and theIsBusy
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 someDebug.Write
statements to check out the life cycle, and theOnResume
does not get fired until AFTER this function is complete. Does that make sense? Could this be the issue?