UWP, open very small Page/Frame - c#

I'm writting an app which has 2 windows:
- main: regular UWP window
- helper: always on top, very small to show only texts like: started, paused ..
I can't force 'helper' window to be small. 'Always on top' in this window works fine.
I'm following UWP samples:
- always on top mode works from:
uwp samples / app window / overlay
- making window small (fails) from: uwp samples / app window / size
My current code is like below.
Any ideas how to make 'helper' window small?
public sealed partial class MainPage : Page
{
private AppWindow appWindow;
private Frame appWindowFrame = new Frame();
async void ShowHelperWindow()
{
// Is CompactOverlay supported for our main window?
// If so, it will be supported for a new window as well.
// If it isn't, it will not be supported for new windows either so we cannot proceed.
if (!ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay))
{
return;
}
if (appWindow == null)
{
// Create a new AppWindow
appWindow = await AppWindow.TryCreateAsync();
// Make sure we release the reference to this window, and release XAML resources, when it's closed
appWindow.Closed += delegate { appWindow = null; appWindowFrame.Content = null; };
// Is CompactOverlay supported for this AppWindow? If not, then stop.
if (appWindow.Presenter.IsPresentationSupported(AppWindowPresentationKind.CompactOverlay))
{
// Create a new frame for the window
// Navigate the frame to the CompactOverlay page inside it.
appWindowFrame.Navigate(typeof(TimerStatusPage));
var size = new Size(192, 48);
WindowManagementPreview.SetPreferredMinSize(appWindow, new Size(192, 48));
// Request the size of our window
appWindow.RequestSize(size);
// Attach the frame to the window
ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowFrame);
// Let's set the title so that we can tell the windows apart
appWindow.Title = "size:" + size;
// Request the Presentation of the window to CompactOverlay
bool switched = appWindow.Presenter.RequestPresentation(AppWindowPresentationKind.CompactOverlay);
if (switched)
{
// If the request was satisfied, show the window
await appWindow.TryShowAsync();
}
}
}
else
{
await appWindow.TryShowAsync();
}
}
... rest of class

Related

How to register a UWP app as share recipient for camera snapshot

In Windows 10, when I hit e.g. SHIFT + WIN + S I can take a screenshot of my screen.
In other cases I have my webcam that can take a picture, and so on.
All those scenarios have the feature to "Share" the captured image to another app, e.g. Mail, OneNote, etc.
I would like to register my own UWP app to be the recipient of such Share, so that the user can manipulate the captured image in my UWP app.
Is there a way to configure my UWP app to do this?
Is there a way to configure my UWP app to do this?
Yes, you could make your UWP app a receiver when you want to share some content from other apps.
Declare your app as a share target. Open the manifest file. Find the Declarations tab, then choose Share Target from the Available Declarations list, and then select Add.
Set the file types and formats based on your requirements in the Declarations. For example, if you need to receive a screenshot, you will need to add Bitmap in the Data format.
Handle share activation in the App.Xaml.cs by handling the Application.OnShareTargetActivated event.
I've made a simple test about this and you could refer to it. For more information about this, you could also check this document: Receive data
Manifest file:
App.xaml.cs:
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
if (shareOperation.Data.Contains(StandardDataFormats.Bitmap))
{
var imageStream = await shareOperation.Data.GetBitmapAsync();
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();
Window.Current.Content = rootFrame;
}
rootFrame.Navigate(typeof(ShareImagePage), imageStream);
Window.Current.Activate();
}
}
ShareImagePage:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.Content != null)
{
IRandomAccessStreamReference imageReceived = null;
imageReceived = e.Parameter as IRandomAccessStreamReference;
using (var imageStream = await imageReceived.OpenReadAsync())
{
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
imgImage.Source = bitmapImage;
}
}
}

How to retrieve the window handle of the current WinUI 3 MainWindow from a page in a frame in a NavigationView control on the MainWindow

