Xamarin Forms - ACR UserDialog smooth transition - xamarin.forms

I have an app with two pages. One of them is the MainPage, which is opened first when the app is opened. The second page is there to update values (user input), sent them to a server and returning to the MainPage (all in one click under one button).
For loading the new values on the MainPage, I'm using an ACR UserDialog and here comes the problem.
The ACR UserDialog must be created at two location:
One in the OnAppearing of the MainPage, so that when the app is opened a nice dialog is shown while loading the data.
One in the second page because of the values being sent to the server.
Both work, but when I press the button to upload the values to the server, the first dialog pops up loading and then the app returns to the MainPage while quickly switching from the first dialog to the second dialog from the OnAppearing. I would like this transition to be smooth: both texts are different and I want to keep the loading going while only updating the text (so that the loading dialog does not switch quickly).
Is this possible?
EDIT: code snippits
I have created a demo, but I cannot send files here.
MainPage:
protected async override void OnAppearing()
{
base.OnAppearing();
UserDialogs.Instance.ShowLoading("Getting Information");
await Task.Delay(2000);
// Do stuff
UserDialogs.Instance.HideLoading();
}
SecondPage:
private async void Button_Clicked(object sender, EventArgs e)
{
UserDialogs.Instance.ShowLoading("Saving Information");
await Task.Delay(2000);
// Do stuff
await Navigation.PopAsync();
}
GIF of the situation:

Related

How to navigate to page when on resume is called in app.xaml.cs for mvvm in xamarin forms app

I have an issue with navigation. When I click home screen button of device and get back to app I get app homescreen instead of pin page. Ideally it should show pin page and its working fine with back button of device.
OnStart() method has navigationasync but the same is not working with OnResume() method.
Do I have to go to each of the Platform project cs file and add the navigation there like for Android OnRestart()/OnResume() method?
If anyone knows the solution please let me know
Most commonly when writing your Xamarin Application with Prism you will have something like:
protected override void OnInitialized()
{
NavigationService.NavigateAsync("SomePage");
}
OnInitialized is called each time the App's ctor is invoked. This is an important consideration here because this means that any time that the native platform tombstones the app in the background or otherwise refreshes the app by calling OnCreate in your MainActivity or FinishedLaunching in your AppDelegate, then OnInitialized will be invoked resetting your App's Navigation stack to SomePage.
You can however override the OnStart/OnResume in PrismApplication and use whatever business logic you need to determine where to navigate and how you might want to restore your application.
public override void OnStart()
{
NavigationService.NavigateAsync("MainPage");
}
public override void OnResume()
{
if(someCondition)
{
NavigationService.NavigateAsync("SomePage");
}
else
{
NavigationService.NavigateAsync("AnotherPage");
}
}

Why ActivityIndicator changes state after entire method is completed?

I would like to show ActivityIndicator object after user tap the login button on page. Unfortunately there is small problem to do that because it seems like ActivityIndicator change state after entire method is completed. This is code I wrote so far:
private void Login(object sender, EventArgs ev)
{
BusyIndicator.IsVisible = true; //<- here I want to show indicator
try
{
//some input validation, connection opening etc
ConnectionHandler.OpenConnection(ServerIP, "dmg", false);
}
catch (Exception e)
{
Logging.Error(e.Message, "Connection", e);
}
}
When I set breakpoint after BusyIndicator.IsVisible = true; there is absolutely no change in app. However I noticed that when method is completed then indicator is shown. Is this a correct behavior of this control?
Why I need this? Because field validation and connecting with server takes some time and I need to show to user that something happens in background. Login function takes ~1 sec so indicator show and hide quickly I can't even see any change.
How can I show indicator immediately after user tap a button?
Your problem is that Login() method is being executed in the UI thread. So, despite setting BusyIndicator.IsVisible = true;, the thread continues tio execute the method to get data, so the UI does not respond.
Solution, run the OpenConnection in a different thread:
private async void Login(object sender, EventArgs ev)
{
BusyIndicator.IsVisible = true; //<- here I want to show indicator
try
{
//some input validation, connection opening etc
await Task.Run(() => { ConnectionHandler.OpenConnection(ServerIP, "dmg", false);});
}
catch (Exception e)
{
Logging.Error(e.Message, "Connection", e);
}
}

Xamarin.Forms (iOS) MessagingCenter message from AppDelegate is not delivered

I have next goal: my app receives push notifications (FCM) and I need to handle user manipulations with them in all possible scenarios.
When I receive foreground push and handle it in WillPresentNotification - everything works as expected.
When I sent app to the background mode (clicking home button) and receive a push, click on that push at Notification Center I have next code in DidReceiveNotificationResponse method:
MessagingCenter.Send<object, PushNotificationObject>(this, "PushNavigationToRootPage", push);
So it just sends a message to the RootPage, which is subscribed/unsubscribed as below:
protected override void OnAppearing()
{
base.OnAppearing();
MessagingCenter.Unsubscribe<object, PushNotificationObject>(this, "PushNavigationToRootPage");
MessagingCenter.Subscribe<object, PushNotificationObject>(this, "PushNavigationToRootPage", (sender, _push) => { ... });
}
protected override void OnDisappearing()
{
MessagingCenter.Unsubscribe<object, PushNotificationObject>(this, "PushNavigationToRootPage");
base.OnDisappearing();
}
enter code here
It also works! BUT!
If I completely close the app (swipe it off from App Switcher) and then click on the received push - it will only Send a message (from the code above), but will never reach code which is placed inside Subscribe of a RootPage.
Any ideas of what is wrong?
Thanks in advance!

