I am writing an Xamarin Forms application using MVVM Cross. I'm using the Master-Detail presentation model.
I'm attempting to wire up my application to support tombstoning. To do so, I configured my android device so that Don't Keep Activities = true. This has the correct desired affect in that when I switch to another application, my application activities are destroyed and when I switch back my application reloads.
However, the methods SaveStateToBundle are never called and subsequently, ReloadFromBundle is never called. So, I'm stuck on finding a way for my application to restore itself in the tombstoning workflow.
Has anyone had any success doing this? Complicating matters is that I not only want to remember the state of my detail page, but i also need to remember which detail page was actually loaded. But at this point I haven't found any way to save my state in the first place.
thanks to all who can help!
Michael
Related
This is related to my other question.
I used the OnStructureChanged event to detect that the 'Help' window popped up in the 3rd party application that my application is writing data to. I need my application to pause while the end user resolves the data issue in the 3rd party application, then I need my application to resume once the end user closes the 'Help' window. (Either I need to detect that the 'Help' window was closed or I need to display a message box and use the DialogResult to trigger my application to resume).
I've never encountered something like this before. I don't know if it's possible to do what I want to do. If it is possible, I don't know where to start.
Advice?
UPDATES:
I have only used Threading once before and I think it was a fairly "easy peasy" usage, I pulled it off without much effort, considering I'd never used Threading before. I'm playing around with Threading for this issue right now. There's a good chance I've implemented it incorrectly, but my app isn't functioning correctly anymore...I don't know if I'm even playing with the correct tool.
I had to just keep moving with the project - deadlines, you know...
I ended up using UI Automation to detect the "Help" window, then I showed a message box giving instructions to the end user. I check the MessageBox's DialogResult and continue processing based on that. It might not be the "best" way to skin the cat, but I'm a noob and I have a deadline, so I did what I needed to do to keep moving.
First of all, I'm not sure if I am even going about this the best way in terms of design, but I'm a little new to Android and very new to Xamarin.Forms. My setup is a series of ContentPages in a Xamarin.Forms PCL that all deal with information from a REST service. This service, upon logging in, grants a WorkToken that the application then holds onto in order to perform further operations. I'm storing this in an ISessionManager.
My problem is a workflow issue. I have a LoginPage that I want to present to the user if their session has ended/faulted/whatever; basically if they aren't logged in and try to do anything, I want to push this page on the stack and force them to attempt to log in and if they provide valid credentials let them continue where they left off. All this is taking place, for the most part, in the PCL, but I've created an Android implementation of the ISessionManager that is queried on each ContentPage's overridden OnAppearing method. Each page calls ISessionManager's CheckLogin which will do just that, and if they aren't logged in, it will create an Intent and start the LoginActivity through that. LoginActivity essentially just wraps around the PCL's LoginPage.
The problem I am running into is that, doing it this way, the LoginActivity is run asynchronously on top of whatever page called it. This calling page is in a broken state, however, because it has not initialized properly through the REST service yet. I imagine there are two possible solutions. Either run the Intent synchronously (which I don't think is possible) or rethink my design. Here's the Intent setup:
var intent = new Intent(_context, typeof(LoginActivity));
intent.AddFlags(ActivityFlags.NewTask);
_context.StartActivity(intent);
I've checked several Xamarin forums for related posts on this, but have not found much beyond basic navigation workflows in Xamarin.Forms.
Edit: I've found something analogous to what I'm trying to do here: How to pass variables from a new intent back to the class that created it in android, but within the context of Xamarin.Forms. The startActivityForResult would solve my problem if it existed in Forms.Context, but there doesn't appear to be an equivalent.
Why are you creating a LoginActivity? is it because you need to use something native from android?
My first thought it's that after you check for the token status on the OnAppearing, you that can decide to push or not the modal for the login page, after the user login is done and the token is save, you can pop the modal and it will show the previous page the user was.
Is there a specific function which is called when someone navigates from the home screen to my app again?
In my application i'm requesting data from a server and i don't want it to be requested everytime someone navigates to my app. The request should come at a maximum of once in an hour. Would a timer keep running when i go from the app to the start screen, or would it stop or keep it's state at maybe 58 minutes?
I'm using c# Windows Phone 8.
If you wish to make a request once an hour maximum, you could simply save the result with a DateTime to evaluate if the request can be made again or not, regardless of the navigation state, but if you really need to know, you can go to the App.xaml code-behind. There, you will find some methods that are useful.
The Application_Launching method is called only when the app starts for the first time. It will not be executed after that. Otherwise, if someone left your application and comes back later, the Application_Activated method will be called.
I also suggest you consult this diagram displaying a Windows Phone app lifetime. The page describes the diagram and gives additional insights.
I know about tombstoning stuff any how to save the states of your application but my question is this regarding states.
Let's say I have a page that have 5 buttons. Whenever I click a button the button can be either visible or hidden. How do I save the current state or the saved state of my page? Let's say if I exit my application and loaded the 5 buttons again one button should be hidden.
I tried saving a variable state value in an IsolatedStorageFile and retrieve it when the Page is loaded in loaded event but I figured out that it's too tedious for the processor to do a lot of things just for saving a state.
Another solution I thought of is when the Loaded event is fired, I will statically declare an if else statements and manually declare the Visibility of the button.
Is there any other way?
Are you trying to do the same thing when the page/app is exited normally and when it's tombstoned? The default expected behaviour is that when launching the app after exiting (via the back button) the app will be in it's default state. When returning from a tombstoned state the app should (as far as is appropriate) be displayed to the user in exactly the same way as when the page/app was tombstoned.
Of course you may have differing needs but I wanted highlight the standard behaviour.
If you want to store state while tombstoned, the convention is to use the OnNavigatedFrom and OnNavigatedTo events to store details in the State object.
There is a good example of how to do this on MSDN: How to: Preserve and Restore Page State for Windows Phone
If you want to preserve state across all executions of your app then you will need to use IsolatedStorage to store the details in a persistent location. Where and when you read and write the data will depend on where the data you need to persist is located.
If it's at an applicaiton level you may be able to use the application level events (Launching, Activated, Closing & Deactivated). If you have state data at page level it's probably be better to do it in the page level (Loaded/Unloaded or NavigatedFrom/To as appropriate).
If you want to store state across all executions of the application you probably need to look at both of the above options.
The System.IO.IsolatedStorage namespace is fine for this kind of behaviour, check it out here
Also check out this article on how to do what you are asking.
Saving Applications States
First of all, we are in C#, WPF, desktop application (can be .NET 3.5).
I need to show login window when application starts, if login succeeds, hide login window and show main app window. In addition, when the main window is closed, one should see login window again. If login window is closed, application quits.
Bonus to make it harder: when "Remember user" option checked, login window is skipped and user is logged in automatically, showing the main window instatly. (please do not think about how the option is stored, assume you just know it and have the value in variable).
What is meant to be the application startpoint (means which window is considered to be in app.xaml StartupUri property)?
How would you solve architecture? Is the best way to use App_Startup event and show some window from that point?
What type of App.ShutdownMode would you use? And how would that work? You can use "OneLastWindowClose", "OnMainWindowClose" or "OnExplicitShutdown". What is your choice and why?
In general, I am interested in "what calls what, what is application 'root', what invokes closing the application".
I already have a solution for my problem that works, but I am interested, if any of you have met this problem and how have you solved it? I will gladly share my approach, but I don't want to limit your ideas in the first place.
Thank you for your contribution.
P.S.: I am using MVVM framework, that makes it just a little more messy, but the point stays. I also use Ninject as IoC, but this issue still of course stays on. I did not mention these information to make the question as clear as possible. I also have to handle exceptions (communication with server or db during the login may fail), and to make it really interesting, I must show interactive 'splashwindow' indicating what application does (loading, communication with server, autologin). But please stay away from these requirements at the moment, we can discuss them later.
I'm going to repeat your questions as I understand them, you can correct me where I am missing something. Also, I'm rather new to the whole M-V-VM thing, so take my advice with a grain of salt. The best way I know how to learn is to throw out my ideas and have them corrected.
You want to know things
1) Where should the logic exist to decide where to show the login or main window
2) Which shutdown mode to use
3) What is application root
1)
I believe the decision to show a login or auto login is business logic, thus should live in the Model of your M-V-VM framework. Once that logic is implemented, the view can display whichever window is required by querying the Model.
I assume your application has an App.xaml and App.cs file which runs when the application is executed. You can override OnStartup within App.cs and display whichever window is necessary, based on the results of the business logic (which are learned from using some object in your Model).
2)
For shutdown model, I'd probably go with OnLastWindowClose, but I have no idea how many windows your application is using. I assume only the two you mentioned (login and main).
3)
What is application root? I would argue that your Model is really the application root, in that it holds all of the important stuff (view is user interface to the model, view model is state for the view). So, when it comes to what is the root or essence of your application, I would argue it is some set of objects in your model.
What calls what? That will all depend on what you're trying to accomplish. In general, I avoid having the view model know anything about the view. Both view and view model can be aware of the model. In certain cases, you'll want to make use of Ninject as a service manager in order to inject a view into the view model (without forcing the view model to depend on the view).
An entirely different approach would be to avoid a log in window altogether and display a login method in the main window. You'll still need some Model object to tell you when to show the login prompt, but you won't have to worry about juggling windows. Honestly, I'd probably go that route. WPF provides us with a lot of interesting and sexy ways to accomplish that task.
The Application object is the root of any WPF project. You are correct that you can handle the App_Startup event - depending on what you need to do at startup, of course.
Depending on whether you need a more complex navigation framework or the application will be forever limited to the scenario you described, you can go a multitude of ways from there.
What I'm doing in the applications I work on is I create a Navigator object that handles navigation both between different windows and inside windows, then I simply call Navigator.Navigate(new MyViewModel(), NavMode.ReplaceWindow); which closes the previous 'main' window (if any is open) and displays a new one, setting the contents to the instance of my ViewModel. The ViewModel is then displayed using the correct templates. I can also use NavMode.ReplaceUserControl which replaces the contents of the current 'main' window, or NavMode.OpenModalWindow which displays a modal dialog. My ShutdownMode is set to OnLastWindowClose, since I can always call App.Shutdown() if I want to close regardless of the open windows.
Of course, when you replace windows you need to make sure to instantiate (not show, just instantiate) the new window before closing the old one, to avoid application shutdown because you have no more windows.
You could do something similar, but it's just an idea and it's tailored specifically for my requirements.