SplitView and Back Button Navigation - UWP - C# - c#

I am currently learning C# in UWP environment. I have a test app which is having a bit of the problem as described in Splitview with frame and navigating to another page, back button does not work.
But the my code is a little different from the above page.
My App.xaml.cs has the following code:
namespace Testing
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
//NavigationCacheMode.Enabled;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
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 (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
//--------------------------------------------------------------------
//Window.Current.Content = new SplitShellPage(rootFrame);
//--------------------------------------------------------------------
Window.Current.Content = rootFrame;
}
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(MainPage), e.Arguments);
}
Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += App_BackRequested;
// Ensure the current window is active
Window.Current.Activate();
}
}
/// <summary>
/// Invoked when Navigation to a certain page fails
/// </summary>
/// <param name="sender">The Frame which failed navigation</param>
/// <param name="e">Details about the navigation failure</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
deferral.Complete();
}
private void App_BackRequested(object sender, Windows.UI.Core.BackRequestedEventArgs e)
{
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
return;
// Navigate back if possible, and if the event has not
// already been handled .
if (rootFrame.CanGoBack && e.Handled == false)
{
e.Handled = true;
rootFrame.GoBack();
}
}
}
}
If I use Window.Current.Content = new SplitShellPage(rootFrame); as in place of Window.Current.Content = rootFrame; the SplitView works but the back button does not work. If I use the second line then SplitView doesn't work but back navigation works.
I even tried setting my launch page to SplitView page as rootFrame.Navigate(typeof(SplitShellPage), e.Arguments); but that causes the application to stop at runtime and the application doesn't start.
The other pages with code are as:
SplitShellPage.xaml.cs
namespace Testing.Pages
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class SplitShellPage : Page
{
public SplitShellPage(Frame frame)
{
this.InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
shell_splitview.Content = frame;
(shell_splitview.Content as Frame).Navigate(typeof(MainPage));
}
private void hamburger_btn_Click(object sender, RoutedEventArgs e)
{
shell_splitview.IsPaneOpen = !shell_splitview.IsPaneOpen;
}
}
}
This method of work I found when searching on google to make the NavigationPane work in all the pages and it does work in all the pages just without the Back Navigation.
MainPage.xaml.cs
namespace Testing
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
}
private void Settings_Flyout_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(SettingsPage));
}
}
}
I have done some searches on google but nothing makes sense because they use some other methods and things get more complicated.
Please let me know what I am doing wrong here and how to make it right. Thanks.
P.S. Let me know if I need to also share the XAML files.

If I use Window.Current.Content = new SplitShellPage(rootFrame); as in place of Window.Current.Content = rootFrame; the SplitView works but the back button does not work
In this situation, the frame currently you are using is shell_splitview.Content.
Because you are using this code for navigating (shell_splitview.Content as Frame).Navigate(typeof(MainPage));. So in App.xaml.cs the method App_BackRequested method try to get the Window.Current.Content as Frame for navigating, the back button will not work.
The solution is provided by the demo in the thread you reference, to add the BackRequested event handle in the page which defined the SplitView. Update your code in SplitShellPage.xaml.cs as follows the back button will work.
public SplitShellPage(Frame frame)
{
this.InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
shell_splitview.Content = frame;
(shell_splitview.Content as Frame).Navigate(typeof(MainPage));
SystemNavigationManager.GetForCurrentView().BackRequested += SplitShellPage_BackRequested;
}
private void SplitShellPage_BackRequested(object sender, BackRequestedEventArgs e)
{
Frame myFrame = shell_splitview.Content as Frame;
if (myFrame.CanGoBack)
{
e.Handled = true;
myFrame.GoBack();
}
}
If I use the second line then SplitView doesn't work but back navigation works.
In this situation, we even did not access the SplitShellPage, and didn't access the SplitView. It is just a implemention of back button between two simple page. It works and has noting relationship with the content of SplitView.
The key point for this issue is to clear which frame you are using for navigating now , rootFrame(Window.Current.Content) or the SplitViewContent frame. And navigating back with back button need the same frame.
You can download the demo from the thread you referenced for further testing. And more details please reference Back button navigation.

Related

How to remove white place in UWP App (XAML)