Why DisplayAlert does not work in constructor?

I have some problems in my Xamarin.Forms app related to invoking async method in the page constructor so when I test something trying to figure out the reason I just realized DisplayAlert method does not even work in the page constructor so I am wondering why is that happening?
Here is my code:
public MainPage ()
{
InitializeComponent ();
DisplayAlert("An alert", "Why I don't show up?", "Ok");
}
and I also tried to call async method that has DisplayAlert method but didn't work too, here is the code:
public MainPage ()
{
InitializeComponent ();
Async_Function_Has_DisplayAlert();
}
async void Async_Function_Has_DisplayAlert()
{
// I tried both and neither of them worked
await DisplayAlert("An alert", "Why I don't show up?", "Ok");
await Task.Run(()=> DisplayAlert("An alert", "Why I don't show up?", "Ok"));
}
So can someone explain why that is happening please?
Normally, you should not call an awaitable method like DisplayAlert() from the constructor.
What you can do is have a method that returns void (still not best practice) and call that method from your constructor.
Tweaking my recommendation after trying it out.
I used Device.Timer to delay the alert.
I think some components have not finished loading (in this case, the DisplayAlert) before trying to call it.
public MainPage()
{
InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(4), () =>
{
ShowMessage();
return false; // True = Repeat again, False = Stop the timer
});
}
public async void ShowMessage()
{
await DisplayAlert("Alert", "I show here", "OK");
}
There seems to be a misconception on what is happening in the constructor.
The constructor simply creates a new Page class.
CustomMainPage mainpage = new CustomMainPage();
(App.Current as App).MainPage = new NavigationPage(mainpage);
So before we add the mainpage class to the NavigationPage, all that has happened is that the CustomMainPage class was initialized and is ready to be inserted into an appropriate container.
However after creating the new page, there is no actual UI on the screen, yet. For instance, the mainpage object wouldn't have width or height set, no layout has been done, etc...
If you run a UI related task, such as presenting an Alert, there isn't simply any foundation for it there, which could do anything resonable.
Of course you could already set members of the mainpage, such as labels or buttons to certain values, colors, styles or whatever you want, from within the constructor, but these wouldn't do anything at that point of time.
All of those values will be taken into account when the page is being layouted and presented but none of that will happen in the constructor.
However, back to your problem: You seemingly want to inform the user that something has gone wrong during the initialization.
I see two ways of adressing that issue:
Check the preconditions on the page or within the code before initializing your view and present the Alert from the page or class, which is initializing your page.
create a private variable in your page class, which you will set from within your page constructor if something goes wrong. This could be a simple bool flag, a string containing an error message, an enum or whatever suits your needs. Then override the OnAppearing() method, check that flag you set earlier and call DisplayAlert depending on the flag's value.
If you want any interactivity on your page, then you should consider Jason's comment to your question and implement it within OnAppearing, because this method will be called once your page has been fully layouted and is being presented on your screen.
Sample code for Jason's recommendation
public async void ShowMessage()
{
await DisplayAlert("Alert", "I show here", "OK");
}
protected override void OnAppearing()
{
ShowMessage();
}

FreshMvvm - Closing the child page of a page in FreshTabbedNavigationContainer

I have set up a FreshTabbedNavigationContainer with 5 pages.
Within the 5th tabbed page which is a SettingsPage where there is a way to display and AboutPage that is displayed via the SettingsPageModel like this
public Command AboutCommand
{
get
{
return new Command(() =>
{
CoreMethods.PushPageModel<AboutPageModel>();
});
}
}
When the user navigates away by selecting another tab, this other tab is displayed correctly.
If the user selects the SettingsPage via the tab, then the child AboutPage is automatically displayed.
I want to remove AboutPage from the navigation stack when another tab page is selected.
I have tried this in the AboutPage.xaml.cs
protected override void OnDisappearing()
{
base.OnDisappearing();
((AboutPageModel)BindingContext).CoreMethods.RemoveFromNavigation();
}
This works BUT if the back button is pressed on the app when in the AboutPage then it has already been removed from the navigation stack, and the app crashes.
How can I check if a PageModel is still in the navigation stack?
I have managed to resolve the problem :)
In the App.xaml.cs file in the App constructor where I create the FreshTabbedNavigationContainer, after setting the MainPage
MainPage = tabbedNavigation;
I then add the following code
tabbedNavigation.CurrentPageChanged += (sender, e) => {
tabbedNavigation.PopToRoot();
};
It works perfectly.

Resources