Confirmation on master detail page before exiting - xamarin.forms

I want to ask for confirmation before exiting page but i tried every way i can find but nothing worked so far.
I have a master detail page as Application Main page.
App.Current.MainPage = new NavigationPage(new FaceApp.MainPageActive());
In that page Detail page is set like following.
Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(RecoveryForm)));
In Recovery form page i have following code
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
if (await DisplayAlert("Alert", "Are you sure you want to go back ?", "Yes", "No"))
{
// Nothing works here. i tried many things including following
await Navigation.PopAsync();
}
});
return true;
}
Code runs successfully but nothing happens, if i remove code of running in Main thread application gets halted.

Related

Xamarin Forms AppShell How return to previous page

I see a lot of threads on this sort of subject but none seem to apply to my question. I don't have a navigation page, I have a hamburger menu -- so Push/PopAsync() would not appear to be the answer. And I don't want to go to a specific page, I want to go back to the previous page (whatever it was) so GoToAsync() would not appear to be the answer.
Xamarin app for Android and UWP with iOS somewhere in the future. The description of the problem below is specific to Android; it works a little differently on UWP.
I want to put a Help entry in the hamburger menu that will take the user to a help page in the default browser. Hamburger menu seems to only go to an app page, so I defined a "dummy" View page that displays "Loading ..." and issues Browser.OpenAsync() in its OnAppearing() method, and that pretty much works. The problem is that the user would expect that the Back button would take him or her to the page they were on before clicking Help. I tried a couple of things. I have gotten close with the following but it does not quite work correctly:
In each of my other Views' OnAppearing() I call a method that saves the value of Current.MainPage.CurrentItem in a static. Then in the Help page after the OpenAsync() I set Current.MainPage.CurrentItem to its setting from the last page before the Help page.
Console.WriteLine("#### HelpPage loading Web Help");
_ = State.DisplayHelpPage(this, "MainHelp"); // _ = await Browser.OpenAsync(uri, blo);
Console.WriteLine("#### HelpPage returning to previous page");
State.ReloadPreviousPage(); // Current.MainPage).CurrentItem = lastFlyoutItem;
It almost works. The first time I click Help in the hamburger menu I get
#### HelpPage loading Web Help
#### HelpPage returning to previous page
#### HelpPage loading Web Help
#### HelpPage returning to previous page
The Web page loads perfectly. But when I click the Back button it displays again. Obviously my OnAppearing() method has been driven twice, which I do not understand.
If I click the Back button again I come back to the previous page in the application just as I wanted. The next time I click Help in the Hamburger menu it takes me to my dummy View page with no Web page. Obviously, my OnAppearing() is not being driven at all. But after that it works perfectly. I can go to any app page, and click Help in the menu. I get the Web page, and the Back button takes me back to the app and the page. In UWP of course the browser does not load on top of the app Views, and I seem to see it being loaded twice every time.
So ... what should I be doing differently? And why is my OnAppearing() being driven twice and then not at all ... and thereafter as I would expect?
There are several parts to this answer:
Get the previous page on to the Navigation stack. This is done by intercepting the Route "//HelpPage", and replacing it with a route that ISN'T a child of Shell.
Remember "FakePageVisible", so we know to do "PopAsync" in OnResume, when app returns from browser.
(Optional) "Entering" flag prevents going to browser twice.
App.xaml.cs:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new AppShell();
}
protected override void OnResume()
{
if (HelpPage.FakePageVisible) {
HelpPage.FakePageVisible = false;
var shell = MainPage as AppShell;
if (shell != null) {
shell.Navigation.PopAsync();
}
}
}
}
AppShell.xaml.cs:
public partial class AppShell : Xamarin.Forms.Shell
{
public AppShell()
{
InitializeComponent();
// Define a route that isn't a child of Shell.
Routing.RegisterRoute("Help2", typeof(HelpPage));
}
protected override void OnNavigating(ShellNavigatingEventArgs args)
{
base.OnNavigating(args);
if (args.Current != null) {
if (args.Source == ShellNavigationSource.ShellItemChanged) {
if (args.Target.Location.OriginalString == "//HelpPage") {
// Cancel the original route.
args.Cancel();
Device.BeginInvokeOnMainThread(() => {
// Used by the next OnAppearing.
HelpPage.Entering = true;
// Go there by a route that isn't a child of Shell.
// Doing so, pushes our previous location on to Navigation stack.
Shell.Current.GoToAsync("Help2");
});
}
}
}
}
}
HelpPage.xaml.cs:
public partial class HelpPage : ContentPage
{
public static bool Entering;
public static bool FakePageVisible;
protected override void OnAppearing
{
// Make sure this only happens once (just in case).
if (Entering) {
Entering = false;
FakePageVisible = true;
Xamarin.Essentials.Browser.OpenAsync("https://aka.ms/xamarin-quickstart");
}
}
}
For a simple demo, this code communicates via static variables in HelpPage. Re-factor as appropriate for your situation.