I need to remove this white borders (marked orange pen). I want that my App fit 880px and be full width. In My XAML Document I did next
<Page
x:Class="FirstScreen.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FirstScreen"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Width="880" Height="600">
<Grid Width="880" Height="600" Background="Black">
</Grid>
</Page>
But I still have white borders! what I need that my App will compile with out this borders?
You can stop window resize, by using TryResizeView(Size) function, but its not recommended to do resize by code behind, when user is engaged in UI.
I will share the solution here , but again ITS NOT RECOMENDED.
in App.xaml.cs , OnLaunched event , once all your UI related code completed, at the end , place this line of code
ApplicationView.GetForCurrentView().TryResizeView(size);
ApplicationView.GetForCurrentView().VisibleBoundsChanged += App_VisibleBoundsChanged;
and create event for "App_VisibleBoundsChanged"
private void App_VisibleBoundsChanged(ApplicationView sender, object args)
{
ApplicationView.GetForCurrentView().TryResizeView(size);
}
declare a global variable for Size
Size size = new Size(800, 600);
This will make your app, always work in specified size. But the user feels like a glitch in app, when they try to resize .
Here is the entire App.xaml.cs code
sealed partial class App : Application
{
Size size = new Size(800, 600);
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used such as when the application is launched to open a specific file.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
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();
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
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(MainPage), e.Arguments);
}
// Ensure the current window is active
Window.Current.Activate();
}
ApplicationView.GetForCurrentView().TryResizeView(size);
ApplicationView.GetForCurrentView().VisibleBoundsChanged += App_VisibleBoundsChanged;
}
private void App_VisibleBoundsChanged(ApplicationView sender, object args)
{
ApplicationView.GetForCurrentView().TryResizeView(size);
}
}
You are giving the Grid a width as 880, so the Grid is not fill in all the window. Just remove the width and height that you've added.

How to remove particular page from modal stack?

I have four pages page 1-page 2-page 3-page 4.I use push modal async for navigating forward. When I tap button click in page 4 it is navigating to the page2. But tapping back button in page 2 is showing all history of the stack pages. So how to remove the page from the modal stack. I also used navigation.Remove(page) but it throws an exception. Please guide.
foreach (var page in Navigation.ModalStack)
{
if (page is Page3)
{
await PopModalPage();
}
}
foreach (var page in Navigation.ModalStack)
{
if (page is Page4)
{
await PopModalPage();
}
}
To navigate to page 2 from page 4 I'm using this code
Any optimized way than this??
You can use the following helper functions
/// <summary>
/// Class with extension methods for INavigation interface to help working with the modal page stack
/// </summary>
public static class ModalHelper
{
/// <summary>
/// Unwinds the modal stack of the navigation until reaching a page with the given type
/// </summary>
/// <typeparam name="PageType"></typeparam>
/// <param name="navigation">The navigation object of the current top page</param>
/// <returns></returns>
public async static Task UnwindModalStackTo<PageType>(this INavigation navigation) where PageType : Page
{
await navigation.UnwindModalStackTo(p => p is PageType);
}
/// <summary>
/// Unwinds the modal stack of the navigation until reaching the given page
/// </summary>
/// <param name="navigation">The navigation object of the current top page</param>
/// <param name="page">The page where to stop unwinding the modal stack</param>
public async static Task UnwindModalStackTo(this INavigation navigation, Page page)
{
await navigation.UnwindModalStackTo(p => p == page);
}
/// <summary>
/// Unwinds the modal stack of the navigation until reaching a page that fulfils the predicate
/// </summary>
/// <param name="navigation">The navigation object of the current top page</param>
/// <param name="predicate">A function which tests whether to stop at a given page</param>
public async static Task UnwindModalStackTo(this INavigation navigation, Func<Page, bool> predicate)
{
bool found = false;
while (navigation != null && navigation.ModalStack.Count > 0)
{
// Get the current top page of the modal stack
Page topPage = navigation.ModalStack[navigation.ModalStack.Count - 1];
// Get the second page in the modal stack from the top (This one will become top next after we pop)
Page parentPage;
if (navigation.ModalStack.Count > 1)
{
parentPage = navigation.ModalStack[navigation.ModalStack.Count - 2];
}
else
{
parentPage = null;
}
// When the top page fulfills the predicate, stop
if (predicate(topPage))
{
found = true;
break;
}
// Pop the top page
await navigation.PopModalAsync();
// We need to use the navigation of the new top page from here on
navigation = parentPage?.Navigation;
}
// When the target page was not found, throw an exception
if (!found)
{
throw new Exception("Desired page not found in modal stack");
}
}
}
Note that after we have popped the top modal page from the stack, we have to use the Navigation from the new top page to continue on.
Example:
Imagine we have an app with five pages: MainPage, Page1, Page2, Page3, Page4.
Mainpage has a button to open Page1 modal, Page1 has a button to open Page2 modal, and so on.
In MainPage:
private async void Button_Clicked(object sender, EventArgs e)
{
Page p = new Page1();
await Navigation.PushModalAsync(p);
}
In Page1:
private async void Button_Clicked(object sender, EventArgs e)
{
Page p = new Page2();
await Navigation.PushModalAsync(p);
}
And so on...
Now in Page4 instead (in order to go back to Page2) we use the following code to close all open modal pages until we reach Page2.
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.UnwindModalStackTo<Page2>();
}
RemovePage only supports removing of specified page from NavigationStack.
Like this: Navigation.RemovePage(Navigation.NavigationStack[Navigation.NavigationStack.Count - 1]);
You can refer this for more detail:
https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.inavigation?view=xamarin-forms
If you want to go 2 pages back this will work
Navigation.RemovePage(Navigation.NavigationStack[Navigation.NavigationStack.Count - 2]);
Navigation.RemovePage(this);
First we remove the page before the current page and then the current page.
Please use await Navigation.PopModalAsync() and read through this link to get info about ModalPages.
EDIT:
Haven't tested it, but could help to understand the approach:
for (var i = Navigation.NavigationStack.Count - 1; i > 0; i--)
{
if (Navigation.NavigationStack[i] is Page2)
{
return;
}
await Navigation.PopModalAsync();
}

