UWP Slow back button on Local Machine - c#

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.

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.

UWP Root frame vs Page frame

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.

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) Hardware Back Press work correctly in mobile but error with PC

In my UWP app when i click on mobile back button app get close, so add this code in app.xaml.cs
private async void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
{
e.Handled = true;
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame.CanGoBack && rootFrame != null)
{
rootFrame.GoBack();
}
else
{
var msg = new MessageDialog("Confirm Close! \nOr Press Refresh Button to Go Back");
var okBtn = new UICommand("OK");
var cancelBtn = new UICommand("Cancel");
msg.Commands.Add(okBtn);
msg.Commands.Add(cancelBtn);
IUICommand result = await msg.ShowAsync();
if (result != null && result.Label == "OK")
{
Application.Current.Exit();
}
}
}
and
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
/* Because of this line my app work on mobile great but when
when i debug on pc it through exception "show in image" */
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
After Done all this code when i debug app on phone, app successfully run -
Mobile Debuging:
But when debug in pc with same code, it show this error- PC Debuging:
when i remove HardwareButtons.BackPressed += HardwareButtons_BackPressed; then issue with pc debugging resolved but in mobile debuging back button again is not work.
The reason is that HardwareButtons API is not the universal solution for handling the back button. This API is available only in the Mobile extension SDK and trying to invoke it on other SKU will cause this exception, because the type is not available.
To enable the same functionality on all systems, you will need to use the new universal back button event:
SystemNavigationManager.GetForCurrentView().BackRequested += BackButtonHandler;
This will work the same on phone, PC, tablets,Xbox One, Surface Hub and HoloLens.
On PC this button is not shown by default, so you have to display it manually or create your own. To show the Back button in window's title bar, use:
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Visible;
It is recommended that you hide this button once Frame.CanGoBack is false, because in that case the button is no longer useful. You should do this after each navigation of the frame. Best place to do this is when setting up the root frame in App.xaml.cs:
Frame rootFrame = Window.Current.Content as Frame;
rootFrame.Navigated += UpdateAppViewBackButton;
Now the handler could look like this:
private void UpdateAppViewBackButton( object sender, NavigationEventArgs e )
{
Frame frame = (Frame) sender;
var systemNavigationManager = SystemNavigationManager.GetForCurrentView();
systemNavigationManager.AppViewBackButtonVisibility =
frame.CanGoBack ? AppViewBackButtonVisibility.Visible :
AppViewBackButtonVisibility.Collapsed;
}
On Application close
I have also noticed that you are using Application.Current.Exit(); to exit the app. This is however not recommended. Once the user chooses OK in the dialog, you should rather set the e.Handled = false and let the system handle the app close manually. This will ensure the app suspension will run as expected and the app will stay in memory if the system has enough resources and will then launch faster again. Application.Current.Exit() kills the application and it is not recommended for UWP apps.
One thing to remember is that on Desktop, there is currently no way to catch the user clicking the close button in the app's title bar, so your confirmation dialog will not display in that case unfortunately.

Categories

Resources