I am attempting to test the Lens application feature, in which my app is supposed to navigate directly to CameraCaptureTask after a user selects the app from the LensPicker (since I do not have a viewfinder on my MainPage). Upon returning to MainPage, the CamerCaptureTask has a completed event which will display the image on the screen.
I am having an issue with a weird recurring situation where my CameraCaptureTask is repeatedly called based on the result of a QueryString value that I cannot clear before the application is tombstoned and then restarted after CameraCaptureTask completes.
LensExampleUriMapper.cs
private string tempUri;
public override Uri MapUri(Uri uri)
{
tempUri = uri.ToString();
// Look for a URI from the lens picker.
if (tempUri.Contains("ViewfinderLaunch"))
{
// Launch as a lens, launch viewfinder screen.
return new Uri("/MainPage.xaml?fromLensPicker=" + "fromLensPicker", UriKind.Relative);
}
// Otherwise perform normal launch.
return uri;
}
MainPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string fromLensPicker = null;
if (NavigationContext.QueryString.TryGetValue("fromLensPicker", out fromLensPicker))
{
if (fromLensPicker == "fromLensPicker")
{
newButton_Click(null, null); //click event that calls CameraCaptureTask
fromLensPicker = null; //Temporarily nullifies value until MainPage is OnNavigatedTo after CameraCaptureTask completes
}
}
}
How might I clear the QueryString value so my application does not continuously call newButton_Click(null, null) after CameraCaptureTask completes and the app is continued?
In OnNavigatedTo of MainPage use NavigationMode to find if you are returning from CameraCaptureTask
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if(e.NavigationMode == NavigationMode.Back)
return;
// else continue further with CameraCaptureTask
}
or
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if(e.NavigationMode == NavigationMode.New)
// continue further with CameraCaptureTask
}
string fromLensPicker = null;
if (NavigationContext.QueryString.TryGetValue("fromLensPicker", out fromLensPicker))
{
if (fromLensPicker == "fromLensPicker")
{
NavigationContext.QueryString.Remove("fromLensPicker");
//...
}
}
Related
I would like to open my app after another app choose my app as the target for sharing a web link.
So first I use OnShareTargetActivated to read the weblink and then use LaunchUriAsync to launch my app through a custom scheme I created for it.
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
try
{
if (shareOperation.Data.Contains(StandardDataFormats.WebLink))
{
var URL = await shareOperation.Data.GetWebLinkAsync();
var mAloudURI = #"myApp:?URL=" + URL;
// Launch the URI
await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var success = await Windows.System.Launcher.LaunchUriAsync(new Uri(mAloudURI));
});
shareOperation.ReportCompleted();
}
}
catch (Exception exc)
{
var i = 0;
}
}
After that, I use OnActivated to read the link and open my MainPage on the passed link.
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.Protocol)
{
ProtocolActivatedEventArgs eventArgs = args as ProtocolActivatedEventArgs;
var url = eventArgs.Uri.PathAndQuery.Substring("?URL=".Length);
Frame rootFrame = Window.Current.Content as Frame;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (rootFrame != null)
{
rootFrame.Navigate(typeof(MainPage), url);
}
}
}
When I'm debugging I get the expected behavior when I F10 (step through) the line calling LaunchUriAsync, then OnActivated gets executed and MainPage gets displayed with the URL I wanted...
However if I try to share again, the secondary popup window for my app gets displayed for a while and then it disappears. Non of my break points get hit...
Is this the correct approach?
This looks to me like a very logical way of opening other apps with the content you are sharing to them...
I am trying to handle the the Share Operation
Code:
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
Uri uriReceived = null;
if (shareOperation.Data.Contains(StandardDataFormats.WebLink))
uriReceived = await shareOperation.Data.GetWebLinkAsync();
shareOperation.ReportCompleted();
}
It crashes at shareOperation.ReportCompleted(); showing error message as
"There was no match for the specified key in the index."
I tried searching for this error landing me to this question, But it seemed it was a problem that went away with later builds, now I'm facing this issue how do you recommend I handle it.
According to the Report sharing status parts of Receive data,
As a result, you shouldn't call it unless your app is at a point where it can be dismissed by the user.
I guess the reason for the exception is the reporting actions require user's permissions. If you call the shareOperation.ReportCompleted(); in ShareTargetActivated directly you will skip the user's authorization. It seems like it is not allowed.
For the workaround, you can handle the code shareOperation.ReportCompleted(); in a function like Button_Click or OnGotFocus . The following code example can resolve your issue.
App.xaml.cs code:
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
rootFrame = new Frame();
rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
rootFrame.NavigationFailed += OnNavigationFailed;
Window.Current.Content = rootFrame;
}
rootFrame.Navigate(typeof(MainPage), args.ShareOperation);
Window.Current.Activate();
}
MainPage.xaml.cs code:
ShareOperation shareOperation;
protected override async void OnGotFocus(RoutedEventArgs e)
{
Uri uriReceived = null;
if (shareOperation.Data.Contains(StandardDataFormats.WebLink))
uriReceived = await shareOperation.Data.GetWebLinkAsync();
this.shareOperation.ReportCompleted();
base.OnGotFocus(e);
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
this.shareOperation = (ShareOperation)e.Parameter;
}
More details please reference the official sharetarget sample.
I have created a small sample Lens application, and I would like to be able to directly navigate to the CameraCaptureTask when the Lens icon is clicked in the default camera application. In my application I am already calling the CameraCaptureTask within a button click event during normal app operations. How might I set this up to work as well from the LensPicker option?
I have been referencing
http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj662936(v=vs.105).aspx
LensExampleUriMapper.cs
private string tempUri;
public override Uri MapUri(Uri uri)
{
tempUri = uri.ToString();
// Look for a URI from the lens picker.
if (tempUri.Contains("ViewfinderLaunch"))
{
// Launch as a lens, launch viewfinder screen.
return new Uri("/MainPage.xaml", UriKind.Relative);
}
// Otherwise perform normal launch.
return uri;
}
I was thinking of passing a QueryString value in return new Uri("/MainPage.xaml", UriKind.Relative); so that in my MainPage OnNavigatedTo event I could check that QueryString value and call the CameraCaptureTask, and then just route the result to the already existing event handler I have created (which displays the resulting image in MainPage). For some reason I am getting a debugging error when trying to create the QueryString to pass, and I am unsure of why?
EDIT** No longer getting error, but an infinite loop occurs when calling CameraCaptureTask. Why?
LensExampleUriMapper.cs
private string tempUri;
public override Uri MapUri(Uri uri)
{
tempUri = uri.ToString();
// Look for a URI from the lens picker.
if (tempUri.Contains("ViewfinderLaunch"))
{
// Launch as a lens, launch viewfinder screen.
return new Uri("/MainPage.xaml?fromLensPicker=" + "fromLensPicker", UriKind.Relative);
}
// Otherwise perform normal launch.
return uri;
}
MainPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string fromLensPicker = null;
if (NavigationContext.QueryString.TryGetValue("fromLensPicker", out fromLensPicker))
{
if (fromLensPicker == "fromLensPicker")
{
newButton_Click(null, null); //click event that calls CameraCaptureTask
fromLensPicker = null; //Temporarily nullifies value until MainPage is OnNavigatedTo after CameraCaptureTask completes
}
}
}
I believe that when CameraCaptureTask is called, the application is tombstoned and then resumed on MainPage, in which the QueryString value fromLensPicker == "fromLensPicker" and the entire cycle starts over again, repetitively. How might I solve this?
Use NavigationMode property in MainPage. I think you can't clear QueryString. But you can check how navigation to your page occured to know if its returning from CameraCaptureTask
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if(e.NavigationMode == NavigationMode.New)
// continue further
}
or
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if(e.NavigationMode == NavigationMode.Back)
return;
// else continue further
}
Instead of making fromLensPicker = null in MainPage.xaml.cs, I now have NavigationContext.QueryString.Remove("fromLensPicker") as referenced from WP7 Navigation with parameters
MainPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string fromLensPicker = null;
if (NavigationContext.QueryString.TryGetValue("fromLensPicker", out fromLensPicker))
{
if (fromLensPicker == "fromLensPicker")
{
NavigationContext.QueryString.Remove("fromLensPicker");
//Perform Action
}
}
}
I've been following the Create your first Windows Store app using C# or Visual Basic tutorials provided by Microsoft but am having some problems saving state when navigating between pages.
Create your first Windows Store app using C# or Visual Basic
Part 3: Navigation, layout, and views
Basically I've noticed that if I navigate from the main page to the photo page select a photo, navigate back to the main page and then go to the photo page again it doesn't remember the photo that was selected. I'm using the following code to navigate to the photo page from the main page.
private void photoPageButton_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(PhotoPage));
}
In the photo page the loadstate method is
protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
if (pageState != null && pageState.ContainsKey("mruToken"))
{
object value = null;
if (pageState.TryGetValue("mruToken", out value))
{
if (value != null)
{
mruToken = value.ToString();
// Open the file via the token that you stored when adding this file into the MRU list.
Windows.Storage.StorageFile file =
await Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(mruToken);
if (file != null)
{
// Open a stream for the selected file.
Windows.Storage.Streams.IRandomAccessStream fileStream =
await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
// Set the image source to a bitmap.
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmapImage =
new Windows.UI.Xaml.Media.Imaging.BitmapImage();
bitmapImage.SetSource(fileStream);
displayImage.Source = bitmapImage;
// Set the data context for the page.
this.DataContext = file;
}
}
}
}
}
The photo page save state is
protected override void SaveState(Dictionary<String, Object> pageState)
{
if (!String.IsNullOrEmpty(mruToken))
{
pageState["mruToken"] = mruToken;
}
}
I've noticed that the pagestate is always null when navigated to. Any ideas?
Enable NavigationCacheMode property of the page and add NavigationCacheMode="Enabled"
OR
Enable it by properties panel.
I did this tutorial too and I found one solution to save the state across pages navigation.
First, override the OnNavigatedFrom in order to save the file token into State Frame:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
var state = SuspensionManager.SessionStateForFrame(this.Frame);
state["mruToken"] = mruToken;
}
Override the OnNavigatedTo in order to load the token from the state:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var state = SuspensionManager.SessionStateForFrame(this.Frame);
if (state != null && state.ContainsKey("mruToken"))
{
object value = null;
if (state.TryGetValue("mruToken", out value))
{
// the same code as LoadState to retrieve the image
}
}
}
In fact, I wrote another function to retrieve the image so it can be used in both LoadState and OnNavigatedTo methods.
private async void restoreImage(object value)
{
if (value != null)
{
mruToken = value.ToString();
// Open the file via the token that you stored when adding this file into the MRU list.
Windows.Storage.StorageFile file =
await Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.GetFileAsync(mruToken);
if (file != null)
{
// Open a stream for the selected file.
Windows.Storage.Streams.IRandomAccessStream fileStream =
await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
// Set the image source to a bitmap.
Windows.UI.Xaml.Media.Imaging.BitmapImage bitmapImage =
new Windows.UI.Xaml.Media.Imaging.BitmapImage();
bitmapImage.SetSource(fileStream);
displayImage.Source = bitmapImage;
// Set the data context for the page.
this.DataContext = file;
}
}
}
The problem is coming from the NavigationHelper OnNavigateTo method
public void OnNavigatedTo(NavigationEventArgs e)
{
var frameState = SuspensionManager.SessionStateForFrame(this.Frame);
this._pageKey = "Page-" + this.Frame.BackStackDepth;
if (e.NavigationMode == NavigationMode.New)
{
// Clear existing state for forward navigation when adding a new page to the
// navigation stack
var nextPageKey = this._pageKey;
int nextPageIndex = this.Frame.BackStackDepth;
while (frameState.Remove(nextPageKey))
{
nextPageIndex++;
nextPageKey = "Page-" + nextPageIndex;
}
// Pass the navigation parameter to the new page
if (this.LoadState != null)
{
this.LoadState(this, new LoadStateEventArgs(e.Parameter, null));
}
}
else
{
// Pass the navigation parameter and preserved page state to the page, using
// the same strategy for loading suspended state and recreating pages discarded
// from cache
if (this.LoadState != null)
{
this.LoadState(this, new LoadStateEventArgs(e.Parameter, (Dictionary<String, Object>)frameState[this._pageKey]));
}
}
}
if (e.NavigationMode == NavigationMode.New) if always true because Frame by default creates a new instance of the Page. See Frame Class Remarks. So The LoadState event handler is always called with a null state parameter
if (this.LoadState != null)
{
this.LoadState(this, new LoadStateEventArgs(e.Parameter, null));
}
Now if you look at the complete code for PhotoPage.xaml very closely you will notice that in the page header there is this NavigationCacheMode="Enabled" that is what makes it PhotoPage works.
There no need for all that code about saving states in the Page. The Frame class does that for you when the Page sets its NavigationCacheMode.
When my UserLogin page loads, i want to check for user database, and if it doesn't exist, or can't be read, i want to direct it to NewUser page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
CheckForUser();
if (UserExists == false)
this.Frame.Navigate(typeof(NewUser));
}
The problem is that it never navigates to NewUser, even when i comment out the if condition.
Navigate can't be called directly form OnNavigatedTo method. You should invoke your code through Dispatcher and it will work:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
CheckForUser();
if (UserExists == false)
Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() => this.Frame.Navigate(typeof(NewUser)));
}
This happens because your app tries to navigate before the current frame completely loaded. Dispatcher could be a nice solution, but you have to follow the syntax bellow.
using Windows.UI.Core;
private async void to_navigate()
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => this.Frame.Navigate(typeof(MainPage)));
}
Replace MainPage with your desired page name.
Call this to_navigate() function.
you can try this and see if this works
frame.Navigate(typeof(myPage)); // the name of your page replace with myPage
full example
var cntnt = Window.Current.Content;
var frame = cntnt as Frame;
if (frame != null)
{
frame.Navigate(typeof(myPage));
}
Window.Current.Activate();
or
if you want to use a 3rd party tool like Telerik try this link as well
Classic Windows Forms, Stunning User Interface
I see you override OnNavigatedTo method but do not call base method. It may be the source of problem.
Try calling base method before any logic:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
CheckForUser();
if (UserExists == false)
this.Frame.Navigate(typeof(NewUser));
}
Use Dispatcher.RunIdleAsync to postpone your navigation to another page until UserLogin page is completely loaded.
The others are correct, but since Dispatcher doesn't work from the view model, here's how to do it there:
SynchronizationContext.Current.Post((o) =>
{
// navigate here
}, null);