Cannot find definition of "this.startup" in windows phone 8.1 app

I am trying to implement parse in a windows phone 8.1 application and I am using this as my guide. In the code, this.Startup isn't recognized.
I am using a Windows phone 8.1 app and Not a silverlight app. So will parse notification work for only Silverlight apps and not Windows Phone 8.1 apps ?
I am providing the code below :
this.Startup += async (sender, args) =>
{
// This optional line tracks statistics around app opens, including push effectiveness:
ParseAnalytics.TrackAppOpens(RootFrame);
// By convention, the empty string is considered a "Broadcast" channel
// Note that we had to add "async" to the definition to use the await keyword
await ParsePush.SubscribeAsync("");
};
Update
namespace App2
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public sealed partial class App : Application
{
private TransitionCollection transitions;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += this.OnSuspending;
//Parse code
ParseClient.Initialize("yTu3sSPuBQe8A35fA1PEEXfqjHQJ84fFoDJlHy59", "vrldzsKd7jBgCP9x3z0vY43vpygvuzdYTTeR06wZ");
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
protected async override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
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();
// TODO: change this value to a cache size that is appropriate for your application
rootFrame.CacheSize = 1;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
// TODO: Load state from previously suspended application
}
// Place the frame in the current Window
Window.Current.Content = rootFrame;
}
if (rootFrame.Content == null)
{
// Removes the turnstile navigation for startup.
if (rootFrame.ContentTransitions != null)
{
this.transitions = new TransitionCollection();
foreach (var c in rootFrame.ContentTransitions)
{
this.transitions.Add(c);
}
}
rootFrame.ContentTransitions = null;
rootFrame.Navigated += this.RootFrame_FirstNavigated;
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), e.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
await ParsePush.SubscribeAsync("");
await ParseAnalytics.TrackAppOpenedAsync(e);
// Ensure the current window is active
Window.Current.Activate();
}
This is my current code.
Now how do I actually bind the Toast alert with the notification ?
I've done the same thing in android and there the Notification has been put in a service (Broadcast receiver). How do I get the same effect in Windows ? With a BackgroundTask ?If so, how to bind parse service in a background task ?

Windows store app: Changing Background image Dynamically from code

