In Windows phone 8 app, instead of always opening the application with same PhoneApplicationPage, I need to switch the initial view. i.e. Home page if settings already exists and settings page if the user opens the app for the first time.
How should I go about it?
Currently the way I adopted is :
Made Default task empty in WMAppManifest.xml
<DefaultTask Name="_default" />
Decided which page to move to in Application_Launching event handler.
private void Application_Launching(object sender, LaunchingEventArgs e)
{
if (SettingFileExists())
RootFrame.Navigate(new Uri("Home.xaml", UriKind.Relative));
else
RootFrame.Navigate(new Uri("Settings.xaml", UriKind.Relative));
}
Is this the best way to approach this scenario? Is there any potential issue with my code?
There a re lots of different ways of doing this and no one "best" way.
My personal preference is to use a custom UriMapper that does the redirect on start up.
E.g.
Set the Navigation startup Uri to something special that doesn't exist. e.g. "StartUp"
Set a custom UriMapper:
RootFrame.UriMapper = new MyUriMapper();
Then in the UriMapper check for the special uri and take appropriate action:
public class MyUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
if (uri.OriginalString == "/StartUp")
{
if (!this.dataOperations.IsLoggedIn())
{
return Login.Path;
}
else
{
return Main.Path;
}
}
return uri;
}
}
Related
I'm having trouble trying to navigate automatically between pages in my Windows 8.1 app based on a little check. It just doesn't want to navigate to another page when doing this in LoadState, as if something isn't loaded yet, but it doesn't give an error either. When I insert a delay using (for example) await Task.Delay(2000) before doing Frame.Navigate, then my app will redirect without any problem.
protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
MyData oData = await getData();
if (oData != null)
{
this.Frame.Navigate(typeof(newPage), oData);
}
else
{
// do something else
}
}
Do I have to put this code in another load- or navigated-event? Or how can I make this work?
In LoadState and SaveState you should only save and restore the page state (called when suspending and reactivating the app). Do nothing else (like navigating).
Put your logic into the OnNavigatedTo method instead...
If you want to navigate from method that called when page is loads, you should place your navigation code to OnNavigatedTo(...). But do not forget to wrap your code in Dispatcher.RunAsync(...) - Frame navigation in xaml return false
I tried calling Frame.Navigate(...) from the OnNavigatedTo method but still the navigation didn't occur.
There are other answers which say use Dispatcher.RunAsync, but that feels like it's making assumptions about the threading model of Windows Phone.
Here's what I do: attach a handler to the Loaded event of the page instead, and put my "redirect" logic in there. Loaded fires after OnNavigateTo and after NavigationHelper_LoadState, but before the page has become visible.
public LaunchPadPage() {
this.InitializeComponent();
this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
this.navigationHelper.SaveState += this.NavigationHelper_SaveState;
this.Loaded += LaunchPadPage_Loaded;
this.app = (App)App.Current;
}
private void NavigationHelper_LoadState(object sender, LoadStateEventArgs e) {
// Let's show the root zone items
// NB: In case we don't have this data yet, do nothing
if (app.Hierarchy != null)
{
DefaultViewModel["Items"] = app.Hierarchy.RootItems;
}
}
private void LaunchPadPage_Loaded(object sender, RoutedEventArgs e) {
// No data? Go to the downloads page instead.
if (app.Hierarchy == null)
{
Frame.Navigate(typeof(DownloadingPage));
}
}
I got stuck trying to implementing file picker for windows phone app. I need to choose files from gallery using FileOpenPicker. I didn't get how it works. Here is my code:
private readonly FileOpenPicker photoPicker = new FileOpenPicker();
// This is a constructor
public MainPage()
{
// < ... >
photoPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
photoPicker.FileTypeFilter.Add(".jpg");
}
// I have button on the UI. On click, app shows picker where I can choose a file
private void bChoosePhoto_OnClick(object sender, RoutedEventArgs e)
{
photoPicker.PickMultipleFilesAndContinue();
}
So, what to do next? I guess I need to get a file object or something.
I found this link. It is msdn explanation where custom class ContinuationManager is implemented. This solution looks weird and ugly. I am not sure if it is the best one. Please help!
PickAndContinue is the only method that would work on Windows Phone 8.1. It's not so weird and ugly, here goes a simple example without ContinuationManager:
Let's assume that you want to pick a .jpg file, you use FileOpenPicker:
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".jpg");
picker.ContinuationData.Add("keyParameter", "Parameter"); // some data which you can pass
picker.PickSingleFileAndContinue();
Once you run PickSingleFileAndContinue();, your app is deactivated. When you finish picking a file, then OnActivated event is fired, where you can read the file(s) you have picked:
protected async override void OnActivated(IActivatedEventArgs args)
{
var continuationEventArgs = args as IContinuationActivatedEventArgs;
if (continuationEventArgs != null)
{
switch (continuationEventArgs.Kind)
{
case ActivationKind.PickFileContinuation:
FileOpenPickerContinuationEventArgs arguments = continuationEventArgs as FileOpenPickerContinuationEventArgs;
string passedData = (string)arguments.ContinuationData["keyParameter"];
StorageFile file = arguments.Files.FirstOrDefault(); // your picked file
// do what you want
break;
// rest of the code - other continuation, window activation etc.
Note that when you run file picker, your app is deactivated and in some rare situations it can be terminated by OS (little resources for example).
The ContinuationManager is only a helper that should help to make some things easier. Of course, you can implement your own behaviour for simpler cases.
I am creating a project network dashboard in which I am creating hub tiles of network setting.
When I pin to start tile from my app. and whenever from home screen I click to tile it should navigate to different pages.
When you add secondary tile to your home screen you need to provide an URI, put some parameters in it:
ShellTile.Create(new Uri("/EntryPage.xaml?param=wifi", UriKind.Relative), NewTileData);
Create an empty entry page (EntryPage.xaml) and in OnNavigatedTo method read parameters from uri and redirect to OS settings page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode != NavigationMode.New)
{
throw new Exception("exit");
}
string parameter;
if (this.NavigationContext.QueryString.ContainsKey("param"))
{
parameter = this.NavigationContext.QueryString["param"];
GoToOSSettigsPage(parameter);
}
}
Sorry for the lame question title, it's hard to describe the problem in one sentence. The problem is as follows:
I need to make sure user has accepted license agreement before he can start using the app. My idea is to use UriMapper, which will check if user has accepted agreement before, and if not, redirect him or her to the license agreement page.
public override Uri MapUri(Uri uri)
{
if(!settingsStorage.IsLicenseAgreementAccepted)
return LicenseAgreementPage;
return uri;
}
However, on the license agreement page, if I override OnNavigatedTo, I see that the navigation URI is not current page's URI, but rather the non-mapped URI, e.g. address of my main page. Therefore, when I try to navigate to that main page, nothing happens, since navigation service think I'm already there.
public partial class LicenseAgreementPage : PhoneApplicationPage
{
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e); // somehow e.Uri equals to /MainPage.xaml, instead of /LicenseAgreementPage.xaml
}
}
So how to overcome this? Is the UriMapper not applicable here? Or is there some workaround?
Thanks.
I had a similar problem where some pages required the user to log on. If the user tried to go to a page requiring login, they were redirected to a login page and then sent back. Maybe you can use the same strategy?
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (Requirelogin && !CurrentAppManager.IsUserLoggedIn)
{
// Transfer URI to the login page and save it, after successful login,
// the login page navigate back to the stored URI
((PhoneApplicationFrame)Application.Current.RootVisual).Navigate(new Uri("Login?" + Helpers.URI + "=" + e.Uri.ToString(), UriKind.Relative));
}
// if the user has just come from Login
// remove it from the stack so they dont hit when pressing back
var entry = NavigationService.BackStack.FirstOrDefault();
if (entry != null && entry.Source.OriginalString.Contains("Login"))
{
NavigationService.RemoveBackEntry();
}
}
I'm using the NavigationContext.QueryString for my Windows Phone 8 app. For example, I set an URI identifier like ItemId in the navigation string and in the OnNavigatedTo, I parse the Id and read the Item via linq.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
try
{
int itemId = int.Parse(NavigationContext.QueryString["itemId"]);
_item = App.MainViewModel.GetItem(itemId);
DataContext = _item;
}
catch (KeyNotFoundException ex)
{
Debug.WriteLine(ex.Message);
throw;
}
}
I've found an interesting alternative and want to hear your opinion:
// in the calling page
PhoneApplicationService.Current.State["Item"] = App.MainViewModel.GetItem(123);
// in the destination page
Item item = PhoneApplicationService.Current.State["Item"] as Item;
Is this really a recommended way?
From MSDN:
The PhoneApplicationService class provides access to various aspects
of the application’s lifetime. This includes management of the
application’s idle behavior and management of the application’s state
when it becomes active or inactive. You can use it like that but the
data has to be serializable.
This link has other ways to share data, but I don't think state is the recommended way of doing it. It's more for tombstoning purpose.