I am struggling with it for a few hours and can't find working solution. My app is a target app for sharing and the problem is when it's running and user wants to share content.
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
await OnInitializeAsync();
if (await CheckToken(args) != true) return;
if (args.PreviousExecutionState != ApplicationExecutionState.Running)
{
if (await LoadData(args) != true) return;
}
var frame = new Frame();
var navigationService = new NavigationService(_dispatcherService) { RootFrame = frame, };
Window.Current.Content = frame;
Window.Current.Activate();
navigationService.Navigate<ShareViewModel>(args.ShareOperation);
}
The problem is that I can't use frame from running application because I get an exception "marshalling thread ...." so I create a new frame and I assign it to Window.Current.Content. This works fine but the problem is when user finishes sharing. What should I do? It seems that I should assign previous frame to Window.Current.Content which was "overriden" by sharing target right? While I try to do it I get again "marshalling thread" exception. If I don't do it then I can't interact with my application because I get an exception that app is being closed. What is the proper scenario for being a sharing target?
Edit: I guess it's important to mention that I call ReportStarted() when I send message in ShareViewModel and ReportCompleted() when I am done.
Exception thrown when I try to assign frame back:
{"The application called an interface that was marshalled for a different thread.\r\n\r\nFailed to initialize the application's root visual"}
I'm pasting the solution which solved the issue. I think the key here is to use
CoreWindow.GetForCurrentThread().Dispatcher
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
await OnInitializeAsync();
if (await CheckToken(args) != true) return;
if (args.PreviousExecutionState != ApplicationExecutionState.Running)
{
if (await LoadData(args) != true) return;
}
var frame = new Frame();
Window.Current.Content = frame;
var dispatchService = new DispatcherService() { Dispatcher = CoreWindow.GetForCurrentThread().Dispatcher };
var navigationService = new NavigationService(dispatchService) { RootFrame = frame };
navigationService.Navigate<ShareViewModel>(args.ShareOperation);
Window.Current.Activate();
}
Related
How can i use
await Windows.System.Launcher.LaunchUriAsync(new Uri("protocol://"));
to navigate to specific view of uwp application.
Is there any way to bring the app in front of the screen, if app was minimized or hidden behind other apps?
Thanks in advance
How can i use await Windows.System.Launcher.LaunchUriAsync(new Uri("protocol://")); to navigate to specific view of uwp application
For this, firstly you need to add the Protocol declaration in your Package.appxmanifest file . (Go to declarations tab and add Protocol from the available protocols). ( MSDN Doc )
Here i am using "app-protocol" as the protocol name.
Once this is done, you need to override the OnActivated() method in your App.xaml.cs. This method will be called when the app is launched using the protocol.
The arguments that we pass when calling the protocol can be retrieved here and based on that you can show your page or maybe pass that parameter to your page and let it handle the navigation .
For instance, if our Uri is app-protocol:login?param1=true, when you receive the ProtocolActivatedEventArgs eventArgs in the onActivated() method you will have access to the whole Uri.
You can use eventArgs.Uri to access all the Uri properties.
In any case your code should look something like this :
C#
protected override void OnActivated(IActivatedEventArgs args)
{
if (args.Kind == ActivationKind.Protocol)
{
ProtocolActivatedEventArgs eventArgs = args as ProtocolActivatedEventArgs;
// Get the root frame
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)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
rootFrame.NavigationFailed += OnNavigationFailed;
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
//URI : app-protocol:login?param1=true
//Logic for showing different pages/views based on parameters passed
if (eventArgs.Uri.PathAndQuery != string.Empty)//PathAndQuery:login?param1=true
{
var absolutePath = eventArgs.Uri.AbsolutePath;//AbsolutePath:login
if (absolutePath.Equals("login"))
{
rootFrame.Navigate(typeof(LoginPage));
}
else
{
rootFrame.Navigate(typeof(MainPage));
}
}
else
{
rootFrame.Navigate(typeof(MainPage));
}
}
// Ensure the current window is active
Window.Current.Activate();
}
Is there any way to bring the app in front of the screen, if app was minimized or hidden behind other apps?
We are calling Window.Current.Activate(); to ensure this.
To bring any UWP window to the front use this snippet (works if window with given viewId was already created and is either minimized or behind other windows:
private async Task TryActivateViewAsync(viewId)
{
if (Window.Current.Dispatcher != null)
{
await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
if (await ApplicationViewSwitcher.TryShowAsStandaloneAsync(viewId))
{
await ApplicationViewSwitcher.SwitchAsync(viewId);
}
});
}
}
Just as a reminder, viewId is an Identifier of a window which you can get when you create that window using:
var coreView = CoreApplication.CreateNewView(); // creates new view
await coreView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
_someViewId = ApplicationView.GetForCurrentView().Id; // gets that view's id
}
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'm using the Intense template to make a UWP application, the problem is that i can't make the Share works, cause i don't know how to navigate from the app.xaml.cs with this template.
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
//Can't make any navigation
}
You can get Microsoft source code to retrieve Frame object
private Frame CreateRootFrame()
{
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)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
return rootFrame;
}
and use like you want
protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
var rootFrame = CreateRootFrame();
// your page and share operation as navigation parameters
rootFrame.Navigate(typeof(ShareTargetPage), args.ShareOperation);
Window.Current.Activate();
}
Microsoft Sample Project
I have a Windows Phone 8.1 Universal App that I am working on adding basic Cortana support to. A lot of the articles about this are for Silverlight etc. - I'm finding it hard to find really good information about this.
So far, I have activation working if the app is already running or suspended. However, if the app is completely exited, then upon activation it crashes immediately. I've tried using Hockey and a simple "LittleWatson" routine to catch the crash, but it seems to happen too soon to be caught. I've seen some references to doing a private beta and trying to get the crash dump, but I didn't have any luck with that so far.
Here's what my activation code looks like in app.xaml.cs:
protected override void OnActivated(IActivatedEventArgs args) {
base.OnActivated(args);
ReceivedSpeechRecognitionResult = null;
if (args.Kind == ActivationKind.VoiceCommand) {
var commandArgs = args as VoiceCommandActivatedEventArgs;
if (commandArgs != null) {
ReceivedSpeechRecognitionResult = commandArgs.Result;
var rootFrame = Window.Current.Content as Frame;
if (rootFrame != null) {
rootFrame.Navigate(typeof(CheckCredentials), null);
}
}
}
}
and here is my check for the command result:
private async Task CheckForVoiceCommands() {
await Task.Delay(1); // not sure why I need this
var speechRecognitionResult = ((App)Application.Current).ReceivedSpeechRecognitionResult;
if (speechRecognitionResult == null) {
return;
}
var voiceCommandName = speechRecognitionResult.RulePath[0];
switch (voiceCommandName) {
// omitted
}
((App)Application.Current).ReceivedSpeechRecognitionResult = null;
}
I'm pretty sure from inserting messages etc. that it fails long before it gets this far.
There's likely something easy I'm missing but I don't know what...
What is causing the crash so early?
EDIT One thing I tried is using the "debug without launch" configuration to try to catch the exception. When I do this, the app appears to hang forever connected in the debugger on the splash screen. However, that did let me force a break. It hangs in
global::Windows.UI.Xaml.Application.Start((p) => new App());
which as best I can tell, just tells me the app is hanging somewhere. That's the only line in the call stack.
Copy a segment of the OnLaunched code into OnActivated like in the example below. OnLaunched is not called when the App is Activated and it does some essential work like activating the window.
protected override void OnActivated(IActivatedEventArgs args)
{
// When a Voice Command activates the app, this method is going to
// be called and OnLaunched is not. Because of that we need similar
// code to the code we have in OnLaunched
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
rootFrame = new Frame();
rootFrame.CacheSize = 1;
Window.Current.Content = rootFrame;
rootFrame.Navigate(typeof(MainPage));
}
Window.Current.Activate();
// For VoiceCommand activations, the activation Kind is ActivationKind.VoiceCommand
if(args.Kind == ActivationKind.VoiceCommand)
{
// since we know this is the kind, a cast will work fine
VoiceCommandActivatedEventArgs vcArgs = (VoiceCommandActivatedEventArgs)args;
// The NavigationTarget retrieved here is the value of the Target attribute in the
// Voice Command Definition xml Navigate node
string target = vcArgs.Result.SemanticInterpretation.Properties["NavigationTarget"][0];