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();
}
Related
Team!!
I have a website that let's people download data into an excel or pdf file. The download takes long enough that I want to display a "Please Wait" modal while the processing is happening. I found some code that does this, but the problem is it just counts from 1 to 100 and then quits. I'd like to alter that so that it displays until the download is complete.
When the use clicks the button to begin the export, the expot_click function is called. The WorkerMethod function below it gets passed into the class and is where the count from 1 to 100 is occurring. I'm not sure what to change, or where to change it.
protected void export_click(object sender, EventArgs e)
{
string exportType = hidExportType.Value;
string exportSections = hidSections.Value;
string exportStudents = hidStudents.Value;
//Display a "Please Wait" message while the download is happening
object result = WaitWindow.Show(this.WorkerMethod);
switch (exportType)
{
case "csv":
export_csv(exportSections, exportStudents);
break;
case "excel":
export_excel(exportSections, exportStudents);
break;
case "pdf":
export_pdf(exportSections, exportStudents);
break;
default:
break;
}
//I'm guessing here is where I'd want to do something to make the wait display quit?
}
private void WorkerMethod(object sender, Jacksonsoft.WaitWindowEventArgs e)
{
// Do something
for (int progress = 1; progress <= 100; progress++)
{
System.Threading.Thread.Sleep(20);
// Update the wait window message
e.Window.Message = string.Format
("Please wait ... {0}%", progress.ToString().PadLeft(3));
}
// Use the arguments sent in
if (e.Arguments.Count > 0)
{
// Set the result to return
e.Result = e.Arguments[0].ToString();
}
else
{
// Set the result to return
e.Result = "Hello World";
}
}
Below is the class that gets called:
/*
* Created by SharpDevelop.
* User: mjackson
* Date: 05/03/2010
* Time: 09:36
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Jacksonsoft
{
/// <summary>
/// Displays a window telling the user to wait while a process is executing.
/// </summary>
public class WaitWindow
{
/// <summary>
/// Shows a wait window with the text 'Please wait...' while executing the passed method.
/// </summary>
/// <param name="workerMethod">Pointer to the method to execute while displaying the wait window.</param>
/// <returns>The result argument from the worker method.</returns>
public static object Show(EventHandler<WaitWindowEventArgs> workerMethod){
return WaitWindow.Show(workerMethod, null);
}
/// <summary>
/// Shows a wait window with the specified text while executing the passed method.
/// </summary>
/// <param name="workerMethod">Pointer to the method to execute while displaying the wait window.</param>
/// <param name="message">The text to display.</param>
/// <returns>The result argument from the worker method.</returns>
public static object Show(EventHandler<WaitWindowEventArgs> workerMethod, string message){
WaitWindow instance = new WaitWindow();
return instance.Show(workerMethod, message, new List<object>());
}
/// <summary>
/// Shows a wait window with the specified text while executing the passed method.
/// </summary>
/// <param name="workerMethod">Pointer to the method to execute while displaying the wait window.</param>
/// <param name="message">The text to display.</param>
/// <param name="args">Arguments to pass to the worker method.</param>
/// <returns>The result argument from the worker method.</returns>
public static object Show(EventHandler<WaitWindowEventArgs> workerMethod, string message, params object[] args){
List<object> arguments = new List<object>();
arguments.AddRange(args);
WaitWindow instance = new WaitWindow();
return instance.Show(workerMethod, message, arguments);
}
#region Instance implementation
private WaitWindow(){}
private WaitWindowGUI _GUI;
internal delegate void MethodInvoker<T>(T parameter1);
internal EventHandler<WaitWindowEventArgs> _WorkerMethod;
internal List<object> _Args;
/// <summary>
/// Updates the message displayed in the wait window.
/// </summary>
public string Message{
set{
this._GUI.Invoke(new MethodInvoker<string>(this._GUI.SetMessage), value);
}
}
/// <summary>
/// Cancels the work and exits the wait windows immediately
/// </summary>
public void Cancel(){
this._GUI.Invoke(new MethodInvoker(this._GUI.Cancel), null);
}
private object Show(EventHandler<WaitWindowEventArgs> workerMethod, string message, List<object> args){
// Validate Parameters
if (workerMethod == null){
throw new ArgumentException("No worker method has been specified.", "workerMethod");
} else {
this._WorkerMethod = workerMethod;
}
this._Args = args;
if (string.IsNullOrEmpty(message)){
message = "Please wait...";
}
// Set up the window
this._GUI = new WaitWindowGUI(this);
this._GUI.MessageLabel.Text = message;
// Call it
this._GUI.ShowDialog();
object result = this._GUI._Result;
// clean up
Exception _Error = this._GUI._Error;
this._GUI.Dispose();
// Return result or throw and exception
if (_Error != null){
throw _Error;
} else {
return result;
}
}
#endregion Instance implementation
}
}
Any suggestions on what to do to get this working would be greatly appreciated!!
You can't use a server side window.
but, what you can do is pop or display a dialog WHEN the user clicks on the button. That pop dialog will stay open while the web page is up on the server being processed. When the server page is done, then that new fresh server page is then send back to the client side browser and thus the display message will go away on its own.
So, say your button to start process is a simple button. When clicked on that "longer" server side code runs.
So, you keep the buttion, but add a client side script to pop up a dialog message.
In this case we will use a jQuery.UI dialog.
So, you will need in the web page jQquery, and jQuery.UI.
So, now the simple button code becomes this:
<asp:Button ID="cmdBigProcess" runat="server" Text="Start the reactor!"
OnClientClick="showait();return true;"
OnClick="cmdBigProcess_Click" />
<div id="mywait" style="display:none;border:solid">
<h2>Big process running - please wait</h2>
</div>
<script>
function showait() {
// lets pop jquery.UI dialog
var mydiv = $("#mywait")
mydiv.dialog({
modal: true, appendTo: "form",
title: "Please wait", closeText: "",
width: "400px"
});
}
</script>
So, we added a simple "div" that will hold the message.
Now, when you click on the button, the "on client click" code runs FIRST, and displays the dialog, then your server side code runs. As noted, we don't have to dismiss or do anything to the dialog, since when the web page is posted, it travels up to the server. The code behind runs (may or may not change thing on the web page), and THEN when the page is done, the whole web page now travels back down to the web side, browser re-plots and re-loads the web page (this is the so called round trip, or often called the page life-cycle. it is BEYOND critical that you grasp and understand this round trip concept. Your code behind NEVER directly interacts with the user. But upon hitting a buttion, the WHOLE web page travels up to server, code runs. And EVEN when the code modifies the controls and things in the web page? They will NOT show up, NOT update, and user will not see any changes to that web page until ALL YOUR code behind is done. Once code behind is done, then the WHOLE page makes the trip back to browser and is re-loaded.
So, the re-load of the page is what in fact will case the popped up dialog to be dismissed. Note that jQuery.UI dialogs (and most web dialogs) do NOT halt code when called - code continues.
The result looks like this:
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.
I want to make a simple app that will allow me to check few parameters of every frame of preview, but I got stuck at running and stopping preview.
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
MediaCapture _MediaCapture;
bool _recording;
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.
/// This parameter is typically used to configure the page.</param>
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
var devices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
var rearCamera = devices[0];
if (devices.Count > 0)
{
rearCamera = devices.Single(currDev =>
currDev.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Back
);
}
_MediaCapture = new MediaCapture();
await _MediaCapture.InitializeAsync(new MediaCaptureInitializationSettings() { VideoDeviceId = rearCamera.Id });
// this is CaptureElement
xCapture.Source = _MediaCapture;
_recording = false;
}
protected override async void OnNavigatedFrom(NavigationEventArgs e)
{
if(_MediaCapture != null)
{
await _MediaCapture.StopPreviewAsync();
await _MediaCapture.StopRecordAsync();
_MediaCapture.Dispose();
_MediaCapture = null;
xCapture.Source = null;
}
base.OnNavigatedFrom(e);
}
// button click handler
private async void StartMeasure(object sender, RoutedEventArgs e)
{
if (_recording)
{
//await _MediaCapture.StopPreviewAsync();
_MediaCapture.VideoDeviceController.TorchControl.Enabled = false;
_recording = false;
}
else
{
//await _MediaCapture.StartPreviewAsync();
_MediaCapture.VideoDeviceController.TorchControl.Enabled = true;
_recording = true;
}
}
}
In this form it works perfectly.
If I uncomment those preview lines it works, but only once.
If I press the button three times: on, off and on again I get exception at line with enabling TorchControl.
System.Exception: Exception from HRESULT: 0xE801000D at Windows.Media.Devices.TorchControl.put_Enabled(Boolean value) at Pulsometr3.MainPage.d__d.MoveNext()
The HRESULT varies.
Whats even more weird, it sometimes freezes the phone (like 2 out of 3 times) and I need to hold Power + Volume Down.
I tried decorating all methods with [STAThread], but it didn't help (http://technet.microsoft.com/en-ca/br226599).
What's even more more interesting, when I hold operations by debbuger using F10 to step over lines I am able to toggle preview as many times as I possibly want. It's werid, since debugger hold all threads, right? So in theory there is no difference?
Also, phone sometimes freezes on deploy... And that's just annoying.
Any ideas?
I've got exactly into this...for some reason microsoft does not care much for it's successor OS to WP8, which makes me really sad. But it was also a half year ago during summer, I've tried this, maybe you can give a shot to googling on application consents and also double check your app manifests, if you have front/rear camera and webcam ticked in :) Besides that if it won't work, then bad luck, you are ought to stick with wp 8.0 version, which works exactly the same on wp 8.1 so do not worry :) also other libs like facebook stuff or parse.com won't work on wp 8.1 C# :)
I think your problem is the page cache enabled. Try to remove this line in your code this.NavigationCacheMode = NavigationCacheMode.Required;
if I understand correctly the button has a handler StartMeasure which is an async method and awaits for Start/StopPreviewAsync().
The problem might be that if you click the button more than once the one action might be still awaited(in progress) and the other one is also called, this might cause some issues because it will try to start and stop the preview at the same time which will probably lead to some race conditions.
You could check this by adding a lock to manage the access to the capture manager in order to test this. Also checking the bool and assigning it after an awaited operation is for sure not an atomic operation so that could lead to race conditions too.
private object locker;
private async void StartMeasure(object sender, RoutedEventArgs e)
{
lock (locker)
{
if (_recording)
{
await _MediaCapture.StopPreviewAsync();
}
else
{
await _MediaCapture.StartPreviewAsync();
}
_recording = !_recording;
_MediaCapture.VideoDeviceController.TorchControl.Enabled = _recording;
}
}
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.
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;
}
}
}