We have a C# Container, a Windows.Form.WebBrowser Class is the called, on a website that has no vertical scrolling (only horizontal).
Scrolling works great in Internet Explorer, Chrome, and Firefox with the touch screen, however when the website is launched inside the Windows.Form.WebBrowser the touch scrolling does not work. It registers the touch/drag event like a left click and drag without grabbing the website.
It will also select the text on the website below.
We created a sample site to demonstrate the issue:
Test website with side scroll. On a touch screen drag and scroll works
namespace WindowsFormsApplication1
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.webBrowser1 = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
//
// webBrowser1
//
this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser1.Location = new System.Drawing.Point(0, 0);
this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20);
this.webBrowser1.Name = "webBrowser1";
this.webBrowser1.ScrollBarsEnabled = false;
this.webBrowser1.Size = new System.Drawing.Size(2419, 1088);
this.webBrowser1.TabIndex = 0;
this.webBrowser1.Url = new System.Uri("https://beta.slimcrm.com/sideScrollTest.html", System.UriKind.Absolute);
this.webBrowser1.AllowNavigation = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(16F, 31F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(2419, 1088);
this.Controls.Add(this.webBrowser1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.WebBrowser webBrowser1;
}
}
We have 2 developers who have searched for 2 days through this site and the internet but nothing we try seems to allow the C# Windows.Form.WebBrowser to register the touch events and drag the website to the left.
We believe it has to be tied to the C#, because the drag events on the touch screen work great in all web browsers. Framework for the site is Knockout.js, Restful API, all within a C# Container.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 15 days ago.
Improve this question
I just started to learn how to draw using the Graphics class in C# but there is this one error in my project in a script called ,"Form1.Designer.cs". Here is the code:
namespace Pong
{
partial class FrmMain
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// FrmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
this.ClientSize = new System.Drawing.Size(1008, 729);
this.Name = "FrmMain";
this.Text = "PONG";
this.Load += new System.EventHandler(this.FrmMain_Load);
this.ResumeLayout(false);
}
#endregion
}
}
The Line that has "this.Load += new System.EventHandler(this.FrmMain_Load);" is the part that is the error. This is the error code I got in the output:
I have a script that makes the graphic called ,"Form1.cs" ,that calls the InitializeComponent() function:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Pong
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Brush whiteBrush = new SolidBrush(Color.White);
g.FillRectangle(whiteBrush, 50, 50, 100, 100);
}
}
}
I am not the best at debugging, so if anyone could debug this glitch it would be very helpful. Thank you!
The error message is telling you exactly what the problem is. Your designer code is trying to register a handler for the form's Load event but there is no method with the specified name. Why is that the case in the first place? I'm guessing that you deleted that method while it was still registered as an event handler. Don't do that because this is what happens. If you want to delete an event handler then you have to remove the registration first, which you do in the Properties window of the designer.
Now that you're in this situation, you can just delete that line from the designer code file and that will fix the issue. If you don't try to register a nonexistent method as an event handler then you won't have that problem.
Not sure if the title makes sense.
I have a form that has several panels that each has a form associated with them.
I call this form the "mainForm", and when I move/drag it across my screen it lags a lot, the mouse also feels extremely unresponsive.
When you first open it and it doesn't lag at all, however after having some controls on screen it lag becomes noticeable and when I have over 100 controls it becomes very laggy. IF I don't move it, the program runs fine and everything in itself is good, it's only when I try to move it.
I'm not entirely sure how this works, but when you move it, does it recalculate something on the form and the controls and are on it? If so is it possible to disable that when trying to move and reenabling it when we stopped moving?
Changing to WPF at this point is not possible due to time constraints.
Hopefully, someone has had an issue like this before.
Any tips are extremely appreciated.
Thank you for your time guys!
I ended up solving it. The issue was happening even with the code that Morten Bork shared. It was simply too many controls (I had about 500 controls in the test I did) and the form was going crazy slow when moved.
The user Jimi input on the matter was key, after looking around in the events I tried the following and it solved my issue. So hopefully someone that needs a solution for something similar can use my solution.
In my "mainForm" when it moves I clear the main panel I have in "ResizeBegin" and add the sub panels back to the main panel in "ResizeEnd" and it works flawlessly so far. Since I also saved the current sub panel being displayed I can make that one display first.
I once created this in winforms:
public class FormExt : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private IContainer components;
private readonly TableLayoutPanel tlp = new TableLayoutPanel();
public FormExt(IFormExtension formExtension)
{
FormExtension = formExtension;
InitializeComponent();
}
public FormExt()
{
InitializeComponent();
}
public Panel LowerLeft { get; set; }
public BorderedPanel LowerRight { get; set; }
public Panel UpperLeft { get; set; }
public IFormExtension FormExtension { get; set; }
public virtual void FormExtended_Closing(object sender, CancelEventArgs e)
{
if (FormExtension.Parent != null)
{
FormExtension.Parent.Refresh();
FormExtension.Parent.Show();
}
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && components != null) components.Dispose();
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//TableLayoutPanel
tlp.Location = new Point(0, 0);
tlp.Dock = DockStyle.Fill;
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F));
tlp.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize, 500F));
tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
tlp.RowStyles.Add(new RowStyle(SizeType.AutoSize, 550F));
tlp.CellBorderStyle = TableLayoutPanelCellBorderStyle.None;
tlp.BorderStyle = BorderStyle.None;
tlp.Margin = new Padding(0);
tlp.Padding = new Padding(0);
//Upper background color
Color myRgbColor = new Color();
#if DEBUG
myRgbColor = Color.FromArgb(255, 0, 0);
#else
myRgbColor = Color.FromArgb(10, 19, 39);
#endif
//LowerLeft
LowerLeft = new Panel();
LowerLeft.BackColor = Color.White;
LowerLeft.Dock = DockStyle.Fill;
//UpperLeft
UpperLeft = new Panel();
UpperLeft.BackColor = myRgbColor;
UpperLeft.BackgroundImageLayout = ImageLayout.None;
UpperLeft.Dock = DockStyle.Fill;
//LowerRight
LowerRight = new BorderedPanel();
LowerRight.Size = new Size(600, 550);
LowerRight.BackColor = Color.White;
LowerRight.Dock = DockStyle.Fill;
components = new System.ComponentModel.Container();
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
FormClosing += FormExtended_Closing;
Text = "";
this.Controls.Add(tlp);
tlp.SetColumnSpan(UpperLeft, 2);
LowerLeft.Margin = new Padding(0);
LowerLeft.Padding = new Padding(0);
tlp.Controls.Add(LowerLeft, 0, 1);
UpperLeft.Margin = new Padding(0);
UpperLeft.Padding = new Padding(0);
tlp.Controls.Add(UpperLeft, 0, 0);
LowerRight.Margin = new Padding(0);
LowerRight.Padding = new Padding(0);
tlp.Controls.Add(LowerRight, 1, 1);
}
#endregion
}
To be a template for a layout.
And then I would add buttons on the left lower, content in lowerright, and upper left and right for a logo and some possible page mechanics like filter lists etc.
The nice concept is you have on 1 active form at a time. And while the otherforms by still exist in memory, they remain inactive, don't receive events unless you deliberately pass them. As far as I know. I at least, have never had the issue you describe using this component. But I never loaded "hundreds of controls" at the same time, on the same form. That is just ... to much responsibility for a single form to have.
The formExtension interface:
public interface IFormExtension
{
public Form Parent { get; set; }
}
This is just one way of creating multiple forms, that each have their own "table-layout" you can either overload this particular layout -> (Or the one you have made)
Or you can simple redefine a new layout placed in a TableLayoutPanel, and then your form should work as intended.
I had the same problem, and I found a workaround but it doesn't make sense.
I overrode the WndProc to see what messages were being sent during the form movement that might be slowing it down. 5 messages cycle through while moving the form:
3: WM_MOVE
534: WM_MOVING
70: WM_WINDOWPOSCHANGING
36: WM_GETMINMAXINFO
71: WM_WINDOWPOSCHANGED
At first, the only Windows message that I suspected could require heavy processing with a lot of controls is WM_GETMINMAXINFO, because it might be evaluating the size of controls, and would take longer for more controls.
Surprisingly, the override and addition of a Debug.WriteLine statement was enough to remove the lag altogether.
protected override void WndProc(ref Message m)
{
Debug.WriteLine($"msg: {message.Msg}, wparam:{message.WParam}, lparam:{message.LParam}, lparam:{message.HWnd}");
base.WndProc(ref m);
}
The presence of the Debug.WriteLine statement seems to change the behavior of the method such that the form moves smoothly with no lag. If I compile in release mode or comment out the Debug statement, then the form lags again. It doesn't make much sense.
UPDATE/SOLUTION: New info. This lag occurs only when dragging the form with my Rival 650 Wireless mouse. It does not lag when I drag the window with the mouse pad built into the laptop. Perhaps the mouse driver is doing something goofy or it's producing mouse move events too rapidly, and somehow the addition of a debug statement slows things down enough to disrupt the lag.
If I lower the polling rate of the mouse from 1000hz to 500hz there is still lag, but if I lower it to 250hz then the window dragging lag disappears altogether. So this seems to be caused by the high polling/event rate of the mouse and the way Windows handles the events.
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.
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;
}
}
}