I am creating my first WinUI 3 desktop application. I have a NavigationView on my MainWindow.
I have 9 different pages that I navigate to via the frame in the NavigationView.
One of the pages is for printing reports. I need to get the FileSavePicker to work from the 'reportPage'. I have implemented the below, directly following the examples from the learn.microsoft.com. (I also added the same FileSavePicker code segment below to a small dummy winui-3 sand-box test app, but instead I put the code on the MainWindow's code-behind and it worked perfectly.) I need to get the FileSavePicker to work from a page instead of a MainWindow.
Thank you all for your help so far.
I get this debug error:
I know the problem has to do with getting the MainWindow's HWND.
// Retrieve the window handle (HWND) of the current WinUI 3 window.
var window = (MainWindow)Application.Current.MainWindow; (I tried this, but it did not work)
I get this error from the above line:
(I tried this, but it did not work)
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
I get this error from the line above:
I don't know the correct syntax.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Provider;
namespace MetricReporting.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class pageReports : Page
{
public pageReports()
{
this.InitializeComponent();
}
private void ButtonBoltReport_Click(object sender, RoutedEventArgs e)
{
DisplayBOLTSaveDialog();
}
private async void DisplayBOLTSaveDialog()
{
FileSavePicker savePicker = new FileSavePicker();
// Retrieve the window handle (HWND) of the current WinUI 3 window.
var window = (MainWindow)Application.Current.MainWindow;
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
// Initialize the folder picker with the window handle (HWND).
WinRT.Interop.InitializeWithWindow.Initialize(savePicker, hWnd);
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = "New Document";
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
// write to file
await FileIO.WriteTextAsync(file, file.Name);
// Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
if (status == FileUpdateStatus.Complete)
{
ReportStatus.Text = "File " + file.Name + " was saved.";
}
else
{
ReportStatus.Text = "File " + file.Name + " couldn't be saved.";
}
}
else
{
ReportStatus.Text = "Operation cancelled.";
}
}
}
}
Change the modifier for the m_window field in App.xaml.cs:
internal Window m_window;
...or better yet expose it through a property:
public Window Window => m_window;
Then you can access the window from the page like this:
var window = (Application.Current as App)?.m_window as MainWindow;
or
var window = (Application.Current as App)?.Window as MainWindow;

UWP Custom Constructor when creating a secondary window

I'm developing a quick application with the sole purpose of using picture-in-picture mode (compact view) in UWP to display Youtube videos over top of my work. Here's the way the current system works:
MainPage - Handles searching of youtube videos
YoutubeItem - A usercontrol that the mainpage creates for each youtube result. Approximately 50 of these are put into a wrap panel.
YoutubeViewer - A seperate page that runs in it's own window and displays the youtube video.
Here's my issue. I store all the information for the youtube video in each of the YoutubeItems. Using a button, I record the click event and handle it. Here's the code for handling the click:
private async void Button_Click(object sender, RoutedEventArgs e)
{
CoreApplicationView newView = CoreApplication.CreateNewView();
int newViewId = 0;
await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Frame frame = new Frame();
frame.Navigate(typeof(YoutubeViewer), null);
Window.Current.Content = frame;
// You have to activate the window in order to show it later.
Window.Current.Activate();
newViewId = ApplicationView.GetForCurrentView().Id;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);
}
The problem arises when I have to send the link for the video to the YoutubeViewer. Originally, I was doing this through a constructor but upon using this method for the Windows Documentation, I am unable to use my own constructor from my knowledge. How would you folks recommend getting the link to the new window?
There are many ways.
the simplest, though not necessarily the most elegant, is to create a new class that inherits from Frameand add to it a property for the link. Something like this:
public class FooFrame: Frame
{
public string Link;
}
then in your code assign it upon initializing the frame:
FooFrame frame = new FooFrame(){Link = "youtube.link.com"}

Close secondary view completely in UWP

