Initialize topmost UWP window from the constructor - c#

Weird issue.
I'm trying to build a desktop app that has an option to open a second "window".
So Foo opens Bar.
Only Bar should, by default, be a topmost window.
The below method works just fine, when called by a button click.
private async Task<bool> MakeTopMost()
{
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay);
}
However, when called from the page constructor, via an Action,
new Action(async () => await MakeTopMost())();
...
Lo and behold. Nothing happens. I've tried the Loaded event also. No dice.
What am I missing?
Edit:
A workaround would be the button clicked to open a new app also makes the app topmost. Like so:
private async void ShowCompactView()
{
var compactViewId = ApplicationView.GetForCurrentView().Id;
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(BAR));
Window.Current.Content = frame;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = "CompactOverlay Window";
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsViewModeAsync(compactViewId, ApplicationViewMode.CompactOverlay);
}
But that makes the whole app topmost (not just a page).

What I basically did in the method posted last in the question was
Get the id of the application page currently displayed
Open a new page.
Compact overlay the id. Which was the main page. So basically the entire app was set as topmost.
So, by using a variable to hold the id of the newly opened page, the BAR, we can open a page from FOO that's automatically set as topmost.
private int _barID;
private async void ShowCompactView()
{
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(Bar));
_barID = ApplicationView.GetForCurrentView().Id;
Window.Current.Content = frame;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = "CompactOverlay Window";
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsViewModeAsync(sliderID, ApplicationViewMode.CompactOverlay);
}
it should have been obvious.

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
}

Page navigation event

I was reading trough the documentation for UWP and I got stuck a little.
I have few pages that connect to WCF service taking some information of it few of them download pictures and take few seconds to load.
So I've decided to implement a loading screen while they load however when I try using
this.Frame.Navigate(typeof(page));
I get stuck in a deadlock state everything freezes while the new page is loading I've tried putting on pageloading event on the other page but this is not helping much since its still locked on the last form.
Does anyone know the right event that I need to call when calling this.Frame.Navigate() so I can initialize my loading control while the new frame is loaded?
Navigate to Loading Screen
this.Frame.Navigate(typeof(LoadingScreen));
In OnNavigatedTo event in LoadingScreen "download pictures"
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
await DownloadPictures();
//After downloading, navigate to the next page
this.Frame.Navigate(typeof(page));
}
try launching the view on a separate window like this
try
{
CoreApplicationView Nv= CoreApplication.CreateNewView();
var z = CoreApplication.MainView;
int id= 0;
await
Nv.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
Frame frame = new Frame();
frame.Navigate(typeof(page));
Window.Current.Content = frame;
// You have to activate the window in order to show it later.
Window.Current.Activate();
id= ApplicationView.GetForCurrentView().Id;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(id);
}
catch (Exception eee)
{
Windows.UI.Popups.MessageDialog errorBox =
new Windows.UI.Popups.MessageDialog("Couldn't Create New
Window: " + eee.Message);
await errorBox.ShowAsync();
}

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.

Using C# & Xamarin Forms - How can I close one modal without setting of chain of closures

In one stage of my app (Android & iOS are the ones we care about) we've got three pages which take in details and then open a webView for the user to input their card details to take a payment - this can't be done in the app due to Apple's guidelines.
I need to format the navigation in a way that when the user has finished in the webView it closes and then closes the 3 previous modals to get back to the original page. I've got it all working with the Appearing event so each page just closes itself:
this.Appearing += async (s, e) =>
{
await Navigation.PopModalAsync();
};
The issue I'm now having is that when the user presses the back button on the phone, it closes all of the pages that they've been through already & back to the original. I thought about implementing a custom nav bar and disabling the back button on the hardware but this would cause the same problem with the Appearing event.
Is there any easy way to solve this?
EDIT: Relevant code;
async void OnButtonClicked(object sender, EventArgs eventArgs)
{
if (IsConnected)
{
ActivityIndicator.IsVisible = true;
var button = (Button) sender;
button .IsEnabled = false;
await Navigation.PushModalAsync(new Page());
this.Appearing += (s, e) =>
{
ActivityIndicator.IsVisible = false;
button.IsEnabled = true;
RefreshPage();
};
}
else
{
NoInternetLabel.IsVisible = true;
}
}
Use this:
YourButton.Clicked += OpenPage;
OpenPage looks like this:
async public void OpenPage(object sender, EventArgs args)
{
await Navigation.PushAsync(new PageToShow());
}
You don't have to do anything to handle the PageToShow() closing, that happens by itself when the user presses the back button.
Managed to solve this by using Actions. In each new Page() we passed up an async method to close it once the one after had completed;
var nextPage = new Page(async () =>
{
await Navigation.PopModalAsync();
_completedSuccessfully();
});
await Navigation.PushModalAsync(nextPage);
And in the new page class;
private readonly Action _completedSuccessfully;
public Page(Action completedSuccessfully)
{
_completedSuccessfully = completedSuccessfully;
}
This meant that when the webView closed it called the completedSuccessfully() action and then chained all of them to the original page.

How to show a modal window in windows 10 universal app?

When I use Mail univesal app in windows 10, when i add an account (setting->accounts->add account), it seems popup a modal window to choose an account. I try to use MessageDialog, but i can't put any custom content into it.
EDIT : this is the screenshot
Is someone knows how to implement it or there is some api can do it?
Note: When this window open, you even can't Minimize/Maximize/Close the main Window. So, it is definitely a modal window.
I haven't used it myself yet but i believe you're looking for ContentDialog api.
var dialog = new ContentDialog() {
Title = "Lorem Ipsum",
MaxWidth = this.ActualWidth // Required for Mobile!
Content = YourXamlContent
};
dialog.PrimaryButtonText = "OK";
dialog.IsPrimaryButtonEnabled = false;
dialog.PrimaryButtonClick += delegate {
};
var result = await dialog.ShowAsync();
msdn guidlines for dialogs: link
msdn ContentDialog API: link
You can easily create a new view like this, for example in your App.xaml.cs:
public static async Task<bool> TryShowNewWindow<TView>(bool switchToView)
{
var newView = CoreApplication.CreateNewView();
int newViewId = 0;
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(TView), null);
Window.Current.Content = frame;
newViewId = ApplicationView.GetForCurrentView().Id;
});
var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);
if (switchToView && viewShown)
{
// Switch to new view
await ApplicationViewSwitcher.SwitchAsync(newViewId);
}
return viewShown;
}
For further information, take a look at those two guides:
Guidelines for multiple windows
Quickstart: Creating multiple windows for an app (XAML)
If you use Template10 project template, you can use the ModalDialog control : https://github.com/Windows-XAML/Template10/wiki/Docs-%7C-Controls#modaldialog

Categories

Resources