UWP Root frame vs Page frame - c#

Here is typical App.xaml.cs code
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
//this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
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;
rootFrame.Navigated += OnNavigated;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
// Register a handler for BackRequested events and set the
// visibility of the Back button
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
rootFrame.CanGoBack ?
AppViewBackButtonVisibility.Visible :
AppViewBackButtonVisibility.Collapsed;
}
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(SignInPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
}
When rootFrame.Navigate(typeof(SignInPage), e.Arguments);is called, SignInPage is created. In SignInPage.xaml.cs, there might be code like: this.Frame.Navigate(typeof(FramePage));. Is the Frame from this.Frame. the same as rootFrame? If it is, when and where does the Page class get assigned the root frame from App.xaml.cs?

Yes this is the same Frame object, as the Page has a reference to the frame controlling it's content. In other words the Frame that did the navigation to the page.
Frame
Gets the controlling Frame for the Page content.
Source: learn.microsoft.com
This property is automatically set on navigation and is first available in your Page object in the OnNavigatedTo method.

Related

Bring the UWP app to the front of current window

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
}

Xamarin.Forms UWP - Launch app on login

I'm trying to launch my app when the user logs in to Windows. I have the appropriate Extension (StartupTask) set in Package.appxmanifest, and I can get the app to launch when I log in to Windows, as expected. However, the app crashes after showing the Splash screen for about a second or two.
In my App.xaml.cs file, I have overridden the OnLaunched (called when the user launches the app) and OnActivated (called when the system launches the app after Windows login). Both call the same function to initialize my app; however, the app crashes only when the app is initialized from the OnActivated function. When initialized from OnLaunched, it works as expected. Here is the relevant code, from App.xaml.cs:
// Called when the user launches the app
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
// Calling InitializeApp here, the app launches without problem
InitializeApp(e);
}
// Called when the system launches the app after Windows login
protected override void OnActivated(IActivatedEventArgs e)
{
base.OnActivated(e);
// Calling InitializeApp here will cause the app to crash
InitializeApp((LaunchActivatedEventArgs)e);
}
// initialize the app
async void InitializeApp(LaunchActivatedEventArgs e)
{
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;
var assembliesToInclude = new List<Assembly>()
{
typeof(CachedImage).GetTypeInfo().Assembly,
typeof(CachedImageRenderer).GetTypeInfo().Assembly
};
Xamarin.Forms.Forms.Init(e, assembliesToInclude);
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
if (session == null)
{
// prevent the app from stopping when minimized
session = new ExtendedExecutionSession();
session.Reason = ExtendedExecutionReason.Unspecified;
session.Revoked += (s, a) => { };
var result = await session.RequestExtensionAsync();
if (result == ExtendedExecutionResult.Denied)
System.Diagnostics.Debug.WriteLine("EXTENDED EXECUTION DENIED");
}
}
The problem is that you are trying to cast the IActivatedEventArgs to LaunchActivatedEventArgs, but when startup activation happens, the type is actually StartupTaskActivatedEventArgs.
Luckily, you actually need the e parameter only for Xamarin.Forms.Forms.Init which actually accepts IActivatedEventArgs, so you can just change the parameter of InitializeApp to be IActivatedEventArgs and remove the cast to LaunchActivatedEventArgs in OnActivated.

Specify startup monitor for UWP app

In a UWP desktop app , is there a way to force the application to open on a specific monitor. (in my case I have a laptop and extra screen connected to the laptop, so I want the specify the startup screen in code)
I used the following code in winforms:
Screen[] screens = Screen.AllScreens;
if (Screen.AllScreens.Length == 1)
{
Application.Run(new frmMain());
}
else
{
//select largest monitor and set new monitor
Rectangle bounds = screens[LargestScreen].Bounds;
frm.SetBounds(bounds.X, bounds.Y, bounds.Width, bounds.Height);
frm.StartPosition = FormStartPosition.Manual;
Application.Run(frm);
}
Any idea how to implement the above in a UWP app?
You should be able to create multiple views for the app and use ProjectionManager class with method StartProjectingAsync to show the secondary view on another screen. You may do this in OnLaunched method then once the app launch the secondary view will show on the screen you want.
protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
Frame rootFrame = Window.Current.Content as Frame;
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 (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
///Get all the screens.
String projectorSelectorQuery = ProjectionManager.GetDeviceSelector();
var outputDevices = await DeviceInformation.FindAllAsync(projectorSelectorQuery);
//if(outputDevices.Count==1)
//{
//}
int thisViewId;
int newViewId = 0;
///Choose one screen for display .
DeviceInformation showDevice = outputDevices[1];
thisViewId = ApplicationView.GetForCurrentView().Id;
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
}
Window.Current.Activate();
}
///Create a new view
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Frame frame = new Frame();
frame.Navigate(typeof(MainPage), null);
Window.Current.Content = frame;
Window.Current.Activate();
newViewId = ApplicationView.GetForCurrentView().Id;
});
await ProjectionManager.StartProjectingAsync(newViewId, thisViewId, showDevice);
}
But it seems like the first view cannot be directly show on other screens since the StartProjectingAsync method requires a new view id. The first view that’s created when your app starts is called the main view. You don’t create this view; it’s created by the app. The main view's thread serves as the manager for the app, and all app activation events are delivered on this thread. And the main view cannot be closed, so the main first view will still leave on the first screen.
Details please reference the Projection official sample.

UWP Slow back button on Local Machine

I am writing Windows 10 Universal App, and I need to add ordinary method
private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
return;
if (rootFrame.CanGoBack && e.Handled == false)
{
e.Handled = true;
rootFrame.GoBack();
}
//debug
int stop = 0;
}
...in my
App.xaml.cs
that will handle the Back button function of the device.
I am using it here:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
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;
rootFrame.Navigated += OnNavigated;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
// Register a handler for BackRequested events and set the
// visibility of the Back button
SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
rootFrame.CanGoBack ?
AppViewBackButtonVisibility.Visible :
AppViewBackButtonVisibility.Collapsed;
}
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
Its works fine, but the problem is when I build and run in on Local Machine and use Back Button to navigate between pages its took around 5000 - 6000 ms (5-6 seconds) to navigate to previous page.
When I debugged it, The delay between:
if (rootFrame.CanGoBack && e.Handled == false)
{
e.Handled = true;
rootFrame.GoBack();
}
//debug
int stop = 0;
rootFrame.GoBack(); and debug variable "stop" is 5,778 ms...., when I run it on Mobile Emulator or Mobile Device the delay time is reduced to ~100ms
I will be grateful is someone is able to help.
Thanks.
I found what causing the delay, It was two SQL transactions methods in my MainPage file, which used to get to much data from SQLite Database file. They were called everytime when the paged is called. (Placed in page constructor). I move them in separate class and everythins seem to be fine.

Can't make Share works

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

Categories

Resources