Im working on a weather app and i want to change the background image dynamically depending on weather its sunny, cloudy and so on. I set the Background image for all the pages from App.xaml.cs as following:
rootFrame.Background = new ImageBrush
{
Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill,
ImageSource = new BitmapImage { UriSource = new Uri("ms-appx:///Assets/blueSky.jpg") }
};
I set the image in App.xaml.cs so all the pages gets the same image, and i dont need to load the image everytime. Full code of App.xaml.cs:
sealed partial class App : Application
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Invoked when the application is launched normally by the end user. Other entry points
/// will be used when the application is launched to open a specific file, to display
/// search results, and so forth.
/// </summary>
/// <param name="args">Details about the launch request and process.</param>
protected async override void OnLaunched(LaunchActivatedEventArgs args)
{
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();
// Her we set the application background Image for all pages
rootFrame.Background = new ImageBrush
{
Stretch = Windows.UI.Xaml.Media.Stretch.UniformToFill,
ImageSource = new BitmapImage { UriSource = new Uri("ms-appx:///Assets/blueSky.jpg") }
};
weather.Common.SuspensionManager.RegisterFrame(rootFrame, "appFrame");
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
await weather.Common.SuspensionManager.RestoreAsync();
}
// 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
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
// Ensure the current window is active
Window.Current.Activate();
}
/// <summary>
/// Invoked when application execution is being suspended. Application state is saved
/// without knowing whether the application will be terminated or resumed with the contents
/// of memory still intact.
/// </summary>
/// <param name="sender">The source of the suspend request.</param>
/// <param name="e">Details about the suspend request.</param>
private async void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Save application state and stop any background activity
await weather.Common.SuspensionManager.SaveAsync();
deferral.Complete();
}
}
This works fine for 1 image, but i cant auto change the image. Any ideas?
Where is the code where you get the weather from a web service? In that code, get the current weather and then, based on the forecast, set the background picture.

WinRT Settings Popup implemented in base class isn't visible?