I am using a secondary view to run my media files, but When I close my secondary view with close button on it (while media is still playing) the secondary view/window closes but the media somehow keeps playing because I can hear the sound and source of sound seems to be the primary view (main app window). How can I completely terminate the secondary window when I close it?
Here is my code to create the secondary view.
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.MinHeight = 200;
frame.MinWidth = 200;
compactViewId = ApplicationView.GetForCurrentView().Id;
frame.Navigate(typeof(CompactNowPlayingPage), caption);
Window.Current.Content = frame;
Window.Current.Activate();
ApplicationView.GetForCurrentView().Title = Title;
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsViewModeAsync(compactViewId, ApplicationViewMode.Default);
Update
After some debugging I've come to know that close button pressed on the secondary view only hides the view but it keeps on running on its thread, I just want that close button to completely close the secondary view, close its thread and destroy the window as a whole.
Update 2
I followed windows samples multiple views and was able to complete all steps, the code runs fine until it reaches Windows.Current.Close() in released event.
Then it gives an exception when it tries "Window.Current.Close()" with in the released event. according to documentation exception occurs due to any on going changes ( which might be because of media file playing ), but I need to force close the window even when media file is playing how can I do that? Here is the exception:
Message = "COM object that has been separated from its underlying RCW cannot be used."
Update 3
This is the latest updated, I am not following official sample now, just following simpler approach now.
Code to open secondary view:
await Helpers.DeviceTypeHelper.CompactOpen(e.ClickedItem as Video, identifier); //where identified is just a string for some custom logic in the secondary view.
//following method is located in a helper class within the project
internal static async Task CompactOpen(Video PlayingVideo, string caption)
{
ApplicationView newView = null;
await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var frame = new Frame();
frame.Navigate(typeof(CompactNowPlayingPage),new object[] { PlayingVideo,caption});
Window.Current.Content = frame;
Window.Current.Activate();
newView = ApplicationView.GetForCurrentView();
newView.Title = PlayingVideo.MyVideoFile.DisplayName;
});
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newView.Id);
}
Secondary View:
public sealed partial class CompactNowPlayingPage : Page
{
public CompactNowPlayingViewModel ViewModel { get; } = new CompactNowPlayingViewModel();
private CustomMediaTransportControls controls;
public CompactNowPlayingPage()
{
InitializeComponent();
this.Loaded += MediaPage_Loaded;
this.Unloaded += MediaPage_Unloaded;
Microsoft.Toolkit.Uwp.UI.Extensions.ApplicationView.SetExtendViewIntoTitleBar(this, true);
Microsoft.Toolkit.Uwp.UI.Extensions.TitleBar.SetButtonBackgroundColor(this, Colors.Transparent);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
string chk = "";
var paramm = e.Parameter as object[];
NowPlayingVideo = paramm[0] as Video;
var vis = Visibility.Collapsed;
chk = paramm[1].ToString();
switch (chk)
{
case "library":
vis = Visibility.Visible;
break;
case "playlist":
vis = Visibility.Visible;
break;
case "history":
vis = Visibility.Collapsed;
break;
case "directplay":
vis = Visibility.Collapsed;
break;
default:
break;
}
controls = new CustomMediaTransportControls(NowPlayingVideo,vis);
Media.TransportControls = controls;
PlayVideo();
}
private Video NowPlayingVideo { get; set; }
private void PlayVideo()
{
if (NowPlayingVideo != null)
{
string token = "";
if (StorageApplicationPermissions.FutureAccessList.Entries.Count == 800)
{
var en = StorageApplicationPermissions.FutureAccessList.Entries;
StorageApplicationPermissions.FutureAccessList.Remove(en.Last().Token);
}
token = StorageApplicationPermissions.FutureAccessList.Add(NowPlayingVideo.MyVideoFile);
Media.Source = null;
Media.Source = $"winrt://{token}";
SetViews();
}
}
private void SetViews()
{
NowPlayingVideo.Views++;
Database.DbHelper.UpdateViews(NowPlayingVideo.MyVideoFile.Path);
}
private void MediaPage_Loaded(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Consolidated += MediaPage_Consolidated;
}
private void MediaPage_Unloaded(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Consolidated -= MediaPage_Consolidated;
}
private void MediaPage_Consolidated(Windows.UI.ViewManagement.ApplicationView sender, Windows.UI.ViewManagement.ApplicationViewConsolidatedEventArgs args)
{
Window.Current.Close();
}
}
Secondary View XAML:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<vlc:MediaElement AreTransportControlsEnabled="True"
Name="Media"
HardwareAcceleration="True"
AutoPlay="True">
</vlc:MediaElement>
</Grid>
Case 1 : Everything runs perfect if I place a video file in Assets folder and give it as a source to the media element and comment the whole OnanvigatdTo method on secondary page. And I am able to successfully close the window as well.
...
Case 2 : But when I try to set the media through the NowPlayingVideo object as shown in the code above and I also use default Transport Controls, so I don't comment the lines used to assign custom transport controls in the above code it runs fine, but when I then try to close the window I get following exception in App.i.g.cs file but stacktrace doesn't exist:
Message = "Attempt has been made to use a COM object that does not have a backing class factory." Message = "COM object that has been separated from its underlying RCW cannot be used.
Case 3 : Exactly like case 2 but here I uncomment Custom transport controls lines so now I am assigning custom transport controls to my media element, this time exception is a bit different with some stacktrace as well
StackTrace = " at System.StubHelpers.StubHelpers.GetCOMIPFromRCW_WinRT(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget)\r\n at Windows.UI.Xaml.DependencyObject.get_Dispatcher()\r\n at VLC.MediaElement.d__160.MoveNext()\r\n--- End of stack trace ...
Message = "Attempt has been made to use a COM object that does not have a backing class factory."
The short answer is: you need to make sure nothings holds on to your view instance, and you call Window.Close in the view's Consolidated event. The longer answer with code is here in the official sample. Take a look at the ViewLifetimeControl.cs source file: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews/cs