How do I stop blazor #onclick re-rendering page

I am using a blazor sever app
I have a control that when clicked using the #onclick event handler I want to navigate to a new page using the NavigationManager in the click event method.
it doesn't really matter what the control is (button, a, tr, etc) they all have the same behavior
if I put a break point in the HTML I can see the current page is re-rendering before it goes to the new page.
a simple way to reproduce this behavior is to make a new blazor project and in the counter.razor page
change the code to this
#page "/counter"
<h1>Counter</h1>
#if (1 == 1)
{
<p>Current count: #currentCount</p>
}
<button class="btn btn-primary" #onclick="IncrementCount">Click me</button>
#code {
private void IncrementCount()
{
//currentCount++;
}
}
put a break point on the HTML line "#if (1 == 1)"
when the button is clicked it calls the click event which does nothing (code commented out), it then re-renders the page and the break point is hit.
The same happens if I add code in the click event calling navigationManager to navigate away from the page, it re-renders before it leaves the page when nothing has changed on the page.
adding onclick:preventDefault and/or #onclick:stopPropagation does not change this
the only thing I have found that does work is adding
private bool c_blnStopRendering = false;
protected override bool ShouldRender()
{
if (c_blnStopRendering == true) { return false; }
return base.ShouldRender();
}
and setting the c_blnStopRendering = true; in the click event
but this seems like over kill and very manual to add it everywhere it is needed
That's the only way to do it at the moment. There is a request in the backlog https://github.com/dotnet/aspnetcore/issues/18919
I was wondering how you got on with this. I had exactly the same problem (I just wanted to NavigateTo without any re-rendering). Overriding ShouldRender to return false, stopped everything - i.e. it didn't NavigateTo the URL. I was however, Navigating to the same page, but with different parameters in the QS. I seem to have solved the problem, (I think !) when I discovered an optional parameter in the NavigateTo method (public void NavigateTo(string uri, bool forceLoad = false);). I set that to true and it seems to be OK now. Was just interested in your experience

Closing Modal Page in Xamarin.Forms

I am opening new ContentPage like this:
MediaPage galleryPage = new MediaPage();
await Application.Current.MainPage.Navigation.PushModalAsync(galleryPage);
Now, when done with the task in that page, I would like to close it and come back to last page where I was before opening ModalPage.
I tried like this:
await Application.Current.MainPage.Navigation.PopModalAsync();
But nothing happens.
Are you sure you are executing it from the main thread? Try this:
Device.BeginInvokeOnMainThread(() =>
{
Application.Current.MainPage.Navigation.PopModalAsync();
});

Xamarin Pillar navigation