I'm trying to make a Setting flyout easily accessible in all pages. I looked at the Settings example at http://code.msdn.microsoft.com/windowsapps/App-settings-sample-1f762f49/sourcecode?fileId=50851&pathId=2033699455.
However there are about a dozen functions and it's just dumb to have to copy/paste/maintain an undetermined number of copies of the same code in each page. So I took the code for the popup and put it in a base class that inherits from LayoutAwarePage base class. My pages then inherit from this new class. Ex:
// Base class declaration that includes settings flyout code
public class SettingsFlyoutAwarePage : myApp.Common.LayoutAwarePage
{
// Settings flyout code here
}
// Page declaration
public sealed partial class GroupedItemsPage : myApp.Common.SettingsFlyoutAwarePage
{
// Standard working page stuff here
}
Here is the actual code to create popup that IS being called and executed in the SettingsFlyoutAwarePage base class, which is identical to the sample code, but nothing actually appears on screen:
void onSettingsCommand(IUICommand command)
{
// Create a Popup window which will contain our flyout.
settingsPopup = new Popup();
settingsPopup.Closed += OnPopupClosed;
Window.Current.Activated += OnWindowActivated;
settingsPopup.IsLightDismissEnabled = true;
settingsPopup.Width = settingsWidth;
settingsPopup.Height = windowBounds.Height;
// Add the proper animation for the panel.
settingsPopup.ChildTransitions = new TransitionCollection();
settingsPopup.ChildTransitions.Add(new PaneThemeTransition()
{
Edge = (SettingsPane.Edge == SettingsEdgeLocation.Right) ?
EdgeTransitionLocation.Right :
EdgeTransitionLocation.Left
});
// Create a SettingsFlyout the same dimenssions as the Popup.
SettingsFlyout mypane = new SettingsFlyout();
mypane.Width = settingsWidth;
mypane.Height = windowBounds.Height;
// Place the SettingsFlyout inside our Popup window.
settingsPopup.Child = mypane;
// Let's define the location of our Popup.
settingsPopup.SetValue(Canvas.LeftProperty, SettingsPane.Edge == SettingsEdgeLocation.Right ? (windowBounds.Width - settingsWidth) : 0);
settingsPopup.SetValue(Canvas.TopProperty, 0);
settingsPopup.IsOpen = true;
}
While I can step through all the code and it all appears to execute just fine, I never actually see the flyout appear. Is it at least theoretically possible to do this from an inherited base class?
Did you implement the onCommandsRequested function as described in demo?
void onCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs eventArgs)
{
UICommandInvokedHandler handler = new UICommandInvokedHandler(onSettingsCommand);
SettingsCommand generalCommand = new SettingsCommand("DefaultsId", "Defaults", handler);
eventArgs.Request.ApplicationCommands.Add(generalCommand);
}
If this helps anyone, here is a Settings flyout-aware class that you can inherit your XAML pages from. Of course you still have to implement the popup itself (demo code link)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.ApplicationSettings;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;
namespace MyApp.Common
{
[Windows.Foundation.Metadata.WebHostHidden]
public class MyAppBasePage : MyApp.Common.LayoutAwarePage
{
public MyAppBasePage()
{
}
private bool isSettingCharmEventRegistered;
// Used to determine the correct height to ensure our custom UI fills the screen.
private Rect windowBounds;
// Desired width for the settings UI. UI guidelines specify this should be 346 or 646 depending on your needs.
private double settingsWidth = 646;
// This is the container that will hold our custom content.
private Popup settingsPopup;
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// Added to make sure the event handler for CommandsRequested is cleaned up before other scenarios.
if (this.isSettingCharmEventRegistered)
{
SettingsPane.GetForCurrentView().CommandsRequested -= onCommandsRequested;
this.isSettingCharmEventRegistered = false;
}
// Unregister the event that listens for events when the window size is updated.
Window.Current.SizeChanged -= OnWindowSizeChanged;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
windowBounds = Window.Current.Bounds;
// Added to listen for events when the window size is updated.
Window.Current.SizeChanged += OnWindowSizeChanged;
// Added to make sure the event handler for CommandsRequested is cleaned up before other scenarios.
if (!this.isSettingCharmEventRegistered)
{
SettingsPane.GetForCurrentView().CommandsRequested += onCommandsRequested;
this.isSettingCharmEventRegistered = true;
}
}
/// <summary>
/// Invoked when the window size is updated.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void OnWindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
windowBounds = Window.Current.Bounds;
}
/// <summary>
/// We use the window's activated event to force closing the Popup since a user maybe interacted with
/// something that didn't normally trigger an obvious dismiss.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
private void OnWindowActivated(object sender, Windows.UI.Core.WindowActivatedEventArgs e)
{
if (e.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.Deactivated)
{
settingsPopup.IsOpen = false;
}
}
/// <summary>
/// When the Popup closes we no longer need to monitor activation changes.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="e">Event data describing the conditions that led to the event.</param>
void OnPopupClosed(object sender, object e)
{
Window.Current.Activated -= OnWindowActivated;
}
/// <summary>
/// This event is generated when the user opens the settings pane. During this event, append your
/// SettingsCommand objects to the available ApplicationCommands vector to make them available to the
/// SettingsPange UI.
/// </summary>
/// <param name="settingsPane">Instance that triggered the event.</param>
/// <param name="eventArgs">Event data describing the conditions that led to the event.</param>
void onCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs eventArgs)
{
UICommandInvokedHandler handler = new UICommandInvokedHandler(onSettingsCommand);
SettingsCommand generalCommand = new SettingsCommand("DefaultsId", "Defaults", handler);
eventArgs.Request.ApplicationCommands.Add(generalCommand);
}
/// <summary>
/// This the event handler for the "Defaults" button added to the settings charm. This method
/// is responsible for creating the Popup window will use as the container for our settings Flyout.
/// The reason we use a Popup is that it gives us the "light dismiss" behavior that when a user clicks away
/// from our custom UI it just dismisses. This is a principle in the Settings experience and you see the
/// same behavior in other experiences like AppBar.
/// </summary>
/// <param name="command"></param>
void onSettingsCommand(IUICommand command)
{
// Create a Popup window which will contain our flyout.
settingsPopup = new Popup();
settingsPopup.Closed += OnPopupClosed;
Window.Current.Activated += OnWindowActivated;
settingsPopup.IsLightDismissEnabled = true;
settingsPopup.Width = settingsWidth;
settingsPopup.Height = windowBounds.Height;
// Add the proper animation for the panel.
settingsPopup.ChildTransitions = new TransitionCollection();
settingsPopup.ChildTransitions.Add(new PaneThemeTransition()
{
Edge = (SettingsPane.Edge == SettingsEdgeLocation.Right) ?
EdgeTransitionLocation.Right :
EdgeTransitionLocation.Left
});
// Create a SettingsFlyout the same dimenssions as the Popup.
SettingsFlyout mypane = new SettingsFlyout();
mypane.Width = settingsWidth;
mypane.Height = windowBounds.Height;
// Place the SettingsFlyout inside our Popup window.
settingsPopup.Child = mypane;
// Let's define the location of our Popup.
settingsPopup.SetValue(Canvas.LeftProperty, SettingsPane.Edge == SettingsEdgeLocation.Right ? (windowBounds.Width - settingsWidth) : 0);
settingsPopup.SetValue(Canvas.TopProperty, 0);
settingsPopup.IsOpen = true;
}
}
}

Categories

Resources