UWP StoreContext provides inaccurate information in RELEASE version

I have an app, published in Windows Store and the app has a trial version. But recently the trial version provides the full version somehow.
When I debugged the code, it shows that the following piece of code gets called twice in the release version and once it says that Trial is true and secondly it says Trial is false.
if (storeContext == null)
{
storeContext = StoreContext.GetDefault();
}
appLicense = await storeContext.GetAppLicenseAsync();
if (appLicense.IsActive)
{
if (appLicense.IsTrial)
{
isTrial = true;
}
else
{
isTrial = false;
}
}
When I debug the code in Release version it appLicense.IsTrial gets evaluated two times and that's how it produces two different results. Is it a bug? Should I tell Microsoft about this? Or is it just related to me somehow? If you try my app from store here you can probably see that it provides full access to the application and that the search is available to use while it's disabled in Trial version. Please help me with this.
Update:
The ExtendedSplash code:
public sealed partial class ExtendedSplash : Page
{
internal Rect splashImageRect; // Rect to store splash screen image coordinates.
private SplashScreen splash; // Variable to hold the splash screen object.
internal bool dismissed = false; // Variable to track splash screen dismissal status.
internal Frame rootFrame;
// Define methods and constructor
public ExtendedSplash(SplashScreen splashscreen, bool loadState)
{
InitializeComponent();
// Listen for window resize events to reposition the extended splash screen image accordingly.
// This ensures that the extended splash screen formats properly in response to window resizing.
Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);
splash = splashscreen;
if (splash != null)
{
// Register an event handler to be executed when the splash screen has been dismissed.
splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(DismissedEventHandler);
// Retrieve the window coordinates of the splash screen image.
splashImageRect = splash.ImageLocation;
//PositionImage();
// If applicable, include a method for positioning a progress control.
//PositionRing();
}
// Create a Frame to act as the navigation context
rootFrame = new Frame();
}
void PositionImage()
{
//extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X);
//extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y);
//extendedSplashImage.Height = splashImageRect.Height;
//extendedSplashImage.Width = splashImageRect.Width;
}
void PositionRing()
{
splashProgressRing.SetValue(Canvas.LeftProperty, splashImageRect.X);// + (splashImageRect.Width * 0.5) - (splashProgressRing.Width * 0.5));
splashProgressRing.SetValue(Canvas.TopProperty, (splashImageRect.Y + splashImageRect.Height));// + splashImageRect.Height * 0.1));
}
// Include code to be executed when the system has transitioned from the splash screen to the extended splash screen (application's first view).
async void DismissedEventHandler(SplashScreen sender, object e)
{
dismissed = true;
// Complete app setup operations here...
await TrialManager.IsTrialLicense();
// this is the code that gets called to see the Trial / Purchase
DismissExtendedSplash();
}
async void DismissExtendedSplash()
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Navigate to mainpage
rootFrame.Navigate(typeof(IndexPage));
// Place the frame in the current Window
Window.Current.Content = rootFrame;
});
}
void ExtendedSplash_OnResize(Object sender, WindowSizeChangedEventArgs e)
{
// Safely update the extended splash screen image coordinates. This function will be executed when a user resizes the window.
if (splash != null)
{
// Update the coordinates of the splash screen image.
splashImageRect = splash.ImageLocation;
//PositionImage();
// If applicable, include a method for positioning a progress control.
//PositionRing();
}
}
void RestoreStateAsync(bool loadState)
{
if (loadState)
{
// code to load your app's state here
}
}
}

Categories