What is the correct way to handle model navigation?
The first case below works as expected but I can then go back to the login page which I don't want. The second case I can see in the debugger that that page is loaded but never shown. Basically the model page stays on top. I am thinking I need to either close the model page before changing pages or I need to handle this differently. I don't won't to pop to root because the root is no longer home but main.
What I really won't to do is change the root, how?
[Edit] This seems to help but there is still a flicker when I unload the modal page.
await _navigator.PushAsync(vm => { vm.NoHistory = true; });
Case 1:
return viewFactory.Resolve<HomeVM>(); - from APP.cs
await _navigator.PushAsync<LoginVM>();
await _navigator.PushAsync<MainVM>();
Case 2:
return viewFactory.Resolve<HomeVM>(); - from APP.cs
await _navigator.PushModalAsync<LoginVM>();
await _navigator.PushAsync<MainVM>(); - Never works.
One way is to reset MainPage completely with the new page when login in successfully.
if (string.IsNullOrEmpty(authLoginToken))
MainPage = new LoginPage();
else
MainPage = new RootPage();
More detailed info, you can take a look the following thread:
https://github.com/asthanarht/CPXamarin/blob/master/CPMobile/CPMobile/App.cs
https://forums.xamarin.com/discussion/48634/from-login-page-to-main-page

How to avoid duplicate entry from asp.net on Postback?

I have a dropdown list that pulls data from template table. I have an Add button to insert new template. Add button will brings up jQuery popup to insert new values. There will be a save button to save the new data. On_Save_Click I enter the new data and close the popup.
Here is the proplem:
When I refresh the page, the page entering the values again. So, I get duplicate entries!
Question:
How can I avoid this issue? I check out Satckoverflow and Google, both they suggest to redirect to another page. I don't want to redirect the user to another page. How can I use the same form to avoid this issue? Please help.
You can use viewstate or session to indicate if data already inserted (button pressed).
Something like this:
private void OnbuttonAdd_click()
{
if(ViewState["DataInserted"] != "1")
{
...
// Add new entry...
...
if(data inserted successfully)
{
ViewState["DataInserted"] = "1";
}
}
}
Edit:
public bool DataInserted
{
get
{
if (HttpContext.Current.Session["DataInserted"] == null)
{
HttpContext.Current.Session["DataInserted"] = false;
}
bool? dataInserted = HttpContext.Current.Session["DataInserted"] as bool?;
return dataInserted.Value;
}
set
{
HttpContext.Current.Session["DataInserted"] = value;
}
}
...
private void OnbuttonAdd_click()
{
if(!DataInserted)
{
...
// Add new entry...
...
if(data inserted successfully)
{
DataInserted = true;
}
}
}
The simplest way is to use a post/redirect/get pattern.
Basically, the refresh action for page build with post requires to repost the data. Using this pattern, you will reload the whole page.
With ASP.Net, you have a simple alternative, use an UpdatePanel. This will refresh only part of the page using AJAX. As the page itself is still the result of a GET request, you can refresh the page. And as you use ASP.Net, it's quite easy to integrate.
Finally, you can use a home made AJAX refresh. A combination of jQuery, KnockOut and rest services (for example), can help you to avoid refreshing the full page in benefits of an ajax call.
There is some experience:
Disable Submit button on click (in client side by JavaScript).
change Session['issaved'] = true on save operation at server side and change it on new action to false.
use view state for pass parameters like RecordId (instead of QueryString) to clear on refresh page. i always pass parameter's with Session to new page, then at page load set
ViewState['aaa']=Session['aaa'] and clear Sessions.
...I hope be useful...
Do this it is very easy and effective
Intead of giving IsPostBack in the page load(),please provide inside the button click (To send or insert data)
Call the same page again after reseting all input values
protected void Btn_Reg_Click1(object sender, EventArgs e)
{
try
{
if (IsPostBack)
{
Registration_Save();
Send_Mail();
txtEmail.Text = "";
txtname.Text = "";
Response.Redirect("~/index.aspx");
}
}
catch (Exception) { }
}
You won't see any server messages after refreshing the page..

Resources