diff --git a/hub/apps/design/accessibility/custom-automation-peers.md b/hub/apps/design/accessibility/custom-automation-peers.md index 6cf6d02295..92d3885a82 100644 --- a/hub/apps/design/accessibility/custom-automation-peers.md +++ b/hub/apps/design/accessibility/custom-automation-peers.md @@ -461,6 +461,6 @@ More generally, be conservative with exceptions. Many clients cannot convert pro ## Related topics * [Accessibility overview](accessibility-overview.md) * [XAML accessibility sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/XAML%20accessibility%20sample) -* [**FrameworkElementAutomationPeer**](/uwp/api/Windows.UI.Xaml.Automation.Peers.FrameworkElementAutomationPeer) -* [**AutomationPeer**](/uwp/api/Windows.UI.Xaml.Automation.Peers.AutomationPeer) -* [**OnCreateAutomationPeer**](/uwp/api/windows.ui.xaml.uielement.oncreateautomationpeer) +* [**FrameworkElementAutomationPeer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Automation.Peers.FrameworkElementAutomationPeer) +* [**AutomationPeer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Automation.Peers.AutomationPeer) +* [**OnCreateAutomationPeer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.oncreateautomationpeer) diff --git a/hub/apps/design/globalizing/adjust-layout-and-fonts--and-support-rtl.md b/hub/apps/design/globalizing/adjust-layout-and-fonts--and-support-rtl.md index 18bb5dda34..156d3929bb 100644 --- a/hub/apps/design/globalizing/adjust-layout-and-fonts--and-support-rtl.md +++ b/hub/apps/design/globalizing/adjust-layout-and-fonts--and-support-rtl.md @@ -59,11 +59,11 @@ this.languageTag = Windows.Globalization.ApplicationLanguages.Languages[0]; var flowDirectionSetting = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().QualifierValues["LayoutDirection"]; if (flowDirectionSetting == "LTR") { - this.layoutRoot.FlowDirection = Windows.UI.Xaml.FlowDirection.LeftToRight; + this.layoutRoot.FlowDirection = Microsoft.UI.Xaml.FlowDirection.LeftToRight; } else { - this.layoutRoot.FlowDirection = Windows.UI.Xaml.FlowDirection.RightToLeft; + this.layoutRoot.FlowDirection = Microsoft.UI.Xaml.FlowDirection.RightToLeft; } ``` diff --git a/hub/apps/design/layout/boxpanel-example-custom-panel.md b/hub/apps/design/layout/boxpanel-example-custom-panel.md index 9283395139..b5da950300 100644 --- a/hub/apps/design/layout/boxpanel-example-custom-panel.md +++ b/hub/apps/design/layout/boxpanel-example-custom-panel.md @@ -1,236 +1,236 @@ ---- -description: Learn to write code for a custom Panel class, implementing ArrangeOverride and MeasureOverride methods, and using the Children property. -MS-HAID: dev\_ctrl\_layout\_txt.boxpanel\_example\_custom\_panel -MSHAttr: PreferredLib:/library/windows/apps -Search.Product: eADQiWindows 10XVcnh -title: "Tutorial: Create a custom panel" -ms.assetid: 981999DB-81B1-4B9C-A786-3025B62B74D6 -label: BoxPanel, an example custom panel -template: detail.hbs -op-migration-status: ready -ms.date: 09/24/2020 -ms.topic: article -keywords: windows 10, uwp -ms.localizationpriority: medium ---- -# "Tutorial: Create a custom panel - -Learn to write code for a custom [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class, implementing [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) methods, and using the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property. - -> **Important APIs**: [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel), [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride),[**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) - -The example code shows a custom panel implementation, but we don't devote a lot of time explaining the layout concepts that influence how you can customize a panel for different layout scenarios. If you want more info about these layout concepts and how they might apply to your particular layout scenario, see [XAML custom panels overview](custom-panels-overview.md). - -A *panel* is an object that provides a layout behavior for child elements it contains, when the XAML layout system runs and your app UI is rendered. You can define custom panels for XAML layout by deriving a custom class from the [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class. You provide behavior for your panel by overriding the [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) methods, supplying logic that measures and arranges the child elements. This example derives from **Panel**. When you start from **Panel**, **ArrangeOverride** and **MeasureOverride** methods don't have a starting behavior. Your code is providing the gateway by which child elements become known to the XAML layout system and get rendered in the UI. So, it's really important that your code accounts for all child elements and follows the patterns the layout system expects. - -## Your layout scenario - -When you define a custom panel, you're defining a layout scenario. - -A layout scenario is expressed through: - -- What the panel will do when it has child elements -- When the panel has constraints on its own space -- How the logic of the panel determines all the measurements, placement, positions, and sizings that eventually result in a rendered UI layout of children - -With that in mind, the `BoxPanel` shown here is for a particular scenario. In the interest of keeping the code foremost in this example, we won't explain the scenario in detail yet, and instead concentrate on the steps needed and the coding patterns. If you want to know more about the scenario first, skip ahead to ["The scenario for `BoxPanel`"](#the-scenario-for-boxpanel), and then come back to the code. - -## Start by deriving from **Panel** - -Start by deriving a custom class from [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel). Probably the easiest way to do this is to define a separate code file for this class, using the **Add** | **New Item** | **Class** context menu options for a project from the **Solution Explorer** in Microsoft Visual Studio. Name the class (and file) `BoxPanel`. - -The template file for a class doesn't start with many **using** statements because it's not specifically for Windows apps. So first, add **using** statements. The template file also starts with a few **using** statements that you probably don't need, and can be deleted. Here's a suggested list of **using** statements that can resolve types you'll need for typical custom panel code: - -```CSharp -using System; -using System.Collections.Generic; // if you need to cast IEnumerable for iteration, or define your own collection properties -using Windows.Foundation; // Point, Size, and Rect -using Windows.UI.Xaml; // DependencyObject, UIElement, and FrameworkElement -using Windows.UI.Xaml.Controls; // Panel -using Windows.UI.Xaml.Media; // if you need Brushes or other utilities -``` - -Now that you can resolve [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel), make it the base class of `BoxPanel`. Also, make `BoxPanel` public: - -```CSharp -public class BoxPanel : Panel -{ -} -``` - -At the class level, define some **int** and **double** values that will be shared by several of your logic functions, but which won't need to be exposed as public API. In the example, these are named: `maxrc`, `rowcount`, `colcount`, `cellwidth`, `cellheight`, `maxcellheight`, `aspectratio`. - -After you've done this, the complete code file looks like this (removing comments on **using**, now that you know why we have them): - -```CSharp -using System; -using System.Collections.Generic; -using Windows.Foundation; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; - -public class BoxPanel : Panel -{ - int maxrc, rowcount, colcount; - double cellwidth, cellheight, maxcellheight, aspectratio; -} -``` - -From here on out, we'll be showing you one member definition at a time, be that a method override or something supporting such as a dependency property. You can add these to the skeleton above in any order. - -## **MeasureOverride** - -```CSharp -protected override Size MeasureOverride(Size availableSize) -{ - // Determine the square that can contain this number of items. - maxrc = (int)Math.Ceiling(Math.Sqrt(Children.Count)); - // Get an aspect ratio from availableSize, decides whether to trim row or column. - aspectratio = availableSize.Width / availableSize.Height; - - // Now trim this square down to a rect, many times an entire row or column can be omitted. - if (aspectratio > 1) - { - rowcount = maxrc; - colcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc; - } - else - { - rowcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc; - colcount = maxrc; - } - - // Now that we have a column count, divide available horizontal, that's our cell width. - cellwidth = (int)Math.Floor(availableSize.Width / colcount); - // Next get a cell height, same logic of dividing available vertical by rowcount. - cellheight = Double.IsInfinity(availableSize.Height) ? Double.PositiveInfinity : availableSize.Height / rowcount; - - foreach (UIElement child in Children) - { - child.Measure(new Size(cellwidth, cellheight)); - maxcellheight = (child.DesiredSize.Height > maxcellheight) ? child.DesiredSize.Height : maxcellheight; - } - return LimitUnboundedSize(availableSize); -} -``` - -The necessary pattern of a [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) implementation is the loop through each element in [**Panel.Children**](/uwp/api/windows.ui.xaml.controls.panel.children). Always call the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) method on each of these elements. **Measure** has a parameter of type [**Size**](/uwp/api/Windows.Foundation.Size). What you're passing here is the size that your panel is committing to have available for that particular child element. So, before you can do the loop and start calling **Measure**, you need to know how much space each cell can devote. From the **MeasureOverride** method itself, you have the *availableSize* value. That is the size that the panel's parent used when it called **Measure**, which was the trigger for this **MeasureOverride** being called in the first place. So a typical logic is to devise a scheme whereby each child element divides the space of the panel's overall *availableSize*. You then pass each division of size to **Measure** of each child element. - -How `BoxPanel` divides size is fairly simple: it divides its space into a number of boxes that's largely controlled by the number of items. Boxes are sized based on row and column count and the available size. Sometimes one row or column from a square isn't needed, so it's dropped and the panel becomes a rectangle rather than square in terms of its row : column ratio. For more info about how this logic was arrived at, skip ahead to ["The scenario for BoxPanel"](#the-scenario-for-boxpanel). - -So what does the measure pass do? It sets a value for the read-only [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) property on each element where [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) was called. Having a **DesiredSize** value is possibly important once you get to the arrange pass, because the **DesiredSize** communicates what the size can or should be when arranging and in the final rendering. Even if you don't use **DesiredSize** in your own logic, the system still needs it. - -It's possible for this panel to be used when the height component of *availableSize* is unbounded. If that's true, the panel doesn't have a known height to divide. In this case, the logic for the measure pass informs each child that it doesn't have a bounded height, yet. It does so by passing a [**Size**](/uwp/api/Windows.Foundation.Size) to the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) call for children where [**Size.Height**](/uwp/api/windows.foundation.size.height) is infinite. That's legal. When **Measure** is called, the logic is that the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) is set as the minimum of these: what was passed to **Measure**, or that element's natural size from factors such as explicitly-set [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) and [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width). - -> [!NOTE] -> The internal logic of [**StackPanel**](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) also has this behavior: **StackPanel** passes an infinite dimension value to [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) on children, indicating that there is no constraint on children in the orientation dimension. **StackPanel** typically sizes itself dynamically, to accommodate all children in a stack that grows in that dimension. - -However, the panel itself can't return a [**Size**](/uwp/api/Windows.Foundation.Size) with an infinite value from [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride); that throws an exception during layout. So, part of the logic is to find out the maximum height that any child requests, and use that height as the cell height in case that isn't coming from the panel's own size constraints already. Here's the helper function `LimitUnboundedSize` that was referenced in previous code, which then takes that maximum cell height and uses it to give the panel a finite height to return, as well as assuring that `cellheight` is a finite number before the arrange pass is initiated: - -```CSharp -// This method limits the panel height when no limit is imposed by the panel's parent. -// That can happen to height if the panel is close to the root of main app window. -// In this case, base the height of a cell on the max height from desired size -// and base the height of the panel on that number times the #rows. -Size LimitUnboundedSize(Size input) -{ - if (Double.IsInfinity(input.Height)) - { - input.Height = maxcellheight * colcount; - cellheight = maxcellheight; - } - return input; -} -``` - -## **ArrangeOverride** - -```CSharp -protected override Size ArrangeOverride(Size finalSize) -{ - int count = 1; - double x, y; - foreach (UIElement child in Children) - { - x = (count - 1) % colcount * cellwidth; - y = ((int)(count - 1) / colcount) * cellheight; - Point anchorPoint = new Point(x, y); - child.Arrange(new Rect(anchorPoint, child.DesiredSize)); - count++; - } - return finalSize; -} -``` - -The necessary pattern of an [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) implementation is the loop through each element in [**Panel.Children**](/uwp/api/windows.ui.xaml.controls.panel.children). Always call the [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) method on each of these elements. - -Note how there aren't as many calculations as in [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride); that's typical. The size of children is already known from the panel's own **MeasureOverride** logic, or from the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) value of each child set during the measure pass. However, we still need to decide the location within the panel where each child will appear. In a typical panel, each child should render at a different position. A panel that creates overlapping elements isn't desirable for typical scenarios (although it's not out of the question to create panels that have purposeful overlaps, if that's really your intended scenario). - -This panel arranges by the concept of rows and columns. The number of rows and columns was already calculated (it was necessary for measurement). So now the shape of the rows and columns plus the known sizes of each cell contribute to the logic of defining a rendering position (the `anchorPoint`) for each element that this panel contains. That [**Point**](/uwp/api/Windows.Foundation.Point), along with the [**Size**](/uwp/api/Windows.Foundation.Size) already known from measure, are used as the two components that construct a [**Rect**](/uwp/api/Windows.Foundation.Rect). **Rect** is the input type for [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange). - -Panels sometimes need to clip their content. If they do, the clipped size is the size that's present in [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize), because the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) logic sets it as the minimum of what was passed to **Measure**, or other natural size factors. So you don't typically need to specifically check for clipping during [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange); the clipping just happens based on passing the **DesiredSize** through to each **Arrange** call. - -You don't always need a count while going through the loop if all the info you need for defining the rendering position is known by other means. For example, in [**Canvas**](/uwp/api/Windows.UI.Xaml.Controls.Canvas) layout logic, the position in the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) collection doesn't matter. All the info needed to position each element in a **Canvas** is known by reading [**Canvas.Left**](/dotnet/api/system.windows.controls.canvas.left) and [**Canvas.Top**](/dotnet/api/system.windows.controls.canvas.top) values of children as part of the arrange logic. The `BoxPanel` logic happens to need a count to compare to the *colcount* so it's known when to begin a new row and offset the *y* value. - -It's typical that the input *finalSize* and the [**Size**](/uwp/api/Windows.Foundation.Size) you return from a [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) implementation are the same. For more info about why, see "**ArrangeOverride**" section of [XAML custom panels overview](custom-panels-overview.md). - -## A refinement: controlling the row vs. column count - -You could compile and use this panel just as it is now. However, we'll add one more refinement. In the code just shown, the logic puts the extra row or column on the side that's longest in aspect ratio. But for greater control over the shapes of cells, it might be desirable to choose a 4x3 set of cells instead of 3x4 even if the panel's own aspect ratio is "portrait." So we'll add an optional dependency property that the panel consumer can set to control that behavior. Here's the dependency property definition, which is very basic: - -```CSharp -// Property -public Orientation Orientation -{ - get { return (Orientation)GetValue(OrientationProperty); } - set { SetValue(OrientationProperty, value); } -} - -// Dependency Property Registration -public static readonly DependencyProperty OrientationProperty = - DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(BoxPanel), new PropertyMetadata(null, OnOrientationChanged)); - -// Changed callback so we invalidate our layout when the property changes. -private static void OnOrientationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) -{ - if (dependencyObject is BoxPanel panel) - { - panel.InvalidateMeasure(); - } -} -``` - -And below is how using `Orientation` impacts the measure logic in `MeasureOverride`. Really all it's doing is changing how `rowcount` and `colcount` are derived from `maxrc` and the true aspect ratio, and there are corresponding size differences for each cell because of that. When `Orientation` is **Vertical** (default), it inverts the value of the true aspect ratio before using it for row and column counts for our "portrait" rectangle layout. - -```CSharp -// Get an aspect ratio from availableSize, decides whether to trim row or column. -aspectratio = availableSize.Width / availableSize.Height; - -// Transpose aspect ratio based on Orientation property. -if (Orientation == Orientation.Vertical) { aspectratio = 1 / aspectratio; } -``` - -## The scenario for BoxPanel - -The particular scenario for `BoxPanel` is that it's a panel where one of the main determinants of how to divide space is by knowing the number of child items, and dividing the known available space for the panel. Panels are innately rectangle shapes. Many panels operate by dividing that rectangle space into further rectangles; that's what [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid) does for its cells. In **Grid**'s case, the size of the cells is set by [**ColumnDefinition**](/uwp/api/Windows.UI.Xaml.Controls.ColumnDefinition) and [**RowDefinition**](/uwp/api/Windows.UI.Xaml.Controls.RowDefinition) values, and elements declare the exact cell they go into with [**Grid.Row**](/dotnet/api/system.windows.controls.grid.row) and [**Grid.Column**](/dotnet/api/system.windows.controls.grid.column) attached properties. Getting good layout from a **Grid** usually requires knowing the number of child elements beforehand, so that there are enough cells and each child element sets its attached properties to fit into its own cell. - -But what if the number of children is dynamic? That's certainly possible; your app code can add items to collections, in response to any dynamic run-time condition you consider to be important enough to be worth updating your UI. If you're using data binding to backing collections/business objects, getting such updates and updating the UI is handled automatically, so that's often the preferred technique (see [Data binding in depth](/windows/uwp/data-binding/data-binding-in-depth)). - -But not all app scenarios lend themselves to data binding. Sometimes, you need to create new UI elements at runtime and make them visible. `BoxPanel` is for this scenario. A changing number of child items is no problem for `BoxPanel` because it's using the child count in calculations, and adjusts both the existing and new child elements into a new layout so they all fit. - -An advanced scenario for extending `BoxPanel` further (not shown here) could both accommodate dynamic children and use a child's [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) as a stronger factor for the sizing of individual cells. This scenario might use varying row or column sizes or non-grid shapes so that there's less "wasted" space. This requires a strategy for how multiple rectangles of various sizes and aspect ratios can all fit into a containing rectangle both for aesthetics and smallest size. `BoxPanel` doesn't do that; it's using a simpler technique for dividing space. `BoxPanel`'s technique is to determine the least square number that's greater than the child count. For example, 9 items would fit in a 3x3 square. 10 items require a 4x4 square. However, you can often fit items while still removing one row or column of the starting square, to save space. In the count=10 example, that fits in a 4x3 or 3x4 rectangle. - -You might wonder why the panel wouldn't instead choose 5x2 for 10 items, because that fits the item number neatly. However, in practice, panels are sized as rectangles that seldom have a strongly oriented aspect ratio. The least-squares technique is a way to bias the sizing logic to work well with typical layout shapes and not encourage sizing where the cell shapes get odd aspect ratios. - -## Related topics - -**Reference** - -* [**FrameworkElement.ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) -* [**FrameworkElement.MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) -* [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) - -**Concepts** - -* [Alignment, margin, and padding](alignment-margin-padding.md) +--- +description: Learn to write code for a custom Panel class, implementing ArrangeOverride and MeasureOverride methods, and using the Children property. +MS-HAID: dev\_ctrl\_layout\_txt.boxpanel\_example\_custom\_panel +MSHAttr: PreferredLib:/library/windows/apps +Search.Product: eADQiWindows 10XVcnh +title: "Tutorial: Create a custom panel" +ms.assetid: 981999DB-81B1-4B9C-A786-3025B62B74D6 +label: BoxPanel, an example custom panel +template: detail.hbs +op-migration-status: ready +ms.date: 09/24/2020 +ms.topic: article +keywords: windows 10, uwp +ms.localizationpriority: medium +--- +# "Tutorial: Create a custom panel + +Learn to write code for a custom [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class, implementing [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) methods, and using the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property. + +> **Important APIs**: [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel), [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride),[**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) + +The example code shows a custom panel implementation, but we don't devote a lot of time explaining the layout concepts that influence how you can customize a panel for different layout scenarios. If you want more info about these layout concepts and how they might apply to your particular layout scenario, see [XAML custom panels overview](custom-panels-overview.md). + +A *panel* is an object that provides a layout behavior for child elements it contains, when the XAML layout system runs and your app UI is rendered. You can define custom panels for XAML layout by deriving a custom class from the [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class. You provide behavior for your panel by overriding the [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) methods, supplying logic that measures and arranges the child elements. This example derives from **Panel**. When you start from **Panel**, **ArrangeOverride** and **MeasureOverride** methods don't have a starting behavior. Your code is providing the gateway by which child elements become known to the XAML layout system and get rendered in the UI. So, it's really important that your code accounts for all child elements and follows the patterns the layout system expects. + +## Your layout scenario + +When you define a custom panel, you're defining a layout scenario. + +A layout scenario is expressed through: + +- What the panel will do when it has child elements +- When the panel has constraints on its own space +- How the logic of the panel determines all the measurements, placement, positions, and sizings that eventually result in a rendered UI layout of children + +With that in mind, the `BoxPanel` shown here is for a particular scenario. In the interest of keeping the code foremost in this example, we won't explain the scenario in detail yet, and instead concentrate on the steps needed and the coding patterns. If you want to know more about the scenario first, skip ahead to ["The scenario for `BoxPanel`"](#the-scenario-for-boxpanel), and then come back to the code. + +## Start by deriving from **Panel** + +Start by deriving a custom class from [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel). Probably the easiest way to do this is to define a separate code file for this class, using the **Add** | **New Item** | **Class** context menu options for a project from the **Solution Explorer** in Microsoft Visual Studio. Name the class (and file) `BoxPanel`. + +The template file for a class doesn't start with many **using** statements because it's not specifically for Windows apps. So first, add **using** statements. The template file also starts with a few **using** statements that you probably don't need, and can be deleted. Here's a suggested list of **using** statements that can resolve types you'll need for typical custom panel code: + +```CSharp +using System; +using System.Collections.Generic; // if you need to cast IEnumerable for iteration, or define your own collection properties +using Windows.Foundation; // Point, Size, and Rect +using Microsoft.UI.Xaml; // DependencyObject, UIElement, and FrameworkElement +using Microsoft.UI.Xaml.Controls; // Panel +using Microsoft.UI.Xaml.Media; // if you need Brushes or other utilities +``` + +Now that you can resolve [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel), make it the base class of `BoxPanel`. Also, make `BoxPanel` public: + +```CSharp +public class BoxPanel : Panel +{ +} +``` + +At the class level, define some **int** and **double** values that will be shared by several of your logic functions, but which won't need to be exposed as public API. In the example, these are named: `maxrc`, `rowcount`, `colcount`, `cellwidth`, `cellheight`, `maxcellheight`, `aspectratio`. + +After you've done this, the complete code file looks like this (removing comments on **using**, now that you know why we have them): + +```CSharp +using System; +using System.Collections.Generic; +using Windows.Foundation; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; + +public class BoxPanel : Panel +{ + int maxrc, rowcount, colcount; + double cellwidth, cellheight, maxcellheight, aspectratio; +} +``` + +From here on out, we'll be showing you one member definition at a time, be that a method override or something supporting such as a dependency property. You can add these to the skeleton above in any order. + +## **MeasureOverride** + +```CSharp +protected override Size MeasureOverride(Size availableSize) +{ + // Determine the square that can contain this number of items. + maxrc = (int)Math.Ceiling(Math.Sqrt(Children.Count)); + // Get an aspect ratio from availableSize, decides whether to trim row or column. + aspectratio = availableSize.Width / availableSize.Height; + + // Now trim this square down to a rect, many times an entire row or column can be omitted. + if (aspectratio > 1) + { + rowcount = maxrc; + colcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc; + } + else + { + rowcount = (maxrc > 2 && Children.Count <= maxrc * (maxrc - 1)) ? maxrc - 1 : maxrc; + colcount = maxrc; + } + + // Now that we have a column count, divide available horizontal, that's our cell width. + cellwidth = (int)Math.Floor(availableSize.Width / colcount); + // Next get a cell height, same logic of dividing available vertical by rowcount. + cellheight = Double.IsInfinity(availableSize.Height) ? Double.PositiveInfinity : availableSize.Height / rowcount; + + foreach (UIElement child in Children) + { + child.Measure(new Size(cellwidth, cellheight)); + maxcellheight = (child.DesiredSize.Height > maxcellheight) ? child.DesiredSize.Height : maxcellheight; + } + return LimitUnboundedSize(availableSize); +} +``` + +The necessary pattern of a [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) implementation is the loop through each element in [**Panel.Children**](/uwp/api/windows.ui.xaml.controls.panel.children). Always call the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) method on each of these elements. **Measure** has a parameter of type [**Size**](/uwp/api/Windows.Foundation.Size). What you're passing here is the size that your panel is committing to have available for that particular child element. So, before you can do the loop and start calling **Measure**, you need to know how much space each cell can devote. From the **MeasureOverride** method itself, you have the *availableSize* value. That is the size that the panel's parent used when it called **Measure**, which was the trigger for this **MeasureOverride** being called in the first place. So a typical logic is to devise a scheme whereby each child element divides the space of the panel's overall *availableSize*. You then pass each division of size to **Measure** of each child element. + +How `BoxPanel` divides size is fairly simple: it divides its space into a number of boxes that's largely controlled by the number of items. Boxes are sized based on row and column count and the available size. Sometimes one row or column from a square isn't needed, so it's dropped and the panel becomes a rectangle rather than square in terms of its row : column ratio. For more info about how this logic was arrived at, skip ahead to ["The scenario for BoxPanel"](#the-scenario-for-boxpanel). + +So what does the measure pass do? It sets a value for the read-only [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) property on each element where [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) was called. Having a **DesiredSize** value is possibly important once you get to the arrange pass, because the **DesiredSize** communicates what the size can or should be when arranging and in the final rendering. Even if you don't use **DesiredSize** in your own logic, the system still needs it. + +It's possible for this panel to be used when the height component of *availableSize* is unbounded. If that's true, the panel doesn't have a known height to divide. In this case, the logic for the measure pass informs each child that it doesn't have a bounded height, yet. It does so by passing a [**Size**](/uwp/api/Windows.Foundation.Size) to the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) call for children where [**Size.Height**](/uwp/api/windows.foundation.size.height) is infinite. That's legal. When **Measure** is called, the logic is that the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) is set as the minimum of these: what was passed to **Measure**, or that element's natural size from factors such as explicitly-set [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) and [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width). + +> [!NOTE] +> The internal logic of [**StackPanel**](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) also has this behavior: **StackPanel** passes an infinite dimension value to [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) on children, indicating that there is no constraint on children in the orientation dimension. **StackPanel** typically sizes itself dynamically, to accommodate all children in a stack that grows in that dimension. + +However, the panel itself can't return a [**Size**](/uwp/api/Windows.Foundation.Size) with an infinite value from [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride); that throws an exception during layout. So, part of the logic is to find out the maximum height that any child requests, and use that height as the cell height in case that isn't coming from the panel's own size constraints already. Here's the helper function `LimitUnboundedSize` that was referenced in previous code, which then takes that maximum cell height and uses it to give the panel a finite height to return, as well as assuring that `cellheight` is a finite number before the arrange pass is initiated: + +```CSharp +// This method limits the panel height when no limit is imposed by the panel's parent. +// That can happen to height if the panel is close to the root of main app window. +// In this case, base the height of a cell on the max height from desired size +// and base the height of the panel on that number times the #rows. +Size LimitUnboundedSize(Size input) +{ + if (Double.IsInfinity(input.Height)) + { + input.Height = maxcellheight * colcount; + cellheight = maxcellheight; + } + return input; +} +``` + +## **ArrangeOverride** + +```CSharp +protected override Size ArrangeOverride(Size finalSize) +{ + int count = 1; + double x, y; + foreach (UIElement child in Children) + { + x = (count - 1) % colcount * cellwidth; + y = ((int)(count - 1) / colcount) * cellheight; + Point anchorPoint = new Point(x, y); + child.Arrange(new Rect(anchorPoint, child.DesiredSize)); + count++; + } + return finalSize; +} +``` + +The necessary pattern of an [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) implementation is the loop through each element in [**Panel.Children**](/uwp/api/windows.ui.xaml.controls.panel.children). Always call the [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) method on each of these elements. + +Note how there aren't as many calculations as in [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride); that's typical. The size of children is already known from the panel's own **MeasureOverride** logic, or from the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) value of each child set during the measure pass. However, we still need to decide the location within the panel where each child will appear. In a typical panel, each child should render at a different position. A panel that creates overlapping elements isn't desirable for typical scenarios (although it's not out of the question to create panels that have purposeful overlaps, if that's really your intended scenario). + +This panel arranges by the concept of rows and columns. The number of rows and columns was already calculated (it was necessary for measurement). So now the shape of the rows and columns plus the known sizes of each cell contribute to the logic of defining a rendering position (the `anchorPoint`) for each element that this panel contains. That [**Point**](/uwp/api/Windows.Foundation.Point), along with the [**Size**](/uwp/api/Windows.Foundation.Size) already known from measure, are used as the two components that construct a [**Rect**](/uwp/api/Windows.Foundation.Rect). **Rect** is the input type for [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange). + +Panels sometimes need to clip their content. If they do, the clipped size is the size that's present in [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize), because the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) logic sets it as the minimum of what was passed to **Measure**, or other natural size factors. So you don't typically need to specifically check for clipping during [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange); the clipping just happens based on passing the **DesiredSize** through to each **Arrange** call. + +You don't always need a count while going through the loop if all the info you need for defining the rendering position is known by other means. For example, in [**Canvas**](/uwp/api/Windows.UI.Xaml.Controls.Canvas) layout logic, the position in the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) collection doesn't matter. All the info needed to position each element in a **Canvas** is known by reading [**Canvas.Left**](/dotnet/api/system.windows.controls.canvas.left) and [**Canvas.Top**](/dotnet/api/system.windows.controls.canvas.top) values of children as part of the arrange logic. The `BoxPanel` logic happens to need a count to compare to the *colcount* so it's known when to begin a new row and offset the *y* value. + +It's typical that the input *finalSize* and the [**Size**](/uwp/api/Windows.Foundation.Size) you return from a [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) implementation are the same. For more info about why, see "**ArrangeOverride**" section of [XAML custom panels overview](custom-panels-overview.md). + +## A refinement: controlling the row vs. column count + +You could compile and use this panel just as it is now. However, we'll add one more refinement. In the code just shown, the logic puts the extra row or column on the side that's longest in aspect ratio. But for greater control over the shapes of cells, it might be desirable to choose a 4x3 set of cells instead of 3x4 even if the panel's own aspect ratio is "portrait." So we'll add an optional dependency property that the panel consumer can set to control that behavior. Here's the dependency property definition, which is very basic: + +```CSharp +// Property +public Orientation Orientation +{ + get { return (Orientation)GetValue(OrientationProperty); } + set { SetValue(OrientationProperty, value); } +} + +// Dependency Property Registration +public static readonly DependencyProperty OrientationProperty = + DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(BoxPanel), new PropertyMetadata(null, OnOrientationChanged)); + +// Changed callback so we invalidate our layout when the property changes. +private static void OnOrientationChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) +{ + if (dependencyObject is BoxPanel panel) + { + panel.InvalidateMeasure(); + } +} +``` + +And below is how using `Orientation` impacts the measure logic in `MeasureOverride`. Really all it's doing is changing how `rowcount` and `colcount` are derived from `maxrc` and the true aspect ratio, and there are corresponding size differences for each cell because of that. When `Orientation` is **Vertical** (default), it inverts the value of the true aspect ratio before using it for row and column counts for our "portrait" rectangle layout. + +```CSharp +// Get an aspect ratio from availableSize, decides whether to trim row or column. +aspectratio = availableSize.Width / availableSize.Height; + +// Transpose aspect ratio based on Orientation property. +if (Orientation == Orientation.Vertical) { aspectratio = 1 / aspectratio; } +``` + +## The scenario for BoxPanel + +The particular scenario for `BoxPanel` is that it's a panel where one of the main determinants of how to divide space is by knowing the number of child items, and dividing the known available space for the panel. Panels are innately rectangle shapes. Many panels operate by dividing that rectangle space into further rectangles; that's what [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid) does for its cells. In **Grid**'s case, the size of the cells is set by [**ColumnDefinition**](/uwp/api/Windows.UI.Xaml.Controls.ColumnDefinition) and [**RowDefinition**](/uwp/api/Windows.UI.Xaml.Controls.RowDefinition) values, and elements declare the exact cell they go into with [**Grid.Row**](/dotnet/api/system.windows.controls.grid.row) and [**Grid.Column**](/dotnet/api/system.windows.controls.grid.column) attached properties. Getting good layout from a **Grid** usually requires knowing the number of child elements beforehand, so that there are enough cells and each child element sets its attached properties to fit into its own cell. + +But what if the number of children is dynamic? That's certainly possible; your app code can add items to collections, in response to any dynamic run-time condition you consider to be important enough to be worth updating your UI. If you're using data binding to backing collections/business objects, getting such updates and updating the UI is handled automatically, so that's often the preferred technique (see [Data binding in depth](/windows/uwp/data-binding/data-binding-in-depth)). + +But not all app scenarios lend themselves to data binding. Sometimes, you need to create new UI elements at runtime and make them visible. `BoxPanel` is for this scenario. A changing number of child items is no problem for `BoxPanel` because it's using the child count in calculations, and adjusts both the existing and new child elements into a new layout so they all fit. + +An advanced scenario for extending `BoxPanel` further (not shown here) could both accommodate dynamic children and use a child's [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) as a stronger factor for the sizing of individual cells. This scenario might use varying row or column sizes or non-grid shapes so that there's less "wasted" space. This requires a strategy for how multiple rectangles of various sizes and aspect ratios can all fit into a containing rectangle both for aesthetics and smallest size. `BoxPanel` doesn't do that; it's using a simpler technique for dividing space. `BoxPanel`'s technique is to determine the least square number that's greater than the child count. For example, 9 items would fit in a 3x3 square. 10 items require a 4x4 square. However, you can often fit items while still removing one row or column of the starting square, to save space. In the count=10 example, that fits in a 4x3 or 3x4 rectangle. + +You might wonder why the panel wouldn't instead choose 5x2 for 10 items, because that fits the item number neatly. However, in practice, panels are sized as rectangles that seldom have a strongly oriented aspect ratio. The least-squares technique is a way to bias the sizing logic to work well with typical layout shapes and not encourage sizing where the cell shapes get odd aspect ratios. + +## Related topics + +**Reference** + +* [**FrameworkElement.ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) +* [**FrameworkElement.MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) +* [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) + +**Concepts** + +* [Alignment, margin, and padding](alignment-margin-padding.md) diff --git a/hub/apps/develop/camera/basic-photo-capture.md b/hub/apps/develop/camera/basic-photo-capture.md index 72abb52745..6197ec92ce 100644 --- a/hub/apps/develop/camera/basic-photo-capture.md +++ b/hub/apps/develop/camera/basic-photo-capture.md @@ -1,104 +1,104 @@ ---- -title: Basic photo, video, and audio capture with MediaCapture -description: Learn how to capture photos and video using the MediaCapture class. -ms.topic: article -ms.date: 07/23/2024 -ms.author: drewbat -author: drewbatgit -ms.localizationpriority: medium -#customer intent: As a developer, I want to access the camera in a Windows app using WinUI. ---- - -# Basic photo, video, and audio capture with MediaCapture in a WinUI 3 app - -This article shows the simplest way to capture photos and video using the [**MediaCapture**](/uwp/api/Windows.Media.Capture.MediaCapture) class. The **MediaCapture** class exposes a robust set of APIs that provide low-level control over the capture pipeline and enable advanced capture scenarios, but this article is intended to help you add basic media capture to your app quickly and easily. To learn about more of the features that **MediaCapture** provides, see [**Camera**](camera.md). - -## Initialize the MediaCapture object - -All of the capture methods described in this article require the first step of initializing the [**MediaCapture**](/uwp/api/Windows.Media.Capture.MediaCapture) object. This includes instantiating the object, selecting a capture device, setting initialization parameters, and then calling [**InitializeAsync**](/uwp/api/windows.media.capture.mediacapture.initializeasync). Typically camera apps will display the camera preview while capturing photos or video in their UI using the [MediaPlayerElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.mediaplayerelement). For a walkthrough of initializing **MediaCapture** and showing the preview in a XAML UI, see [Show the camera preview in a WinUI app](camera-quickstart-winui3.md). The code examples in this article will assume that an initialized instance of **MediaCapture** has already been created. - -## Capture a photo to a SoftwareBitmap - -The [**SoftwareBitmap**](/uwp/api/Windows.Graphics.Imaging.SoftwareBitmap) class provides a common representation of images across multiple features. If you want to capture a photo and then immediately use the captured image in your app, such as displaying it in XAML, instead of capturing to a file, then you should capture to a **SoftwareBitmap**. You still have the option of saving the image to disk later. - -Capture a photo to a **SoftwareBitmap** using the [**LowLagPhotoCapture**](/uwp/api/Windows.Media.Capture.LowLagPhotoCapture) class. Get an instance of this class by calling [**PrepareLowLagPhotoCaptureAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagphotocaptureasync), passing in an [**ImageEncodingProperties**](/uwp/api/Windows.Media.MediaProperties.ImageEncodingProperties) object specifying the image format you want. [**CreateUncompressed**](/uwp/api/windows.media.mediaproperties.imageencodingproperties.createuncompressed) creates an uncompressed encoding with the specified pixel format. Initiate photo capture by calling [**CaptureAsync**](/uwp/api/windows.media.capture.lowlagphotocapture.captureasync), which returns a [**CapturedPhoto**](/uwp/api/Windows.Media.Capture.CapturedPhoto) object. Get a **SoftwareBitmap** by accessing the [**Frame**](/uwp/api/windows.media.capture.capturedphoto.frame) property and then the [**SoftwareBitmap**](/uwp/api/windows.media.capture.capturedframe.softwarebitmap) property. - -You can capture multiple photos by repeatedly calling **CaptureAsync**. When you are done capturing, call [**FinishAsync**](/uwp/api/windows.media.capture.advancedphotocapture.finishasync) to shut down the **LowLagPhotoCapture** session and free up the associated resources. After calling **FinishAsync**, to begin capturing photos again you will need to call [**PrepareLowLagPhotoCaptureAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagphotocaptureasync) again to reinitialize the capture session before calling [**CaptureAsync**](/uwp/api/windows.media.capture.lowlagphotocapture.captureasync). - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraLowLagPhotoCapture"::: - -## Capture a photo to a memory stream - -You can use **MediaCapture** to capture a photo to an in-memory stream, which you can then use to transcode the photo from the stream to a file on disk. - -Create an [**InMemoryRandomAccessStream**](/uwp/api/Windows.Storage.Streams.InMemoryRandomAccessStream) and then call [**CapturePhotoToStreamAsync**](/uwp/api/windows.media.capture.mediacapture.capturephototostreamasync) to capture a photo to the stream, passing in the stream and an [**ImageEncodingProperties**](/uwp/api/Windows.Media.MediaProperties.ImageEncodingProperties) object specifying the image format that should be used. You can create custom encoding properties by initializing the object yourself, but the class provides static methods, like [**ImageEncodingProperties.CreateJpeg**](/uwp/api/windows.media.mediaproperties.imageencodingproperties.createjpeg) for common encoding formats. - -Create a [**BitmapDecoder**](/uwp/api/Windows.Graphics.Imaging.BitmapDecoder) to decode the image from the in memory stream. Create a [**BitmapEncoder**](/uwp/api/Windows.Graphics.Imaging.BitmapEncoder) to encode the image to file by calling [**CreateForTranscodingAsync**](/uwp/api/windows.graphics.imaging.bitmapencoder.createfortranscodingasync). - -You can optionally create a [**BitmapPropertySet**](/uwp/api/Windows.Graphics.Imaging.BitmapPropertySet) object and then call [**SetPropertiesAsync**](/uwp/api/windows.graphics.imaging.bitmapproperties.setpropertiesasync) on the image encoder to include metadata about the photo in the image file. For more information about encoding properties, see [**Image metadata**](/windows/uwp/audio-video-camera/image-metadata). - -Finally, call [**FlushAsync**](/uwp/api/windows.graphics.imaging.bitmapencoder.flushasync) on the encoder object to transcode the photo from the in-memory stream to the file. - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraLowLagPhotoCapture"::: - - -## Capture a video - -Quickly add video capture to your app by using the [**LowLagMediaRecording**](/uwp/api/Windows.Media.Capture.LowLagMediaRecording) class. - -First, the **LowLagMediaRecording** needs to persist while video is being captured, so declare a class variable to for the object. - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraDeclareLowLagMediaRecording"::: - - -Call [**PrepareLowLagRecordToStorageFileAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagrecordtostoragefileasync) to initialize the media recording, passing in the storage file and a [**MediaEncodingProfile**](/uwp/api/Windows.Media.MediaProperties.MediaEncodingProfile) object specifying the encoding for the video. The class provides static methods, like [**CreateMp4**](/uwp/api/windows.media.mediaproperties.mediaencodingprofile.createmp4), for creating common video encoding profiles. Call [**StartAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.startasync) to begin capturing video. - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStartLowLagMediaRecording"::: - - -To stop recording video, call [**StopAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.stopasync). - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStopLowLagMediaRecording"::: - -You can continue to call **StartAsync** and **StopAsync** to capture additional videos. When you are done capturing videos, call [**FinishAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.finishasync) to dispose of the capture session and clean up associated resources. After this call, you must call **PrepareLowLagRecordToStorageFileAsync** again to reinitialize the capture session before calling **StartAsync**. - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraFinalizeLowLagMediaRecording"::: - -When capturing video, you should register a handler for the [**RecordLimitationExceeded**](/uwp/api/windows.media.capture.mediacapture.recordlimitationexceeded) event of the **MediaCapture** object, which will be raised by the operating system if you surpass the limit for a single recording, currently three hours. In the handler for the event, you should finalize your recording by calling [**StopAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.stopasync). - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraRecordLimitationExceeded"::: - - -You can pause a video recording and then resume recording without creating a separate output file by calling [**PauseAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.pauseasync) and then calling [**ResumeAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.resumeasync). - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraPauseVideoCapture"::: - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraResumeVideoCapture"::: - -Calling [**PauseWithResultAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.pausewithresultasync) returns a [**MediaCapturePauseResult**](/uwp/api/Windows.Media.Capture.MediaCapturePauseResult) object. The [**LastFrame**](/uwp/api/windows.media.capture.mediacapturepauseresult.lastframe) property is a [**VideoFrame**](/uwp/api/Windows.Media.VideoFrame) object representing the last frame. To display the frame in XAML, get the **SoftwareBitmap** representation of the video frame. Currently, only images in BGRA8 format with premultiplied or empty alpha channel are supported, so call [**Convert**](/uwp/api/windows.graphics.imaging.softwarebitmap.convert) if necessary to get the correct format. **PauseWithResultAsync** also returns the duration of the video that was recorded in the preceding segment in case you need to track how much total time has been recorded. - -You can also get a result frame when you stop the video by calling [**StopWithResultAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.stopwithresultasync). - -### Play and edit captured video files - -Once you have captured a video to a file, you may want to load the file and play it back within your app's UI. You can do this using the **[MediaPlayerElement](/uwp/api/Windows.UI.Xaml.Controls.MediaPlayerElement)** XAML control and an associated **[MediaPlayer](/uwp/api/windows.media.playback.mediaplayer)**. For information on playing media in a XAML page, see [Play audio and video with MediaPlayer](/windows/uwp/audio-video-camera/play-audio-and-video-with-mediaplayer). - -You can also create a **[MediaClip](/uwp/api/windows.media.editing.mediaclip)** object from a video file by calling **[CreateFromFileAsync](/uwp/api/windows.media.editing.mediaclip.createfromfileasync)**. A **[MediaComposition](/uwp/api/windows.media.editing.mediacomposition)** provides basic video editing functionality like arranging the sequence of **MediaClip** objects, trimming video length, creating layers, adding background music, and applying video effects. For more information on working with media compositions, see [Media compositions and editing](/windows/uwp/audio-video-camera/media-compositions-and-editing). - - -## Capture audio - -You can quickly add audio capture to your app by using the same technique shown above for capturing video. Call [**PrepareLowLagRecordToStorageFileAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagrecordtostoragefileasync) to initialize the capture session, passing in the file and a [**MediaEncodingProfile**](/uwp/api/Windows.Media.MediaProperties.MediaEncodingProfile) which is generated in this example by the [**CreateMp3**](/uwp/api/windows.media.mediaproperties.mediaencodingprofile.createmp3) static method. To begin recording, call [**StartAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.startasync). - - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStartAudioCapture"::: - - -Call [**StopAsync**](/uwp/api/windows.media.capture.lowlagphotosequencecapture.stopasync) to stop the audio recording. - -:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStopAudioCapture"::: - -You can call **StartAsync** and **StopAsync** multiple times to record several audio files. When you are done capturing audio, call [**FinishAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.finishasync) to dispose of the capture session and clean up associated resources. After this call, you must call **PrepareLowLagRecordToStorageFileAsync** again to reinitialize the capture session before calling **StartAsync**. - -For information about detecting when the system changes the audio level of the audio capture stream, see [Detect and respond to audio level changes by the system](detect-audio-level-changes.md). - +--- +title: Basic photo, video, and audio capture with MediaCapture +description: Learn how to capture photos and video using the MediaCapture class. +ms.topic: article +ms.date: 07/23/2024 +ms.author: drewbat +author: drewbatgit +ms.localizationpriority: medium +#customer intent: As a developer, I want to access the camera in a Windows app using WinUI. +--- + +# Basic photo, video, and audio capture with MediaCapture in a WinUI 3 app + +This article shows the simplest way to capture photos and video using the [**MediaCapture**](/uwp/api/Windows.Media.Capture.MediaCapture) class. The **MediaCapture** class exposes a robust set of APIs that provide low-level control over the capture pipeline and enable advanced capture scenarios, but this article is intended to help you add basic media capture to your app quickly and easily. To learn about more of the features that **MediaCapture** provides, see [**Camera**](camera.md). + +## Initialize the MediaCapture object + +All of the capture methods described in this article require the first step of initializing the [**MediaCapture**](/uwp/api/Windows.Media.Capture.MediaCapture) object. This includes instantiating the object, selecting a capture device, setting initialization parameters, and then calling [**InitializeAsync**](/uwp/api/windows.media.capture.mediacapture.initializeasync). Typically camera apps will display the camera preview while capturing photos or video in their UI using the [MediaPlayerElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.mediaplayerelement). For a walkthrough of initializing **MediaCapture** and showing the preview in a XAML UI, see [Show the camera preview in a WinUI app](camera-quickstart-winui3.md). The code examples in this article will assume that an initialized instance of **MediaCapture** has already been created. + +## Capture a photo to a SoftwareBitmap + +The [**SoftwareBitmap**](/uwp/api/Windows.Graphics.Imaging.SoftwareBitmap) class provides a common representation of images across multiple features. If you want to capture a photo and then immediately use the captured image in your app, such as displaying it in XAML, instead of capturing to a file, then you should capture to a **SoftwareBitmap**. You still have the option of saving the image to disk later. + +Capture a photo to a **SoftwareBitmap** using the [**LowLagPhotoCapture**](/uwp/api/Windows.Media.Capture.LowLagPhotoCapture) class. Get an instance of this class by calling [**PrepareLowLagPhotoCaptureAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagphotocaptureasync), passing in an [**ImageEncodingProperties**](/uwp/api/Windows.Media.MediaProperties.ImageEncodingProperties) object specifying the image format you want. [**CreateUncompressed**](/uwp/api/windows.media.mediaproperties.imageencodingproperties.createuncompressed) creates an uncompressed encoding with the specified pixel format. Initiate photo capture by calling [**CaptureAsync**](/uwp/api/windows.media.capture.lowlagphotocapture.captureasync), which returns a [**CapturedPhoto**](/uwp/api/Windows.Media.Capture.CapturedPhoto) object. Get a **SoftwareBitmap** by accessing the [**Frame**](/uwp/api/windows.media.capture.capturedphoto.frame) property and then the [**SoftwareBitmap**](/uwp/api/windows.media.capture.capturedframe.softwarebitmap) property. + +You can capture multiple photos by repeatedly calling **CaptureAsync**. When you are done capturing, call [**FinishAsync**](/uwp/api/windows.media.capture.advancedphotocapture.finishasync) to shut down the **LowLagPhotoCapture** session and free up the associated resources. After calling **FinishAsync**, to begin capturing photos again you will need to call [**PrepareLowLagPhotoCaptureAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagphotocaptureasync) again to reinitialize the capture session before calling [**CaptureAsync**](/uwp/api/windows.media.capture.lowlagphotocapture.captureasync). + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraLowLagPhotoCapture"::: + +## Capture a photo to a memory stream + +You can use **MediaCapture** to capture a photo to an in-memory stream, which you can then use to transcode the photo from the stream to a file on disk. + +Create an [**InMemoryRandomAccessStream**](/uwp/api/Windows.Storage.Streams.InMemoryRandomAccessStream) and then call [**CapturePhotoToStreamAsync**](/uwp/api/windows.media.capture.mediacapture.capturephototostreamasync) to capture a photo to the stream, passing in the stream and an [**ImageEncodingProperties**](/uwp/api/Windows.Media.MediaProperties.ImageEncodingProperties) object specifying the image format that should be used. You can create custom encoding properties by initializing the object yourself, but the class provides static methods, like [**ImageEncodingProperties.CreateJpeg**](/uwp/api/windows.media.mediaproperties.imageencodingproperties.createjpeg) for common encoding formats. + +Create a [**BitmapDecoder**](/uwp/api/Windows.Graphics.Imaging.BitmapDecoder) to decode the image from the in memory stream. Create a [**BitmapEncoder**](/uwp/api/Windows.Graphics.Imaging.BitmapEncoder) to encode the image to file by calling [**CreateForTranscodingAsync**](/uwp/api/windows.graphics.imaging.bitmapencoder.createfortranscodingasync). + +You can optionally create a [**BitmapPropertySet**](/uwp/api/Windows.Graphics.Imaging.BitmapPropertySet) object and then call [**SetPropertiesAsync**](/uwp/api/windows.graphics.imaging.bitmapproperties.setpropertiesasync) on the image encoder to include metadata about the photo in the image file. For more information about encoding properties, see [**Image metadata**](/windows/uwp/audio-video-camera/image-metadata). + +Finally, call [**FlushAsync**](/uwp/api/windows.graphics.imaging.bitmapencoder.flushasync) on the encoder object to transcode the photo from the in-memory stream to the file. + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraLowLagPhotoCapture"::: + + +## Capture a video + +Quickly add video capture to your app by using the [**LowLagMediaRecording**](/uwp/api/Windows.Media.Capture.LowLagMediaRecording) class. + +First, the **LowLagMediaRecording** needs to persist while video is being captured, so declare a class variable to for the object. + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraDeclareLowLagMediaRecording"::: + + +Call [**PrepareLowLagRecordToStorageFileAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagrecordtostoragefileasync) to initialize the media recording, passing in the storage file and a [**MediaEncodingProfile**](/uwp/api/Windows.Media.MediaProperties.MediaEncodingProfile) object specifying the encoding for the video. The class provides static methods, like [**CreateMp4**](/uwp/api/windows.media.mediaproperties.mediaencodingprofile.createmp4), for creating common video encoding profiles. Call [**StartAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.startasync) to begin capturing video. + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStartLowLagMediaRecording"::: + + +To stop recording video, call [**StopAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.stopasync). + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStopLowLagMediaRecording"::: + +You can continue to call **StartAsync** and **StopAsync** to capture additional videos. When you are done capturing videos, call [**FinishAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.finishasync) to dispose of the capture session and clean up associated resources. After this call, you must call **PrepareLowLagRecordToStorageFileAsync** again to reinitialize the capture session before calling **StartAsync**. + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraFinalizeLowLagMediaRecording"::: + +When capturing video, you should register a handler for the [**RecordLimitationExceeded**](/uwp/api/windows.media.capture.mediacapture.recordlimitationexceeded) event of the **MediaCapture** object, which will be raised by the operating system if you surpass the limit for a single recording, currently three hours. In the handler for the event, you should finalize your recording by calling [**StopAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.stopasync). + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraRecordLimitationExceeded"::: + + +You can pause a video recording and then resume recording without creating a separate output file by calling [**PauseAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.pauseasync) and then calling [**ResumeAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.resumeasync). + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraPauseVideoCapture"::: + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraResumeVideoCapture"::: + +Calling [**PauseWithResultAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.pausewithresultasync) returns a [**MediaCapturePauseResult**](/uwp/api/Windows.Media.Capture.MediaCapturePauseResult) object. The [**LastFrame**](/uwp/api/windows.media.capture.mediacapturepauseresult.lastframe) property is a [**VideoFrame**](/uwp/api/Windows.Media.VideoFrame) object representing the last frame. To display the frame in XAML, get the **SoftwareBitmap** representation of the video frame. Currently, only images in BGRA8 format with premultiplied or empty alpha channel are supported, so call [**Convert**](/uwp/api/windows.graphics.imaging.softwarebitmap.convert) if necessary to get the correct format. **PauseWithResultAsync** also returns the duration of the video that was recorded in the preceding segment in case you need to track how much total time has been recorded. + +You can also get a result frame when you stop the video by calling [**StopWithResultAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.stopwithresultasync). + +### Play and edit captured video files + +Once you have captured a video to a file, you may want to load the file and play it back within your app's UI. You can do this using the **[MediaPlayerElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MediaPlayerElement)** XAML control and an associated **[MediaPlayer](/uwp/api/windows.media.playback.mediaplayer)**. For information on playing media in a XAML page, see [Play audio and video with MediaPlayer](/windows/uwp/audio-video-camera/play-audio-and-video-with-mediaplayer). + +You can also create a **[MediaClip](/uwp/api/windows.media.editing.mediaclip)** object from a video file by calling **[CreateFromFileAsync](/uwp/api/windows.media.editing.mediaclip.createfromfileasync)**. A **[MediaComposition](/uwp/api/windows.media.editing.mediacomposition)** provides basic video editing functionality like arranging the sequence of **MediaClip** objects, trimming video length, creating layers, adding background music, and applying video effects. For more information on working with media compositions, see [Media compositions and editing](/windows/uwp/audio-video-camera/media-compositions-and-editing). + + +## Capture audio + +You can quickly add audio capture to your app by using the same technique shown above for capturing video. Call [**PrepareLowLagRecordToStorageFileAsync**](/uwp/api/windows.media.capture.mediacapture.preparelowlagrecordtostoragefileasync) to initialize the capture session, passing in the file and a [**MediaEncodingProfile**](/uwp/api/Windows.Media.MediaProperties.MediaEncodingProfile) which is generated in this example by the [**CreateMp3**](/uwp/api/windows.media.mediaproperties.mediaencodingprofile.createmp3) static method. To begin recording, call [**StartAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.startasync). + + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStartAudioCapture"::: + + +Call [**StopAsync**](/uwp/api/windows.media.capture.lowlagphotosequencecapture.stopasync) to stop the audio recording. + +:::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml.cs" id="SnippetCameraStopAudioCapture"::: + +You can call **StartAsync** and **StopAsync** multiple times to record several audio files. When you are done capturing audio, call [**FinishAsync**](/uwp/api/windows.media.capture.lowlagmediarecording.finishasync) to dispose of the capture session and clean up associated resources. After this call, you must call **PrepareLowLagRecordToStorageFileAsync** again to reinitialize the capture session before calling **StartAsync**. + +For information about detecting when the system changes the audio level of the audio capture stream, see [Detect and respond to audio level changes by the system](detect-audio-level-changes.md). + diff --git a/hub/apps/develop/data/drag-and-drop.md b/hub/apps/develop/data/drag-and-drop.md index 3d66a40297..ec0386e680 100644 --- a/hub/apps/develop/data/drag-and-drop.md +++ b/hub/apps/develop/data/drag-and-drop.md @@ -11,7 +11,7 @@ ms.localizationpriority: medium Drag and drop is an intuitive way to transfer data within an application or between applications on the Windows desktop. Drag and drop lets the user transfer data between applications or within an application using a standard gesture (press-hold-and-pan with the finger or press-and-pan with a mouse or a stylus). -> **Important APIs**: [CanDrag property](/uwp/api/windows.ui.xaml.uielement.candrag), [AllowDrop property](/uwp/api/windows.ui.xaml.uielement.allowdrop) +> **Important APIs**: [CanDrag property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.candrag), [AllowDrop property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.allowdrop) The drag source, which is the application or area where the drag gesture is triggered, provides the data to be transferred by filling a data package object that can contain standard data formats, including text, RTF, HTML, bitmaps, storage items or custom data formats. The source also indicates the kind of operations it supports: copy, move or link. When the pointer is released, drop occurs. The drop target, which is the application or area underneath the pointer, processes the data package and returns the type of operation it performed. @@ -22,7 +22,7 @@ Drag and drop allows data transfer between or within any kind of application, in Here's an overview of what you need to do to enable drag and drop in your app: 1. Enable dragging on an element by setting its **CanDrag** property to true. -2. Build the data package. The system handles images and text automatically, but for other content, you'll need to handle the [**DragStarting**](/uwp/api/windows.ui.xaml.uielement.dragstarting) and [**DropCompleted**](/uwp/api/windows.ui.xaml.uielement.dropcompleted) events and use them to construct your own data package. +2. Build the data package. The system handles images and text automatically, but for other content, you'll need to handle the [**DragStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragstarting) and [**DropCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dropcompleted) events and use them to construct your own data package. 3. Enable dropping by setting the **AllowDrop** property to **true** on all the elements that can receive dropped content. 4. Handle the **DragOver** event to let the system know what type of drag operations the element can receive. 5. Process the **Drop** event to receive the dropped content. @@ -31,11 +31,11 @@ Here's an overview of what you need to do to enable drag and drop in your app: ## Enable dragging -To enable dragging on an element, set its [**CanDrag**](/uwp/api/windows.ui.xaml.uielement.candrag) property to **true**. This make the element—and the elements it contains, in the case of collections like ListView—draggable. +To enable dragging on an element, set its [**CanDrag**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.candrag) property to **true**. This make the element—and the elements it contains, in the case of collections like ListView—draggable. Be specific about what's draggable. Users won't want to drag everything in your app, only certain items, such as images or text. -Here's how to set [**CanDrag**](/uwp/api/windows.ui.xaml.uielement.candrag). +Here's how to set [**CanDrag**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.candrag). ```xaml @@ -49,11 +49,11 @@ In most cases, the system will construct a data package for you. The system auto - Images - Text -For other content, you'll need to handle the [**DragStarting**](/uwp/api/windows.ui.xaml.uielement.dragstarting) and [**DropCompleted**](/uwp/api/windows.ui.xaml.uielement.dropcompleted) events and use them to construct your own [DataPackage](/uwp/api/windows.applicationmodel.datatransfer.datapackage). +For other content, you'll need to handle the [**DragStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragstarting) and [**DropCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dropcompleted) events and use them to construct your own [DataPackage](/uwp/api/windows.applicationmodel.datatransfer.datapackage). ## Enable dropping -The following markup shows how the [**AllowDrop**](/uwp/api/windows.ui.xaml.uielement.allowdrop) property can be used to specify that an area of the app is a valid drop target for a dragged item (the specified area must not have a null background, it must be able to receive pointer input, and the item cannot be dropped anywhere other than the specified area). +The following markup shows how the [**AllowDrop**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.allowdrop) property can be used to specify that an area of the app is a valid drop target for a dragged item (the specified area must not have a null background, it must be able to receive pointer input, and the item cannot be dropped anywhere other than the specified area). > [!NOTE] > Typically, a UI element has a null background by default. If you want users to be able to drop an item anywhere within your app, the app background cannot be null (set `Background="Transparent"` if the background should not be visible). @@ -67,7 +67,7 @@ The following markup shows how the [**AllowDrop**](/uwp/api/windows.ui.xaml.uiel ## Handle the DragOver event -The [**DragOver**](/uwp/api/windows.ui.xaml.uielement.dragover) event fires when a user has dragged an item over your app, but not yet dropped it. In this handler, you need to specify what kind of operations your app supports by using the [**AcceptedOperation**](/uwp/api/windows.ui.xaml.drageventargs.acceptedoperation) property. Copy is the most common. +The [**DragOver**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragover) event fires when a user has dragged an item over your app, but not yet dropped it. In this handler, you need to specify what kind of operations your app supports by using the [**AcceptedOperation**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.drageventargs.acceptedoperation) property. Copy is the most common. ```csharp private void Grid_DragOver(object sender, DragEventArgs e) @@ -78,7 +78,7 @@ private void Grid_DragOver(object sender, DragEventArgs e) ## Process the Drop event -The [**Drop**](/uwp/api/windows.ui.xaml.uielement.drop) event occurs when the user releases items in a valid drop area. Process them by using the [**DataView**](/uwp/api/windows.ui.xaml.drageventargs.dataview) property. +The [**Drop**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.drop) event occurs when the user releases items in a valid drop area. Process them by using the [**DataView**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.drageventargs.dataview) property. For simplicity in the example below, we'll assume the user dropped a single photo and access it directly. In reality, users can drop multiple items of varying formats simultaneously. Your app should handle this possibility by checking what types of files were dropped and how many there are, and process each accordingly. You should also consider notifying the user if they're trying to do something your app doesn't support. @@ -102,7 +102,7 @@ private async void Grid_Drop(object sender, DragEventArgs e) ## Customize the UI -The system provides a default UI for dragging and dropping. However, you can also choose to customize various parts of the UI by setting custom captions and glyphs, or by opting not to show a UI at all. To customize the UI, use the [**DragEventArgs.DragUIOverride**](/uwp/api/windows.ui.xaml.drageventargs.draguioverride) property. +The system provides a default UI for dragging and dropping. However, you can also choose to customize various parts of the UI by setting custom captions and glyphs, or by opting not to show a UI at all. To customize the UI, use the [**DragEventArgs.DragUIOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.drageventargs.draguioverride) property. ```csharp private void Grid_DragOverCustomized(object sender, DragEventArgs e) @@ -121,7 +121,7 @@ private void Grid_DragOverCustomized(object sender, DragEventArgs e) ## Open a context menu on an item you can drag with touch -When using touch, dragging a [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) and opening its context menu share similar touch gestures; each begins with a press and hold. Here's how the system disambiguates between the two actions for elements in your app that support both: +When using touch, dragging a [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) and opening its context menu share similar touch gestures; each begins with a press and hold. Here's how the system disambiguates between the two actions for elements in your app that support both: - If a user presses and holds an item and begins dragging it within 500 milliseconds, the item is dragged and the context menu is not shown. - If the user presses and holds but does not drag within 500 milliseconds, the context menu is opened. @@ -129,19 +129,19 @@ When using touch, dragging a [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) ## Designate an item in a ListView or GridView as a folder -You can specify a [**ListViewItem**](/uwp/api/Windows.UI.Xaml.Controls.ListViewItem) or [**GridViewItem**](/uwp/api/Windows.UI.Xaml.Controls.GridViewItem) as a folder. This is particularly useful for TreeView and File Explorer scenarios. To do so, explicitly set the [**AllowDrop**](/uwp/api/windows.ui.xaml.uielement.allowdrop) property to **True** on that item. +You can specify a [**ListViewItem**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ListViewItem) or [**GridViewItem**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.GridViewItem) as a folder. This is particularly useful for TreeView and File Explorer scenarios. To do so, explicitly set the [**AllowDrop**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.allowdrop) property to **True** on that item. -The system will automatically show the appropriate animations for dropping into a folder versus a non-folder item. Your app code must continue to handle the [**Drop**](/uwp/api/windows.ui.xaml.uielement.drop) event on the folder item (as well as on the non-folder item) in order to update the data source and add the dropped item to the target folder. +The system will automatically show the appropriate animations for dropping into a folder versus a non-folder item. Your app code must continue to handle the [**Drop**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.drop) event on the folder item (as well as on the non-folder item) in order to update the data source and add the dropped item to the target folder. ## Enable drag and drop reordering within ListViews -[**ListView**](/uwp/api/Windows.UI.Xaml.Controls.ListView)s support drag-based reordering out of the box, using an API very similar to the **CanDrop** API described in this article. At minimum, you add the **AllowDrop** and **CanReorderItems** properties. +[**ListView**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ListView)s support drag-based reordering out of the box, using an API very similar to the **CanDrop** API described in this article. At minimum, you add the **AllowDrop** and **CanReorderItems** properties. -See [**ListViewBase.CanReorderItems**](/uwp/api/windows.ui.xaml.controls.listviewbase.canreorderitems) for more information. +See [**ListViewBase.CanReorderItems**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listviewbase.canreorderitems) for more information. ## Implementing custom drag and drop -The [UIElement](/uwp/api/windows.ui.xaml.uielement) class does most of the work of implementing drag-and-drop for you. But if you want, you can implement your own version by using the APIs below. +The [UIElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement) class does most of the work of implementing drag-and-drop for you. But if you want, you can implement your own version by using the APIs below. | Functionality | Windows App SDK
Microsoft.UI.Input.DragDrop namespace | | --- | --- | @@ -153,13 +153,13 @@ The [UIElement](/uwp/api/windows.ui.xaml.uielement) class does most of the work ## See also - [App-to-app communication](../../design/input/index.md) -- [AllowDrop](/uwp/api/windows.ui.xaml.uielement.allowdrop) -- [CanDrag](/uwp/api/windows.ui.xaml.uielement.candrag) -- [DragOver](/uwp/api/windows.ui.xaml.uielement.dragover) -- [AcceptedOperation](/uwp/api/windows.ui.xaml.drageventargs.acceptedoperation) -- [DataView](/uwp/api/windows.ui.xaml.drageventargs.dataview) -- [DragUIOverride](/uwp/api/windows.ui.xaml.drageventargs.draguioverride) -- [Drop](/uwp/api/windows.ui.xaml.uielement.drop) -- [IsDragSource](/uwp/api/windows.ui.xaml.controls.listviewbase.isdragsource) -- [**DragStarting**](/uwp/api/windows.ui.xaml.uielement.dragstarting) -- [**DropCompleted**](/uwp/api/windows.ui.xaml.uielement.dropcompleted) +- [AllowDrop](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.allowdrop) +- [CanDrag](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.candrag) +- [DragOver](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragover) +- [AcceptedOperation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.drageventargs.acceptedoperation) +- [DataView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.drageventargs.dataview) +- [DragUIOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.drageventargs.draguioverride) +- [Drop](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.drop) +- [IsDragSource](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listviewbase.isdragsource) +- [**DragStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragstarting) +- [**DropCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dropcompleted) diff --git a/hub/apps/develop/input/focus-navigation.md b/hub/apps/develop/input/focus-navigation.md index bd0cc5b08c..dc710848f4 100644 --- a/hub/apps/develop/input/focus-navigation.md +++ b/hub/apps/develop/input/focus-navigation.md @@ -53,23 +53,23 @@ The 2D inner navigation region of a control, or control group, is referred to as ![directional area](images/keyboard/directional-area-small.png) *2D Inner navigation region, or directional area, of a control group* -You can use the [XYFocusKeyboardNavigation](/uwp/api/windows.ui.xaml.uielement#Windows_UI_Xaml_UIElement_XYFocusKeyboardNavigation) property (which has possible values of [Auto](/uwp/api/windows.ui.xaml.input.xyfocuskeyboardnavigationmode), [Enabled](/uwp/api/windows.ui.xaml.input.xyfocuskeyboardnavigationmode), or [Disabled](/uwp/api/windows.ui.xaml.input.xyfocuskeyboardnavigationmode)) to manage 2D inner navigation with the keyboard arrow keys. +You can use the [XYFocusKeyboardNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement#Windows_UI_Xaml_UIElement_XYFocusKeyboardNavigation) property (which has possible values of [Auto](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocuskeyboardnavigationmode), [Enabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocuskeyboardnavigationmode), or [Disabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocuskeyboardnavigationmode)) to manage 2D inner navigation with the keyboard arrow keys. > [!NOTE] -> Tab order is not affected by this property. To avoid a confusing navigation experience, we recommend that child elements of a directional area *not* be explicitly specified in the tab navigation order of your application. See the [UIElement.TabFocusNavigation](/uwp/api/windows.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) and [TabIndex](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) properties for more detail on tabbing behavior for an element. +> Tab order is not affected by this property. To avoid a confusing navigation experience, we recommend that child elements of a directional area *not* be explicitly specified in the tab navigation order of your application. See the [UIElement.TabFocusNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) and [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) properties for more detail on tabbing behavior for an element. -### [Auto](/uwp/api/windows.ui.xaml.input.xyfocuskeyboardnavigationmode) (default behavior) +### [Auto](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocuskeyboardnavigationmode) (default behavior) When set to Auto, directional navigation behavior is determined by the element’s ancestry, or inheritance hierarchy. If all ancestors are in default mode (set to **Auto**), directional navigation with the keyboard is *not* supported. -### [Disabled](/uwp/api/windows.ui.xaml.input.xyfocuskeyboardnavigationmode) +### [Disabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocuskeyboardnavigationmode) Set **XYFocusKeyboardNavigation** to **Disabled** to block directional navigation to the control and its child elements. ![XYFocusKeyboardNavigation disabled behavior](images/keyboard/xyfocuskeyboardnav-disabled.gif) *XYFocusKeyboardNavigation disabled behavior* -In this example, the primary [StackPanel](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) (ContainerPrimary) has **XYFocusKeyboardNavigation** set to **Enabled**. All child elements inherit this setting, and can be navigated to with the arrow keys. However, the B3 and B4 elements are in a secondary [StackPanel](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) (ContainerSecondary) with **XYFocusKeyboardNavigation** set to **Disabled**, which overrides the primary container and disables arrow key navigation to itself and between its child elements. +In this example, the primary [StackPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.StackPanel) (ContainerPrimary) has **XYFocusKeyboardNavigation** set to **Enabled**. All child elements inherit this setting, and can be navigated to with the arrow keys. However, the B3 and B4 elements are in a secondary [StackPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.StackPanel) (ContainerSecondary) with **XYFocusKeyboardNavigation** set to **Disabled**, which overrides the primary container and disables arrow key navigation to itself and between its child elements. ```XAML ``` -### [Enabled](/uwp/api/windows.ui.xaml.input.xyfocuskeyboardnavigationmode) +### [Enabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocuskeyboardnavigationmode) -Set **XYFocusKeyboardNavigation** to **Enabled** to support 2D directional navigation to a control and each of its [UIElement](/uwp/api/Windows.UI.Xaml.UIElement) child objects. +Set **XYFocusKeyboardNavigation** to **Enabled** to support 2D directional navigation to a control and each of its [UIElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) child objects. When set, navigation with the arrow keys is restricted to elements within the directional area. Tab navigation is not affected, as all controls remain accessible through their tab order hierarchy. ![XYFocusKeyboardNavigation enabled behavior](images/keyboard/xyfocuskeyboardnav-enabled.gif) *XYFocusKeyboardNavigation enabled behavior* -In this example, the primary [StackPanel](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) (ContainerPrimary) has **XYFocusKeyboardNavigation** set to **Enabled**. All child elements inherit this setting, and can be navigated to with the arrow keys. The B3 and B4 elements are in a secondary [StackPanel](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) (ContainerSecondary) where **XYFocusKeyboardNavigation** is not set, which then inherits the primary container setting. The B5 element is not within a declared directional area, and does not support arrow key navigation but does support standard tab navigation behavior. +In this example, the primary [StackPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.StackPanel) (ContainerPrimary) has **XYFocusKeyboardNavigation** set to **Enabled**. All child elements inherit this setting, and can be navigated to with the arrow keys. The B3 and B4 elements are in a secondary [StackPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.StackPanel) (ContainerSecondary) where **XYFocusKeyboardNavigation** is not set, which then inherits the primary container setting. The B5 element is not within a declared directional area, and does not support arrow key navigation but does support standard tab navigation behavior. ```xaml [!NOTE] -> Use this property instead of the [Control.TabNavigation](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabNavigation) property for objects that do not use a [ControlTemplate](/uwp/api/windows.ui.xaml.controls.controltemplate) to define their appearance. +> Use this property instead of the [Control.TabNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabNavigation) property for objects that do not use a [ControlTemplate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.controltemplate) to define their appearance. -As we mentioned in the previous section, to avoid a confusing navigation experience, we recommend that child elements of a directional area *not* be explicitly specified in the tab navigation order of your application. See the [UIElement.TabFocusNavigation](/uwp/api/windows.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) and the [TabIndex](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) properties for more detail on tabbing behavior for an element. -> For versions older than Windows 10 Creators Update (build 10.0.15063), tab settings were limited to [ControlTemplate](/uwp/api/windows.ui.xaml.controls.controltemplate) objects. For more info, see [Control.TabNavigation](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabNavigation). +As we mentioned in the previous section, to avoid a confusing navigation experience, we recommend that child elements of a directional area *not* be explicitly specified in the tab navigation order of your application. See the [UIElement.TabFocusNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) and the [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) properties for more detail on tabbing behavior for an element. +> For versions older than Windows 10 Creators Update (build 10.0.15063), tab settings were limited to [ControlTemplate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.controltemplate) objects. For more info, see [Control.TabNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabNavigation). -[TabFocusNavigation](/uwp/api/windows.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) -has a value of type [KeyboardNavigationMode](/uwp/api/windows.ui.xaml.input.keyboardnavigationmode) with the following possible values (note that these examples are not custom control groups and do not require inner navigation with the arrow keys): +[TabFocusNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) +has a value of type [KeyboardNavigationMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardnavigationmode) with the following possible values (note that these examples are not custom control groups and do not require inner navigation with the arrow keys): - **Local** (default) Tab indexes are recognized on the local subtree inside the container. For this example, the tab order is B1, B2, B3, B4, B5, B6, B7, B1. @@ -312,23 +312,23 @@ Here's the code for the preceding examples (with TabFocusNavigation ="Cycle"). ``` -### [TabIndex](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) +### [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) -Use [TabIndex](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) to specify the order in which elements receive focus when the user navigates through controls using the Tab key. A control with a lower tab index receives focus before a control with a higher index. +Use [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabIndex) to specify the order in which elements receive focus when the user navigates through controls using the Tab key. A control with a lower tab index receives focus before a control with a higher index. -When a control has no [TabIndex](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) specified, it is assigned a higher index value than the current highest index value (and the lowest priority) of all interactive controls in the visual tree, based on scope. +When a control has no [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) specified, it is assigned a higher index value than the current highest index value (and the lowest priority) of all interactive controls in the visual tree, based on scope. All child elements of a control are considered a scope, and if one of these elements also has child elements, they are considered another scope. Any ambiguity is resolved by choosing the first element on the visual tree of the scope. -To exclude a control from the tab order, set the [IsTabStop](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_IsTabStop) property to **false**. +To exclude a control from the tab order, set the [IsTabStop](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_IsTabStop) property to **false**. -Override the default tab order by setting the [TabIndex](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) property. +Override the default tab order by setting the [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) property. > [!NOTE] -> [TabIndex](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) works the same way with both [UIElement.TabFocusNavigation](/uwp/api/windows.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) and [Control.TabNavigation](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabNavigation). +> [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) works the same way with both [UIElement.TabFocusNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement#Windows_UI_Xaml_UIElement_TabFocusNavigation) and [Control.TabNavigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_TabNavigation). -Here, we show how focus navigation can be affected by the [TabIndex](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) property on specific elements. +Here, we show how focus navigation can be affected by the [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) property on specific elements. !["Local" tab navigation with TabIndex behavior](images/keyboard/tabnav-tabindex.gif) @@ -432,7 +432,7 @@ The following navigation strategy properties let you influence which control rec - XYFocusLeftNavigationStrategy - XYFocusRightNavigationStrategy -These properties have possible values of [Auto](/uwp/api/windows.ui.xaml.input.xyfocusnavigationstrategy) (default), [NavigationDirectionDistance](/uwp/api/windows.ui.xaml.input.xyfocusnavigationstrategy), [Projection](/uwp/api/windows.ui.xaml.input.xyfocusnavigationstrategy), or [RectilinearDistance ](/uwp/api/windows.ui.xaml.input.xyfocusnavigationstrategy). +These properties have possible values of [Auto](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocusnavigationstrategy) (default), [NavigationDirectionDistance](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocusnavigationstrategy), [Projection](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocusnavigationstrategy), or [RectilinearDistance ](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.xyfocusnavigationstrategy). If set to **Auto**, the behavior of the element is based on the ancestors of the element. If all elements are set to **Auto**, **Projection** is used. diff --git a/hub/apps/develop/input/handle-pointer-input.md b/hub/apps/develop/input/handle-pointer-input.md index a0416ee6cc..2007a509cb 100644 --- a/hub/apps/develop/input/handle-pointer-input.md +++ b/hub/apps/develop/input/handle-pointer-input.md @@ -29,7 +29,7 @@ Most interaction experiences typically involve the user identifying the object t > [!NOTE] > Device-specific info is also promoted from the raw HID data should your app require it. -Each input point (or contact) on the input stack is represented by a [**Pointer**](/uwp/api/Windows.UI.Xaml.Input.Pointer) object exposed through the [**PointerRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.PointerRoutedEventArgs) parameter in the various pointer event handlers. In the case of multi-pen or multi-touch input, each contact is treated as a unique input pointer. +Each input point (or contact) on the input stack is represented by a [**Pointer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.Pointer) object exposed through the [**PointerRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.PointerRoutedEventArgs) parameter in the various pointer event handlers. In the case of multi-pen or multi-touch input, each contact is treated as a unique input pointer. ## Pointer events @@ -38,18 +38,18 @@ Pointer events expose basic info such as input device type and detection state ( Windows apps can listen for the following pointer events: > [!NOTE] -> Constrain pointer input to a specific UI element by calling [**CapturePointer**](/uwp/api/windows.ui.xaml.uielement.capturepointer) on that element within a pointer event handler. When a pointer is captured by an element, only that object receives pointer input events, even when the pointer moves outside the bounding area of the object. The [**IsInContact**](/uwp/api/windows.ui.xaml.input.pointer.isincontact) (mouse button pressed, touch or stylus in contact) must be true for **CapturePointer** to be successful. +> Constrain pointer input to a specific UI element by calling [**CapturePointer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.capturepointer) on that element within a pointer event handler. When a pointer is captured by an element, only that object receives pointer input events, even when the pointer moves outside the bounding area of the object. The [**IsInContact**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointer.isincontact) (mouse button pressed, touch or stylus in contact) must be true for **CapturePointer** to be successful. | Event | Description | |---|---| -| [**PointerCanceled**](/uwp/api/windows.ui.xaml.uielement.pointercanceled) | Occurs when a pointer is canceled by the platform. This can occur in the following circumstances:
• Touch pointers are canceled when a pen is detected within range of the input surface.
• An active contact is not detected for more than 100 ms.
• Monitor/display is changed (resolution, settings, multi-mon configuration).
• The desktop is locked or the user has logged off.
• The number of simultaneous contacts exceeded the number supported by the device. | -| [**PointerCaptureLost**](/uwp/api/windows.ui.xaml.uielement.pointercapturelost) | Occurs when another UI element captures the pointer, the pointer was released, or another pointer was programmatically captured.
**Note:** There is no corresponding pointer capture event. | -| [**PointerEntered**](/uwp/api/windows.ui.xaml.uielement.pointerentered) | Occurs when a pointer enters the bounding area of an element. This can happen in slightly different ways for touch, touchpad, mouse, and pen input.
• Touch requires a finger contact to fire this event, either from a direct touch down on the element or from moving into the bounding area of the element.
• Mouse and touchpad both have an on-screen cursor that is always visible and fires this event even if no mouse or touchpad button is pressed.
• Like touch, pen fires this event with a direct pen down on the element or from moving into the bounding area of the element. However, pen also has a hover state ([IsInRange](/uwp/api/windows.ui.xaml.input.pointer.isinrange)) that, when true, fires this event. | -| [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) | Occurs when a pointer leaves the bounding area of an element. This can happen in slightly different ways for touch, touchpad, mouse, and pen input.
• Touch requires a finger contact and fires this event when the pointer moves out of the bounding area of the element.
• Mouse and touchpad both have an on-screen cursor that is always visible and fires this event even if no mouse or touchpad button is pressed.
• Like touch, pen fires this event when moving out of the bounding area of the element. However, pen also has a hover state ([IsInRange](/uwp/api/windows.ui.xaml.input.pointer.isinrange)) that fires this event when the state changes from true to false. | -| [**PointerMoved**](/uwp/api/windows.ui.xaml.uielement.pointermoved) | Occurs when a pointer changes coordinates, button state, pressure, tilt, or contact geometry (for example, width and height) within the bounding area of an element. This can happen in slightly different ways for touch, touchpad, mouse, and pen input.
• Touch requires a finger contact and fires this event only when in contact within the bounding area of the element.
• Mouse and touchpad both have an on-screen cursor that is always visible and fires this event even if no mouse or touchpad button is pressed.
• Like touch, pen fires this event when in contact within the bounding area of the element. However, pen also has a hover state ([IsInRange](/uwp/api/windows.ui.xaml.input.pointer.isinrange)) that, when true and within the bounding area of the element, fires this event. | -| [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) | Occurs when the pointer indicates a press action (such as a touch down, mouse button down, pen down, or touchpad button down) within the bounding area of an element.
[CapturePointer](/uwp/api/windows.ui.xaml.uielement.capturepointer) must be called from the handler for this event. | -| [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) | Occurs when the pointer indicates a release action (such as a touch up, mouse button up, pen up, or touchpad button up) within the bounding area of an element or, if the pointer is captured, outside the bounding area. | -| [**PointerWheelChanged**](/uwp/api/windows.ui.xaml.uielement.pointerwheelchanged) | Occurs when the mouse wheel is rotated.
Mouse input is associated with a single pointer assigned when mouse input is first detected. Clicking a mouse button (left, wheel, or right) creates a secondary association between the pointer and that button through the [PointerMoved](/uwp/api/windows.ui.xaml.uielement.pointermoved) event. |  +| [**PointerCanceled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercanceled) | Occurs when a pointer is canceled by the platform. This can occur in the following circumstances:
• Touch pointers are canceled when a pen is detected within range of the input surface.
• An active contact is not detected for more than 100 ms.
• Monitor/display is changed (resolution, settings, multi-mon configuration).
• The desktop is locked or the user has logged off.
• The number of simultaneous contacts exceeded the number supported by the device. | +| [**PointerCaptureLost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercapturelost) | Occurs when another UI element captures the pointer, the pointer was released, or another pointer was programmatically captured.
**Note:** There is no corresponding pointer capture event. | +| [**PointerEntered**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerentered) | Occurs when a pointer enters the bounding area of an element. This can happen in slightly different ways for touch, touchpad, mouse, and pen input.
• Touch requires a finger contact to fire this event, either from a direct touch down on the element or from moving into the bounding area of the element.
• Mouse and touchpad both have an on-screen cursor that is always visible and fires this event even if no mouse or touchpad button is pressed.
• Like touch, pen fires this event with a direct pen down on the element or from moving into the bounding area of the element. However, pen also has a hover state ([IsInRange](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointer.isinrange)) that, when true, fires this event. | +| [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) | Occurs when a pointer leaves the bounding area of an element. This can happen in slightly different ways for touch, touchpad, mouse, and pen input.
• Touch requires a finger contact and fires this event when the pointer moves out of the bounding area of the element.
• Mouse and touchpad both have an on-screen cursor that is always visible and fires this event even if no mouse or touchpad button is pressed.
• Like touch, pen fires this event when moving out of the bounding area of the element. However, pen also has a hover state ([IsInRange](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointer.isinrange)) that fires this event when the state changes from true to false. | +| [**PointerMoved**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) | Occurs when a pointer changes coordinates, button state, pressure, tilt, or contact geometry (for example, width and height) within the bounding area of an element. This can happen in slightly different ways for touch, touchpad, mouse, and pen input.
• Touch requires a finger contact and fires this event only when in contact within the bounding area of the element.
• Mouse and touchpad both have an on-screen cursor that is always visible and fires this event even if no mouse or touchpad button is pressed.
• Like touch, pen fires this event when in contact within the bounding area of the element. However, pen also has a hover state ([IsInRange](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointer.isinrange)) that, when true and within the bounding area of the element, fires this event. | +| [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) | Occurs when the pointer indicates a press action (such as a touch down, mouse button down, pen down, or touchpad button down) within the bounding area of an element.
[CapturePointer](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.capturepointer) must be called from the handler for this event. | +| [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) | Occurs when the pointer indicates a release action (such as a touch up, mouse button up, pen up, or touchpad button up) within the bounding area of an element or, if the pointer is captured, outside the bounding area. | +| [**PointerWheelChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerwheelchanged) | Occurs when the mouse wheel is rotated.
Mouse input is associated with a single pointer assigned when mouse input is first detected. Clicking a mouse button (left, wheel, or right) creates a secondary association between the pointer and that button through the [PointerMoved](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) event. |  ## Pointer event example @@ -61,9 +61,9 @@ Here are some code snippets from a basic pointer tracking app that show how to l ### Create the UI -For this example, we use a [Rectangle](/uwp/api/windows.ui.xaml.shapes.rectangle) (`Target`) as the object consuming pointer input. The color of the target changes when the pointer status changes. +For this example, we use a [Rectangle](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes.rectangle) (`Target`) as the object consuming pointer input. The color of the target changes when the pointer status changes. -Details for each pointer are displayed in a floating [TextBlock](/uwp/api/Windows.UI.Xaml.Controls.TextBlock) that follows the pointer as it moves. The pointer events themselves are reported in the [RichTextBlock](/uwp/api/Windows.UI.Xaml.Controls.RichTextBlock) to the right of the rectangle. +Details for each pointer are displayed in a floating [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TextBlock) that follows the pointer as it moves. The pointer events themselves are reported in the [RichTextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RichTextBlock) to the right of the rectangle. This is the Extensible Application Markup Language (XAML) for the UI in this example. @@ -120,9 +120,9 @@ This is the Extensible Application Markup Language (XAML) for the UI in this exa ### Listen for pointer events -In most cases, we recommend that you get pointer info through the [**PointerRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.PointerRoutedEventArgs) of the event handler. +In most cases, we recommend that you get pointer info through the [**PointerRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.PointerRoutedEventArgs) of the event handler. -If the event argument doesn't expose the pointer details required, you can get access to extended [**PointerPoint**](/uwp/api/Windows.UI.Input.PointerPoint) info exposed through the [**GetCurrentPoint**](/uwp/api/windows.ui.xaml.input.pointerroutedeventargs.getcurrentpoint) and [**GetIntermediatePoints**](/uwp/api/windows.ui.xaml.input.pointerroutedeventargs.getintermediatepoints) methods of [**PointerRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.PointerRoutedEventArgs). +If the event argument doesn't expose the pointer details required, you can get access to extended [**PointerPoint**](/uwp/api/Windows.UI.Input.PointerPoint) info exposed through the [**GetCurrentPoint**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointerroutedeventargs.getcurrentpoint) and [**GetIntermediatePoints**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointerroutedeventargs.getintermediatepoints) methods of [**PointerRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.PointerRoutedEventArgs). The following code sets up the global dictionary object for tracking each active pointer, and identifies the various pointer event listeners for the target object. @@ -130,14 +130,14 @@ The following code sets up the global dictionary object for tracking each active // Dictionary to maintain information about each active pointer. // An entry is added during PointerPressed/PointerEntered events and removed // during PointerReleased/PointerCaptureLost/PointerCanceled/PointerExited events. -Dictionary pointers; +Dictionary pointers; public MainPage() { this.InitializeComponent(); // Initialize the dictionary. - pointers = new Dictionary(); + pointers = new Dictionary(); // Declare the pointer event handlers. Target.PointerPressed += @@ -166,10 +166,10 @@ public MainPage() Next, we use UI feedback to demonstrate basic pointer event handlers. -- This handler manages the [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) event. We add the event to the event log, add the pointer to the active pointer dictionary, and display the pointer details. +- This handler manages the [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) event. We add the event to the event log, add the pointer to the active pointer dictionary, and display the pointer details. > [!NOTE] - > [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) and [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) events do not always occur in pairs. Your app should listen for and handle any event that might conclude a pointer down (such as [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited), [**PointerCanceled**](/uwp/api/windows.ui.xaml.uielement.pointercanceled), and [**PointerCaptureLost**](/uwp/api/windows.ui.xaml.uielement.pointercapturelost)). + > [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) and [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) events do not always occur in pairs. Your app should listen for and handle any event that might conclude a pointer down (such as [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited), [**PointerCanceled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercanceled), and [**PointerCaptureLost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercapturelost)).   ```csharp @@ -205,14 +205,14 @@ void Target_PointerPressed(object sender, PointerRoutedEventArgs e) } // Change background color of target when pointer contact detected. - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Green); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Green); // Display pointer details. CreateInfoPop(ptrPt); } ``` -- This handler manages the [**PointerEntered**](/uwp/api/windows.ui.xaml.uielement.pointerentered) event. We add the event to the event log, add the pointer to the pointer collection, and display the pointer details. +- This handler manages the [**PointerEntered**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerentered) event. We add the event to the event log, add the pointer to the pointer collection, and display the pointer details. ```csharp /// @@ -241,7 +241,7 @@ private void Target_PointerEntered(object sender, PointerRoutedEventArgs e) if (pointers.Count == 0) { // Change background color of target when pointer contact detected. - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Blue); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Blue); } // Display pointer details. @@ -249,10 +249,10 @@ private void Target_PointerEntered(object sender, PointerRoutedEventArgs e) } ``` -- This handler manages the [**PointerMoved**](/uwp/api/windows.ui.xaml.uielement.pointermoved) event. We add the event to the event log and update the pointer details. +- This handler manages the [**PointerMoved**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) event. We add the event to the event log and update the pointer details. > [!Important] - > Mouse input is associated with a single pointer assigned when mouse input is first detected. Clicking a mouse button (left, wheel, or right) creates a secondary association between the pointer and that button through the [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) event. The [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) event is fired only when that same mouse button is released (no other button can be associated with the pointer until this event is complete). Because of this exclusive association, other mouse button clicks are routed through the [**PointerMoved**](/uwp/api/windows.ui.xaml.uielement.pointermoved) event.   + > Mouse input is associated with a single pointer assigned when mouse input is first detected. Clicking a mouse button (left, wheel, or right) creates a secondary association between the pointer and that button through the [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) event. The [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) event is fired only when that same mouse button is released (no other button can be associated with the pointer until this event is complete). Because of this exclusive association, other mouse button clicks are routed through the [**PointerMoved**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) event.   ```csharp /// @@ -299,7 +299,7 @@ private void Target_PointerMoved(object sender, PointerRoutedEventArgs e) } ``` -- This handler manages the [**PointerWheelChanged**](/uwp/api/windows.ui.xaml.uielement.pointerwheelchanged) event. We add the event to the event log, add the pointer to the pointer array (if necessary), and display the pointer details. +- This handler manages the [**PointerWheelChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerwheelchanged) event. We add the event to the event log, add the pointer to the pointer array (if necessary), and display the pointer details. ```csharp /// @@ -329,7 +329,7 @@ private void Target_PointerWheelChanged(object sender, PointerRoutedEventArgs e) } ``` -- This handler manages the [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) event where contact with the digitizer is terminated. We add the event to the event log, remove the pointer from the pointer collection, and update the pointer details. +- This handler manages the [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) event where contact with the digitizer is terminated. We add the event to the event log, remove the pointer from the pointer collection, and update the pointer details. ```csharp /// @@ -357,7 +357,7 @@ void Target_PointerReleased(object sender, PointerRoutedEventArgs e) if (ptrPt.PointerDevice.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Mouse) { // Update target UI. - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Red); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Red); DestroyInfoPop(ptrPt); @@ -376,12 +376,12 @@ void Target_PointerReleased(object sender, PointerRoutedEventArgs e) } else { - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Blue); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Blue); } } ``` -- This handler manages the [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) event (when contact with the digitizer is maintained). We add the event to the event log, remove the pointer from the pointer array, and update the pointer details. +- This handler manages the [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) event (when contact with the digitizer is maintained). We add the event to the event log, remove the pointer from the pointer array, and update the pointer details. ```csharp /// @@ -408,7 +408,7 @@ private void Target_PointerExited(object sender, PointerRoutedEventArgs e) if (pointers.Count == 0) { - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Red); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Red); } // Update the UI and pointer details. @@ -416,7 +416,7 @@ private void Target_PointerExited(object sender, PointerRoutedEventArgs e) } ``` -- This handler manages the [**PointerCanceled**](/uwp/api/windows.ui.xaml.uielement.pointercanceled) event. We add the event to the event log, remove the pointer from the pointer array, and update the pointer details. +- This handler manages the [**PointerCanceled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercanceled) event. We add the event to the event log, remove the pointer from the pointer array, and update the pointer details. ```csharp /// @@ -448,17 +448,17 @@ private void Target_PointerCanceled(object sender, PointerRoutedEventArgs e) if (pointers.Count == 0) { - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Black); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Black); } DestroyInfoPop(ptrPt); } ``` -- This handler manages the [**PointerCaptureLost**](/uwp/api/windows.ui.xaml.uielement.pointercapturelost) event. We add the event to the event log, remove the pointer from the pointer array, and update the pointer details. +- This handler manages the [**PointerCaptureLost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercapturelost) event. We add the event to the event log, remove the pointer from the pointer array, and update the pointer details. > [!NOTE] - > [**PointerCaptureLost**](/uwp/api/windows.ui.xaml.uielement.pointercapturelost) can occur instead of [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased). Pointer capture can be lost for various reasons including user interaction, programmatic capture of another pointer, calling [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased).   + > [**PointerCaptureLost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercapturelost) can occur instead of [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased). Pointer capture can be lost for various reasons including user interaction, programmatic capture of another pointer, calling [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased).   ```csharp /// @@ -483,7 +483,7 @@ private void Target_PointerCaptureLost(object sender, PointerRoutedEventArgs e) if (pointers.Count == 0) { - Target.Fill = new SolidColorBrush(Windows.UI.Colors.Black); + Target.Fill = new SolidColorBrush(Microsoft.UI.Colors.Black); } // Remove contact from dictionary. @@ -499,9 +499,9 @@ private void Target_PointerCaptureLost(object sender, PointerRoutedEventArgs e) ### Get pointer properties -As stated earlier, you must get most extended pointer info from a [**Windows.UI.Input.PointerPoint**](/uwp/api/Windows.UI.Input.PointerPoint) object obtained through the [**GetCurrentPoint**](/uwp/api/windows.ui.xaml.input.pointerroutedeventargs.getcurrentpoint) and [**GetIntermediatePoints**](/uwp/api/windows.ui.xaml.input.pointerroutedeventargs.getintermediatepoints) methods of [**PointerRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.PointerRoutedEventArgs). The following code snippets show how. +As stated earlier, you must get most extended pointer info from a [**Windows.UI.Input.PointerPoint**](/uwp/api/Windows.UI.Input.PointerPoint) object obtained through the [**GetCurrentPoint**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointerroutedeventargs.getcurrentpoint) and [**GetIntermediatePoints**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.pointerroutedeventargs.getintermediatepoints) methods of [**PointerRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.PointerRoutedEventArgs). The following code snippets show how. -- First, we create a new [**TextBlock**](/uwp/api/Windows.UI.Xaml.Controls.TextBlock) for each pointer. +- First, we create a new [**TextBlock**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TextBlock) for each pointer. ```csharp /// @@ -512,7 +512,7 @@ void CreateInfoPop(PointerPoint ptrPt) { TextBlock pointerDetails = new TextBlock(); pointerDetails.Name = ptrPt.PointerId.ToString(); - pointerDetails.Foreground = new SolidColorBrush(Windows.UI.Colors.White); + pointerDetails.Foreground = new SolidColorBrush(Microsoft.UI.Colors.White); pointerDetails.Text = QueryPointer(ptrPt); TranslateTransform x = new TranslateTransform(); @@ -524,7 +524,7 @@ void CreateInfoPop(PointerPoint ptrPt) } ``` -- Then we provide a way to update the pointer info in an existing [**TextBlock**](/uwp/api/Windows.UI.Xaml.Controls.TextBlock) associated with that pointer. +- Then we provide a way to update the pointer info in an existing [**TextBlock**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TextBlock) associated with that pointer. ```csharp /// @@ -535,7 +535,7 @@ void UpdateInfoPop(PointerPoint ptrPt) { foreach (var pointerDetails in Container.Children) { - if (pointerDetails.GetType().ToString() == "Windows.UI.Xaml.Controls.TextBlock") + if (pointerDetails.GetType().ToString() == "Microsoft.UI.Xaml.Controls.TextBlock") { TextBlock textBlock = (TextBlock)pointerDetails; if (textBlock.Name == ptrPt.PointerId.ToString()) @@ -627,7 +627,7 @@ This particular app uses both color and animation to highlight the primary point ### Visual feedback -We define a **[UserControl](/uwp/api/windows.ui.xaml.controls.usercontrol)**, based on a XAML **[Ellipse](/uwp/api/windows.ui.xaml.shapes.ellipse)** object, that highlights where each pointer is on the canvas and uses a **[Storyboard](/uwp/api/windows.ui.xaml.media.animation.storyboard)** to animate the ellipse that corresponds to the primary pointer. +We define a **[UserControl](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.usercontrol)**, based on a XAML **[Ellipse](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.shapes.ellipse)** object, that highlights where each pointer is on the canvas and uses a **[Storyboard](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.storyboard)** to animate the ellipse that corresponds to the primary pointer. **Here's the XAML:** @@ -702,9 +702,9 @@ We define a **[UserControl](/uwp/api/windows.ui.xaml.controls.usercontrol)**, ba And here's the code-behind: ```csharp using Windows.Foundation; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; // The User Control item template is documented at // https://go.microsoft.com/fwlink/?LinkId=234236 @@ -819,7 +819,7 @@ namespace UWP_Pointers ``` ### Create the UI -The UI in this example is limited to the input **[Canvas](/uwp/api/windows.ui.xaml.controls.canvas)** where we track any pointers and render the pointer indicators and primary pointer animation (if applicable), along with a header bar containing a pointer counter and a primary pointer identifier. +The UI in this example is limited to the input **[Canvas](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.canvas)** where we track any pointers and render the pointer indicators and primary pointer animation (if applicable), along with a header bar containing a pointer counter and a primary pointer identifier. Here's the MainPage.xaml: diff --git a/hub/apps/develop/input/keyboard-accelerators.md b/hub/apps/develop/input/keyboard-accelerators.md index ca8595bf21..b5eda9c7ee 100644 --- a/hub/apps/develop/input/keyboard-accelerators.md +++ b/hub/apps/develop/input/keyboard-accelerators.md @@ -1,646 +1,646 @@ ---- -description: Learn how accelerator keys can improve the usability and accessibility of Windows apps. -title: Keyboard accelerators -label: Keyboard accelerators -template: detail.hbs -keywords: keyboard, accelerator, accelerator key, keyboard shortcuts, accessibility, navigation, focus, text, input, user interactions, gamepad, remote -ms.date: 07/09/2021 -ms.topic: article -pm-contact: chigy -design-contact: miguelrb -doc-status: Draft -ms.localizationpriority: medium ---- - -# Keyboard accelerators - -![Hero image of the Surface keyboard](images/accelerators/accelerators_hero2.png) - -Accelerator keys (or keyboard accelerators) are keyboard shortcuts that improve the usability and accessibility of your Windows applications by providing an intuitive way for users to invoke common actions or commands without navigating the app UI. - -> [!NOTE] -> A keyboard is indispensable for users with certain disabilities (see [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md)), and is also an important tool for users who prefer it as a more efficient way to interact with an app. - -See the [Access keys](../../design/input/access-keys.md) topic for details on navigating the UI of a Windows application with keyboard shortcuts. - -To create your own custom keyboard shortcuts, see the [Keyboard events](../../design/input/keyboard-events.md) topic. - -## Overview - -Accelerators are composed of two types of keys: modifiers and non-modifiers. Modifier keys include Shift, Menu, Control, and the Windows key, which are exposed through [VirtualKeyModifiers](/uwp/api/Windows.System.VirtualKeyModifiers). Non-modifiers include any [VirtualKey](/uwp/api/windows.system.virtualkey), such as Delete, F3, Spacebar, Arrow, Esc, and all alphanumeric and punctuation keys. - -> [!NOTE] -> Accelerators typically include the function keys F1 through F12 or some combination of a standard key paired with one or more modifier keys (CTRL, Shift). For example, if a user presses Ctrl+Shift+M, the framework checks the modifiers (Ctrl and Shift) and fires the accelerator, if it exists. - -Many XAML controls have built-in keyboard accelerators. For example, ListView supports Ctrl+A for selecting all the items in the list, and RichEditBox supports Ctrl+Tab for inserting a Tab in the text box. These built-in keyboard accelerators are referred to as **control accelerators** and are executed only if the focus is on the element or one of its children. Accelerators defined by you using the keyboard accelerator APIs discussed here are referred to as **app accelerators**. - -Keyboard accelerators are not available for every action but are often associated with commands exposed in menus (and should be specified with the menu item content). Accelerators can also be associated with actions that do not have equivalent menu items. However, because users rely on an application's menus to discover and learn the available command set, you should try to make discovery of accelerators as easy as possible (using labels or established patterns can help with this). - -An accelerator auto-repeats (for example, when the user presses Ctrl+Shift and then holds down M, the accelerator is invoked repeatedly until M is released). This behavior cannot be modified. - -![Screenshot of keyboard accelerators in a menu item label.](images/accelerators/accelerators_menuitemlabel.png) -*Keyboard accelerators described in a menu item label* - -## When to use keyboard accelerators - -We recommend that you specify keyboard accelerators wherever appropriate in your UI, and support accelerators in all custom controls. - -- Keyboard accelerators make your app more accessible for users with motor disabilities, including those users who can press only one key at a time or have difficulty using a mouse. - - A well-designed keyboard UI is an important aspect of software accessibility. It enables users with vision impairments or who have certain motor disabilities to navigate an app and interact with its features. Such users might not be able to operate a mouse and instead rely on various assistive technologies such as keyboard enhancement tools, on-screen keyboards, screen enlargers, screen readers, and voice input utilities. For these users, comprehensive command coverage is crucial. - -- Keyboard accelerators make your app more usable for power users who prefer to interact through the keyboard. - - Experienced users often have a strong preference for using the keyboard because keyboard-based commands can be entered more quickly and don't require them to remove their hands from the keyboard. For these users, efficiency and consistency are crucial; comprehensiveness is important only for the most frequently used commands. - -## Specify a keyboard accelerator - -Use the [KeyboardAccelerator](/uwp/api/windows.ui.xaml.input.keyboardaccelerator.-ctor) APIs to create keyboard accelerators in Windows apps. With these APIs, you don't have to handle multiple KeyDown events to detect the key combination pressed, and you can localize accelerators in the app resources. - -We recommend that you set keyboard accelerators for the most common actions in your app and document them using the menu item label or tooltip. In this example, we declare keyboard accelerators only for the Rename and Copy commands. - -``` xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -![Screenshot of a keyboard accelerator in a tooltip.](images/accelerators/accelerators_tooltip.png) -***Keyboard accelerator described in a tooltip*** - -The [UIElement](/uwp/api/windows.ui.xaml.uielement) object has a [KeyboardAccelerator](/uwp/api/windows.ui.xaml.input.keyboardaccelerator) collection, [KeyboardAccelerators](/uwp/api/windows.ui.xaml.uielement.KeyboardAccelerators), where you specify your custom KeyboardAccelerator objects and define the keystrokes for the keyboard accelerator: - -- **[Key](/uwp/api/windows.ui.xaml.input.keyboardaccelerator.Key)** - the [VirtualKey](/uwp/api/windows.system.virtualkey) used for the keyboard accelerator. - -- **[Modifiers](/uwp/api/windows.ui.xaml.input.keyboardaccelerator.Modifiers)** – the [VirtualKeyModifiers](/uwp/api/windows.system.virtualkeymodifiers) used for the keyboard accelerator. If Modifiers is not set, the default value is None. - -> [!NOTE] -> Single key (A, Delete, F2, Spacebar, Esc, Multimedia Key) accelerators and multi-key accelerators (Ctrl+Shift+M) are supported. However, Gamepad virtual keys are not supported. - -## Scoped accelerators - -Some accelerators work only in specific scopes while others work app-wide. - -For example, Microsoft Outlook includes the following accelerators: -- Ctrl+B, Ctrl+I and ESC work only on the scope of the send email form -- Ctrl+1 and Ctrl+2 work app-wide - -### Context menus - -Context menu actions affect only specific areas or elements, such as the selected characters in a text editor or a song in a playlist. For this reason, we recommend setting the scope of keyboard accelerators for context menu items to the parent of the context menu. - -Use the [ScopeOwner](/uwp/api/windows.ui.xaml.input.keyboardaccelerator.ScopeOwner) property to specify the scope of the keyboard accelerator. This code demonstrates how to implement a context menu on a ListView with scoped keyboard accelerators: - -``` xaml - - - - - - - - - - - - - - - - - - - - - - - - - Track 1 - Alternative Track 1 - - -``` - -The ScopeOwner attribute of the MenuFlyoutItem.KeyboardAccelerators element marks the accelerator as scoped instead of global (the default is null, or global). For more detail, see the **Resolving accelerators** section later in this topic. - -## Invoke a keyboard accelerator - -The [KeyboardAccelerator](/uwp/api/windows.ui.xaml.input.keyboardaccelerator) object uses the [UI Automation (UIA) control pattern](/windows/desktop/WinAuto/uiauto-controlpatternsoverview) to take action when an accelerator is invoked. - -The UIA [control patterns] expose common control functionality. For example, the Button control implements the [Invoke](/windows/desktop/WinAuto/uiauto-implementinginvoke) control pattern to support the Click event (typically a control is invoked by clicking, double-clicking, or pressing Enter, a predefined keyboard shortcut, or some other combination of keystrokes). When a keyboard accelerator is used to invoke a control, the XAML framework looks up whether the control implements the Invoke control pattern and, if so, activates it (it is not necessary to listen for the KeyboardAcceleratorInvoked event). - -In the following example, Control+S triggers the Click event because the button implements the Invoke pattern. - -``` xaml - -``` - -If an element implements multiple control patterns, only one can be activated through an accelerator. The control patterns are prioritized as follows: -1. Invoke (Button) -2. Toggle (Checkbox) -3. Selection (ListView) -4. Expand/Collapse (ComboBox)  - -If no match is identified, the accelerator is invalid and a debug message is provided ("No automation patterns for this component found. Implement all desired behavior in the Invoked event. Setting Handled to true in your event handler suppresses this message.") - -## Custom keyboard accelerator behavior - -The Invoked event of the [KeyboardAccelerator](/uwp/api/windows.ui.xaml.input.keyboardaccelerator) object is fired when the accelerator is executed. The [KeyboardAcceleratorInvokedEventArgs](/uwp/api/windows.ui.xaml.input.keyboardacceleratorinvokedeventargs) event object includes the following properties: - -- [**Handled**](/uwp/api/windows.ui.xaml.input.keyboardacceleratorinvokedeventargs.handled) (Boolean): Setting this to true prevents the event triggering the control pattern and stops accelerator event bubbling. The default is false. -- [**Element**](/uwp/api/windows.ui.xaml.input.keyboardacceleratorinvokedeventargs.element) (DependencyObject): The object associated with the accelerator. -- [**KeyboardAccelerator**](/uwp/api/windows.ui.xaml.input.keyboardacceleratorinvokedeventargs.keyboardaccelerator): The keyboard accelerator used to raise the Invoked event. - -Here we demonstrate how to define a collection of keyboard accelerators for items in a ListView, and how to handle the Invoked event for each accelerator. - -``` xaml - - - - - - -``` - -``` csharp -void SelectAllInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) -{ - MyListView.SelectAll(); - args.Handled = true; -} - -void RefreshInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) -{ - MyListView.SelectionMode = ListViewSelectionMode.None; - MyListView.SelectionMode = ListViewSelectionMode.Multiple; - args.Handled = true; -} -``` - -## Override default keyboard behavior - -Some controls, when they have focus, support built-in keyboard accelerators that override any app-defined accelerator. For example, when a [TextBox](/uwp/api/windows.ui.xaml.controls.textbox) has focus, the Control+C accelerator only copies the currently selected text (app-defined accelerators are ignored and no other functionality is executed). - -While we don't recommend overriding default control behaviors due to user familiarity and expectations, you can override a control's built-in keyboard accelerator. The following example shows how to override the Control+C keyboard accelerator for a [TextBox](/uwp/api/windows.ui.xaml.controls.textbox) through the [PreviewKeyDown](/uwp/api/windows.ui.xaml.uielement.previewkeydown) event handler: - -``` csharp - private void TextBlock_PreviewKeyDown(object sender, KeyRoutedEventArgs e) - { - var ctrlState = CoreWindow.GetForCurrentThread().GetKeyState(Windows.System.VirtualKey.Control); - var isCtrlDown = ctrlState == CoreVirtualKeyStates.Down || ctrlState - == (CoreVirtualKeyStates.Down | CoreVirtualKeyStates.Locked); - if (isCtrlDown && e.Key == Windows.System.VirtualKey.C) - { - // Your custom keyboard accelerator behavior. - - e.Handled = true; - } - } -``` - -## Disable a keyboard accelerator - -If a control is disabled, the associated accelerator is also disabled. In the following example, because the IsEnabled property of the ListView is set to false, the associated Control+A accelerator can't be invoked. - -``` xaml - - - - - - - - - - - - -``` - -Parent and child controls can share the same accelerator. In this case, the parent control can be invoked even if the child has focus and its accelerator is disabled. - -## Screen readers and keyboard accelerators - -Screen readers such as Narrator can announce the keyboard accelerator key combination to users. By default, this is each modifier (in the VirtualModifiers enum order) followed by the key (and separated by "+" signs). You can customize this through the [AcceleratorKey](/uwp/api/windows.ui.xaml.automation.automationproperties.AcceleratorKeyProperty) AutomationProperties attached property. If more than one accelerator is specified, only the first is announced. - -In this example, the AutomationProperty.AcceleratorKey returns the string "Control+Shift+A": - -``` xaml - - - - - - - - - -    -``` - -> [!NOTE] -> Setting AutomationProperties.AcceleratorKey doesn't enable keyboard functionality, it only indicates to the UIA framework which keys are used. - -## Common Keyboard Accelerators - -We recommend that you make keyboard accelerators consistent across Windows applications. - -Users have to memorize keyboard accelerators and expect the same (or similar) results, but this might not always be possible due to differences in functionality across apps. - -| **Editing** | **Common Keyboard Accelerator** | -| ------------- | ----------------------------------- | -| Begin editing mode | Ctrl + E | -| Select all items in a focused control or window | Ctrl + A | -| Search and replace | Ctrl + H | -| Undo | Ctrl + Z | -| Redo | Ctrl + Y | -| Delete selection and copy it to the clipboard | Ctrl + X | -| Copy selection to the clipboard | Ctrl + C, Ctrl + Insert | -| Paste the contents of the clipboard | Ctrl + V, Shift + Insert | -| Paste the contents of the clipboard (with options) | Ctrl + Alt + V | -| Rename an item | F2 | -| Add a new item | Ctrl + N | -| Add a new secondary item | Ctrl + Shift + N | -| Delete selected item (with undo) | Del, Ctrl+D | -| Delete selected item (without undo) | Shift + Del | -| Bold | Ctrl + B | -| Underline | Ctrl + U | -| Italic | Ctrl + I | -| **Navigation** | | -| Find content in a focused control or Window | Ctrl + F | -| Go to the next search result | F3 | -| Go to the next UI pane | F6 | -| Go to the previous UI pane | Shift + F6 | -| **Other Actions** | | -| Add favorites | Ctrl + D | -| Refresh | F5 or Ctrl + R | -| Zoom In | Ctrl + + | -| Zoom out | Ctrl + - | -| Zoom to default view | Ctrl + 0 | -| Save | Ctrl + S | -| Close | Ctrl + W | -| Print | Ctrl + P | - -Notice that some of the combinations are not valid for localized versions of Windows. For example, in the Spanish version of Windows, Ctrl+N is used for bold instead of Ctrl+B. We recommend providing localized keyboard accelerators if the app is localized. - -## Usability affordances for keyboard accelerators - -### Tooltips - -As keyboard accelerators are not typically described directly in the UI of your Windows application, you can improve discoverability through [tooltips](../../design/controls/tooltips.md), which display automatically when the user moves focus to, presses and holds, or hovers the mouse pointer over a control. The tooltip can identify whether a control has an associated keyboard accelerator and, if so, what the accelerator key combination is. - -By default, when keyboard accelerators are declared, all controls (except [MenuFlyoutItem](/uwp/api/Windows.UI.Xaml.Controls.MenuFlyoutItem) and [ToggleMenuFlyoutItem](/uwp/api/windows.ui.xaml.controls.togglemenuflyoutitem)) present the corresponding key combinations in a tooltip. - -> [!NOTE] -> If a control has more than one accelerator defined, only the first is presented. - -![Screenshot of a Save button with a tool tip above it that indicates support for the Ctrl+S accelerator.](images/accelerators/accelerators_tooltip_savebutton_small.png)
-*Accelerator key combo in tooltip* - -For [Button](/uwp/api/windows.ui.xaml.controls.button), [AppBarButton](/uwp/api/windows.ui.xaml.controls.appbarbutton), and [AppBarToggleButton](/uwp/api/windows.ui.xaml.controls.appbartogglebutton) objects, the keyboard accelerator is appended to the control's default tooltip. For [MenuFlyoutItem](/uwp/api/windows.ui.xaml.controls.appbarbutton) and [ToggleMenuFlyoutItem](/uwp/api/windows.ui.xaml.controls.togglemenuflyoutitem) objects, the keyboard accelerator is displayed with the flyout text. - -> [!NOTE] -> Specifying a tooltip (see Button1 in the following example) overrides this behavior. - -```xaml - - - - - -``` - -![Screenshot of three buttons labeled Button1, Button2, and Button3 with a tool tip above Button2 that indicates support for the Windows+B accelerator.](images/accelerators/accelerators-button-small.png) - -*Accelerator key combo appended to Button's default tooltip* - -```xaml - - - - - -``` - -![Screenshot of a button with a Disk icon and a tool tip that includes the default Save text appended with the Ctrl+S accelerator in parentheses.](images/accelerators/accelerators-appbarbutton-small.png) - -*Accelerator key combo appended to AppBarButton's default tooltip* - -```xaml - - - - - - - - - - - - - - - - - - - -``` - -![Screenshot of a Menu with MenuFlyoutItems that include accelerator key combos.](images/accelerators/accelerators-appbar-menuflyoutitem-small.png)
-*Accelerator key combo appended to MenuFlyoutItem's text* - -Control the presentation behavior by using the [KeyboardAcceleratorPlacementMode](/uwp/api/windows.ui.xaml.uielement.KeyboardAcceleratorPlacementMode) property, which accepts two values: [Auto](/uwp/api/windows.ui.xaml.input.keyboardacceleratorplacementmode) or [Hidden](/uwp/api/windows.ui.xaml.input.keyboardacceleratorplacementmode). - -```xaml - -``` - -In some cases, you might need to present a tooltip relative to another element (typically a container object). - -Here, we show how to use the KeyboardAcceleratorPlacementTarget property to display the keyboard accelerator key combination for a Save button with the Grid container instead of the button. - -```xaml - - - -``` - -### Labels - -In some cases, we recommend using a control's label to identify whether the control has an associated keyboard accelerator and, if so, what the accelerator key combination is. - -Some platform controls do this by default, specifically the [MenuFlyoutItem](/uwp/api/Windows.UI.Xaml.Controls.MenuFlyoutItem) and [ToggleMenuFlyoutItem](/uwp/api/windows.ui.xaml.controls.togglemenuflyoutitem) objects, while the [AppBarButton](/uwp/api/windows.ui.xaml.controls.appbarbutton) and the [AppBarToggleButton](/uwp/api/windows.ui.xaml.controls.appbartogglebutton) do it when they appear in the overflow menu of the [CommandBar](/uwp/api/windows.ui.xaml.controls.commandbar). - -![Keyboard accelerators described in a menu item label.](images/accelerators/accelerators_menuitemlabel.png) -*Keyboard accelerators described in a menu item label* - -You can override the default accelerator text for the label through the [KeyboardAcceleratorTextOverride](/uwp/api/windows.ui.xaml.controls.appbarbutton.KeyboardAcceleratorTextOverride) property of the [MenuFlyoutItem](/uwp/api/Windows.UI.Xaml.Controls.MenuFlyoutItem), [ToggleMenuFlyoutItem](/uwp/api/windows.ui.xaml.controls.togglemenuflyoutitem), [AppBarButton](/uwp/api/windows.ui.xaml.controls.appbarbutton), and [AppBarToggleButton](/uwp/api/windows.ui.xaml.controls.appbartogglebutton) controls (use a single space for no text). - -> [!NOTE] -> The override text is not be presented if the system cannot detect an attached keyboard (you can check this yourself through the [KeyboardPresent](/uwp/api/windows.devices.input.keyboardcapabilities.KeyboardPresent) property). - -## Advanced Concepts - -Here, we review some low-level aspects of keyboard accelerators. - -### Input event priority - -Input events occur in a specific sequence that you can intercept and handle based on the requirements of your app. - -#### The KeyDown/KeyUp bubbling event - -In XAML, a keystroke is processed as if there is just one input bubbling pipeline. This input pipeline is used by the KeyDown/KeyUp events and character input. For example, if an element has focus and the user presses a key down, a KeyDown event is raised on the element, followed by the parent of the element, and so on up the tree, until the args.Handled property is true. - -The KeyDown event is also used by some controls to implement the built-in control accelerators. When a control has a keyboard accelerator, it handles the KeyDown event, which means that there won't be KeyDown event bubbling. For example, the RichEditBox supports copy with Ctrl+C. When Ctrl is pressed, the KeyDown event is fired and bubbles, but when the user presses C at the same time, the KeyDown event is marked Handled and is not raised (unless the handledEventsToo parameter of [UIElement.AddHandler](/uwp/api/windows.ui.xaml.uielement.addhandler) is set to true). - -#### The CharacterReceived event - -As the [CharacterReceived](/uwp/api/windows.ui.core.corewindow.CharacterReceived) event is fired after the [KeyDown](/uwp/api/windows.ui.core.corewindow.KeyDown) event for text controls such as TextBox, you can cancel character input in the KeyDown event handler. - -#### The PreviewKeyDown and PreviewKeyUp events - -The preview input events are fired before any other events. If you don't handle these events, the accelerator for the element that has the focus is fired, followed by the KeyDown event. Both events bubble until handled. - - -![Diagram showing the key event sequence](images/accelerators/accelerators_keyevents.png) -***Key event sequence*** - -Order of events: - -Preview KeyDown events
-…
-App accelerator
-OnKeyDown method
-KeyDown event
-App accelerators on the parent
-OnKeyDown method on the parent
-KeyDown event on the parent
-(Bubbles to the root)
-…
-CharacterReceived event
-PreviewKeyUp events
-KeyUpEvents
- -When the accelerator event is handled, the KeyDown event is also marked as handled. The KeyUp event remains unhandled. - -### Resolving accelerators - -A keyboard accelerator event bubbles from the element that has focus up to the root. If the event isn't handled, the XAML framework looks for other unscoped app accelerators outside of the bubbling path. - -When two keyboard accelerators are defined with the same key combination, the first keyboard accelerator found on the visual tree is invoked. - -Scoped keyboard accelerators are invoked only when focus is inside a specific scope. For example, in a Grid that contains dozens of controls, a keyboard accelerator can be invoked for a control only when focus is within the Grid (the scope owner). - -### Scoping accelerators programmatically - -The [UIElement.TryInvokeKeyboardAccelerator](/uwp/api/windows.ui.xaml.uielement.tryinvokekeyboardaccelerator) method invokes any matching accelerators in the subtree of the element. - -The [UIElement.OnProcessKeyboardAccelerators](/uwp/api/windows.ui.xaml.uielement.onprocesskeyboardaccelerators) method is executed before the keyboard accelerator. This method passes a [ProcessKeyboardAcceleratorArgs](/uwp/api/windows.ui.xaml.input.processkeyboardacceleratoreventargs) object that contains the key, the modifier, and a Boolean indicating whether the keyboard accelerator is handled. If marked as handled, the keyboard accelerator bubbles (so the outside keyboard accelerator is never invoked). - -> [!NOTE] -> OnProcessKeyboardAccelerators always fires, whether handled or not (similar to the OnKeyDown event). You must check whether the event was marked as handled. - -In this example, we use OnProcessKeyboardAccelerators and TryInvokeKeyboardAccelerator to scope keyboard accelerators to the Page object: - -``` csharp -protected override void OnProcessKeyboardAccelerators( - ProcessKeyboardAcceleratorArgs args) -{ - if(args.Handled != true) - { - this.TryInvokeKeyboardAccelerator(args); - args.Handled = true; - } -} -``` - -### Localize the accelerators - -We recommend localizing all keyboard accelerators. You can do this with the standard resources (.resw) file and the x:Uid attribute in your XAML declarations. In this example, the Windows Runtime automatically loads the resources. - -![Diagram of keyboard accelerator localization with the resources file](images/accelerators/accelerators_localization.png) -***Keyboard accelerator localization with the resources file*** - -``` xaml - -``` - -> [!NOTE] -> Keyboard accelerators are implemented as virtual-keys. Localized accelerators must be chosen from the predefined collection of [Virtual-Key codes](/windows/win32/inputdev/virtual-key-codes) (otherwise, a XAML parser error will occur). - -### Setup an accelerator programmatically - -Here is an example of programmatically defining an accelerator: - -``` csharp -void AddAccelerator( - VirtualKeyModifiers keyModifiers, - VirtualKey key, - TypedEventHandler handler ) - { - var accelerator = - new KeyboardAccelerator() - { - Modifiers = keyModifiers, Key = key - }; - accelerator.Invoked += handler; - this.KeyboardAccelerators.Add(accelerator); - } -``` - -> [!NOTE] -> KeyboardAccelerator is not shareable, the same KeyboardAccelerator can't be added to multiple elements. - -### Override keyboard accelerator behavior - -You can handle the [KeyboardAccelerator.Invoked](/uwp/api/windows.ui.xaml.input.keyboardaccelerator.Invoked) event to override the default KeyboardAccelerator behavior. - -This example shows how to override the "Select all" command (Ctrl+A keyboard accelerator) in a custom ListView control. We also set the Handled property to true to stop the event bubbling further. - -```csharp -public class MyListView : ListView -{ - … - protected override void OnKeyboardAcceleratorInvoked(KeyboardAcceleratorInvokedEventArgs args) - { - if(args.Accelerator.Key == VirtualKey.A - && args.Accelerator.Modifiers == KeyboardModifiers.Control) - { - CustomSelectAll(TypeOfSelection.OnlyNumbers); - args.Handled = true; - } - } - … -} -``` - -## Related articles - -- [Keyboard interactions](../../design/input/keyboard-interactions.md) -- [Access keys](../../design/input/access-keys.md) -- [VirtualKey Enum](/uwp/api/windows.system.virtualkey) - -### Samples - -- [WinUI 3 Gallery](https://github.com/Microsoft/WinUI-Gallery) +--- +description: Learn how accelerator keys can improve the usability and accessibility of Windows apps. +title: Keyboard accelerators +label: Keyboard accelerators +template: detail.hbs +keywords: keyboard, accelerator, accelerator key, keyboard shortcuts, accessibility, navigation, focus, text, input, user interactions, gamepad, remote +ms.date: 07/09/2021 +ms.topic: article +pm-contact: chigy +design-contact: miguelrb +doc-status: Draft +ms.localizationpriority: medium +--- + +# Keyboard accelerators + +![Hero image of the Surface keyboard](images/accelerators/accelerators_hero2.png) + +Accelerator keys (or keyboard accelerators) are keyboard shortcuts that improve the usability and accessibility of your Windows applications by providing an intuitive way for users to invoke common actions or commands without navigating the app UI. + +> [!NOTE] +> A keyboard is indispensable for users with certain disabilities (see [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md)), and is also an important tool for users who prefer it as a more efficient way to interact with an app. + +See the [Access keys](../../design/input/access-keys.md) topic for details on navigating the UI of a Windows application with keyboard shortcuts. + +To create your own custom keyboard shortcuts, see the [Keyboard events](../../design/input/keyboard-events.md) topic. + +## Overview + +Accelerators are composed of two types of keys: modifiers and non-modifiers. Modifier keys include Shift, Menu, Control, and the Windows key, which are exposed through [VirtualKeyModifiers](/uwp/api/Windows.System.VirtualKeyModifiers). Non-modifiers include any [VirtualKey](/uwp/api/windows.system.virtualkey), such as Delete, F3, Spacebar, Arrow, Esc, and all alphanumeric and punctuation keys. + +> [!NOTE] +> Accelerators typically include the function keys F1 through F12 or some combination of a standard key paired with one or more modifier keys (CTRL, Shift). For example, if a user presses Ctrl+Shift+M, the framework checks the modifiers (Ctrl and Shift) and fires the accelerator, if it exists. + +Many XAML controls have built-in keyboard accelerators. For example, ListView supports Ctrl+A for selecting all the items in the list, and RichEditBox supports Ctrl+Tab for inserting a Tab in the text box. These built-in keyboard accelerators are referred to as **control accelerators** and are executed only if the focus is on the element or one of its children. Accelerators defined by you using the keyboard accelerator APIs discussed here are referred to as **app accelerators**. + +Keyboard accelerators are not available for every action but are often associated with commands exposed in menus (and should be specified with the menu item content). Accelerators can also be associated with actions that do not have equivalent menu items. However, because users rely on an application's menus to discover and learn the available command set, you should try to make discovery of accelerators as easy as possible (using labels or established patterns can help with this). + +An accelerator auto-repeats (for example, when the user presses Ctrl+Shift and then holds down M, the accelerator is invoked repeatedly until M is released). This behavior cannot be modified. + +![Screenshot of keyboard accelerators in a menu item label.](images/accelerators/accelerators_menuitemlabel.png) +*Keyboard accelerators described in a menu item label* + +## When to use keyboard accelerators + +We recommend that you specify keyboard accelerators wherever appropriate in your UI, and support accelerators in all custom controls. + +- Keyboard accelerators make your app more accessible for users with motor disabilities, including those users who can press only one key at a time or have difficulty using a mouse. + + A well-designed keyboard UI is an important aspect of software accessibility. It enables users with vision impairments or who have certain motor disabilities to navigate an app and interact with its features. Such users might not be able to operate a mouse and instead rely on various assistive technologies such as keyboard enhancement tools, on-screen keyboards, screen enlargers, screen readers, and voice input utilities. For these users, comprehensive command coverage is crucial. + +- Keyboard accelerators make your app more usable for power users who prefer to interact through the keyboard. + + Experienced users often have a strong preference for using the keyboard because keyboard-based commands can be entered more quickly and don't require them to remove their hands from the keyboard. For these users, efficiency and consistency are crucial; comprehensiveness is important only for the most frequently used commands. + +## Specify a keyboard accelerator + +Use the [KeyboardAccelerator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator.-ctor) APIs to create keyboard accelerators in Windows apps. With these APIs, you don't have to handle multiple KeyDown events to detect the key combination pressed, and you can localize accelerators in the app resources. + +We recommend that you set keyboard accelerators for the most common actions in your app and document them using the menu item label or tooltip. In this example, we declare keyboard accelerators only for the Rename and Copy commands. + +``` xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +![Screenshot of a keyboard accelerator in a tooltip.](images/accelerators/accelerators_tooltip.png) +***Keyboard accelerator described in a tooltip*** + +The [UIElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement) object has a [KeyboardAccelerator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator) collection, [KeyboardAccelerators](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.KeyboardAccelerators), where you specify your custom KeyboardAccelerator objects and define the keystrokes for the keyboard accelerator: + +- **[Key](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator.Key)** - the [VirtualKey](/uwp/api/windows.system.virtualkey) used for the keyboard accelerator. + +- **[Modifiers](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator.Modifiers)** – the [VirtualKeyModifiers](/uwp/api/windows.system.virtualkeymodifiers) used for the keyboard accelerator. If Modifiers is not set, the default value is None. + +> [!NOTE] +> Single key (A, Delete, F2, Spacebar, Esc, Multimedia Key) accelerators and multi-key accelerators (Ctrl+Shift+M) are supported. However, Gamepad virtual keys are not supported. + +## Scoped accelerators + +Some accelerators work only in specific scopes while others work app-wide. + +For example, Microsoft Outlook includes the following accelerators: +- Ctrl+B, Ctrl+I and ESC work only on the scope of the send email form +- Ctrl+1 and Ctrl+2 work app-wide + +### Context menus + +Context menu actions affect only specific areas or elements, such as the selected characters in a text editor or a song in a playlist. For this reason, we recommend setting the scope of keyboard accelerators for context menu items to the parent of the context menu. + +Use the [ScopeOwner](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator.ScopeOwner) property to specify the scope of the keyboard accelerator. This code demonstrates how to implement a context menu on a ListView with scoped keyboard accelerators: + +``` xaml + + + + + + + + + + + + + + + + + + + + + + + + + Track 1 + Alternative Track 1 + + +``` + +The ScopeOwner attribute of the MenuFlyoutItem.KeyboardAccelerators element marks the accelerator as scoped instead of global (the default is null, or global). For more detail, see the **Resolving accelerators** section later in this topic. + +## Invoke a keyboard accelerator + +The [KeyboardAccelerator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator) object uses the [UI Automation (UIA) control pattern](/windows/desktop/WinAuto/uiauto-controlpatternsoverview) to take action when an accelerator is invoked. + +The UIA [control patterns] expose common control functionality. For example, the Button control implements the [Invoke](/windows/desktop/WinAuto/uiauto-implementinginvoke) control pattern to support the Click event (typically a control is invoked by clicking, double-clicking, or pressing Enter, a predefined keyboard shortcut, or some other combination of keystrokes). When a keyboard accelerator is used to invoke a control, the XAML framework looks up whether the control implements the Invoke control pattern and, if so, activates it (it is not necessary to listen for the KeyboardAcceleratorInvoked event). + +In the following example, Control+S triggers the Click event because the button implements the Invoke pattern. + +``` xaml + +``` + +If an element implements multiple control patterns, only one can be activated through an accelerator. The control patterns are prioritized as follows: +1. Invoke (Button) +2. Toggle (Checkbox) +3. Selection (ListView) +4. Expand/Collapse (ComboBox)  + +If no match is identified, the accelerator is invalid and a debug message is provided ("No automation patterns for this component found. Implement all desired behavior in the Invoked event. Setting Handled to true in your event handler suppresses this message.") + +## Custom keyboard accelerator behavior + +The Invoked event of the [KeyboardAccelerator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator) object is fired when the accelerator is executed. The [KeyboardAcceleratorInvokedEventArgs](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardacceleratorinvokedeventargs) event object includes the following properties: + +- [**Handled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardacceleratorinvokedeventargs.handled) (Boolean): Setting this to true prevents the event triggering the control pattern and stops accelerator event bubbling. The default is false. +- [**Element**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardacceleratorinvokedeventargs.element) (DependencyObject): The object associated with the accelerator. +- [**KeyboardAccelerator**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardacceleratorinvokedeventargs.keyboardaccelerator): The keyboard accelerator used to raise the Invoked event. + +Here we demonstrate how to define a collection of keyboard accelerators for items in a ListView, and how to handle the Invoked event for each accelerator. + +``` xaml + + + + + + +``` + +``` csharp +void SelectAllInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) +{ + MyListView.SelectAll(); + args.Handled = true; +} + +void RefreshInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) +{ + MyListView.SelectionMode = ListViewSelectionMode.None; + MyListView.SelectionMode = ListViewSelectionMode.Multiple; + args.Handled = true; +} +``` + +## Override default keyboard behavior + +Some controls, when they have focus, support built-in keyboard accelerators that override any app-defined accelerator. For example, when a [TextBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox) has focus, the Control+C accelerator only copies the currently selected text (app-defined accelerators are ignored and no other functionality is executed). + +While we don't recommend overriding default control behaviors due to user familiarity and expectations, you can override a control's built-in keyboard accelerator. The following example shows how to override the Control+C keyboard accelerator for a [TextBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox) through the [PreviewKeyDown](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.previewkeydown) event handler: + +``` csharp + private void TextBlock_PreviewKeyDown(object sender, KeyRoutedEventArgs e) + { + var ctrlState = CoreWindow.GetForCurrentThread().GetKeyState(Windows.System.VirtualKey.Control); + var isCtrlDown = ctrlState == CoreVirtualKeyStates.Down || ctrlState + == (CoreVirtualKeyStates.Down | CoreVirtualKeyStates.Locked); + if (isCtrlDown && e.Key == Windows.System.VirtualKey.C) + { + // Your custom keyboard accelerator behavior. + + e.Handled = true; + } + } +``` + +## Disable a keyboard accelerator + +If a control is disabled, the associated accelerator is also disabled. In the following example, because the IsEnabled property of the ListView is set to false, the associated Control+A accelerator can't be invoked. + +``` xaml + + + + + + + + + + + + +``` + +Parent and child controls can share the same accelerator. In this case, the parent control can be invoked even if the child has focus and its accelerator is disabled. + +## Screen readers and keyboard accelerators + +Screen readers such as Narrator can announce the keyboard accelerator key combination to users. By default, this is each modifier (in the VirtualModifiers enum order) followed by the key (and separated by "+" signs). You can customize this through the [AcceleratorKey](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties.AcceleratorKeyProperty) AutomationProperties attached property. If more than one accelerator is specified, only the first is announced. + +In this example, the AutomationProperty.AcceleratorKey returns the string "Control+Shift+A": + +``` xaml + + + + + + + + + +    +``` + +> [!NOTE] +> Setting AutomationProperties.AcceleratorKey doesn't enable keyboard functionality, it only indicates to the UIA framework which keys are used. + +## Common Keyboard Accelerators + +We recommend that you make keyboard accelerators consistent across Windows applications. + +Users have to memorize keyboard accelerators and expect the same (or similar) results, but this might not always be possible due to differences in functionality across apps. + +| **Editing** | **Common Keyboard Accelerator** | +| ------------- | ----------------------------------- | +| Begin editing mode | Ctrl + E | +| Select all items in a focused control or window | Ctrl + A | +| Search and replace | Ctrl + H | +| Undo | Ctrl + Z | +| Redo | Ctrl + Y | +| Delete selection and copy it to the clipboard | Ctrl + X | +| Copy selection to the clipboard | Ctrl + C, Ctrl + Insert | +| Paste the contents of the clipboard | Ctrl + V, Shift + Insert | +| Paste the contents of the clipboard (with options) | Ctrl + Alt + V | +| Rename an item | F2 | +| Add a new item | Ctrl + N | +| Add a new secondary item | Ctrl + Shift + N | +| Delete selected item (with undo) | Del, Ctrl+D | +| Delete selected item (without undo) | Shift + Del | +| Bold | Ctrl + B | +| Underline | Ctrl + U | +| Italic | Ctrl + I | +| **Navigation** | | +| Find content in a focused control or Window | Ctrl + F | +| Go to the next search result | F3 | +| Go to the next UI pane | F6 | +| Go to the previous UI pane | Shift + F6 | +| **Other Actions** | | +| Add favorites | Ctrl + D | +| Refresh | F5 or Ctrl + R | +| Zoom In | Ctrl + + | +| Zoom out | Ctrl + - | +| Zoom to default view | Ctrl + 0 | +| Save | Ctrl + S | +| Close | Ctrl + W | +| Print | Ctrl + P | + +Notice that some of the combinations are not valid for localized versions of Windows. For example, in the Spanish version of Windows, Ctrl+N is used for bold instead of Ctrl+B. We recommend providing localized keyboard accelerators if the app is localized. + +## Usability affordances for keyboard accelerators + +### Tooltips + +As keyboard accelerators are not typically described directly in the UI of your Windows application, you can improve discoverability through [tooltips](../../design/controls/tooltips.md), which display automatically when the user moves focus to, presses and holds, or hovers the mouse pointer over a control. The tooltip can identify whether a control has an associated keyboard accelerator and, if so, what the accelerator key combination is. + +By default, when keyboard accelerators are declared, all controls (except [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MenuFlyoutItem) and [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem)) present the corresponding key combinations in a tooltip. + +> [!NOTE] +> If a control has more than one accelerator defined, only the first is presented. + +![Screenshot of a Save button with a tool tip above it that indicates support for the Ctrl+S accelerator.](images/accelerators/accelerators_tooltip_savebutton_small.png)
+*Accelerator key combo in tooltip* + +For [Button](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.button), [AppBarButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton), and [AppBarToggleButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton) objects, the keyboard accelerator is appended to the control's default tooltip. For [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton) and [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem) objects, the keyboard accelerator is displayed with the flyout text. + +> [!NOTE] +> Specifying a tooltip (see Button1 in the following example) overrides this behavior. + +```xaml + + + + + +``` + +![Screenshot of three buttons labeled Button1, Button2, and Button3 with a tool tip above Button2 that indicates support for the Windows+B accelerator.](images/accelerators/accelerators-button-small.png) + +*Accelerator key combo appended to Button's default tooltip* + +```xaml + + + + + +``` + +![Screenshot of a button with a Disk icon and a tool tip that includes the default Save text appended with the Ctrl+S accelerator in parentheses.](images/accelerators/accelerators-appbarbutton-small.png) + +*Accelerator key combo appended to AppBarButton's default tooltip* + +```xaml + + + + + + + + + + + + + + + + + + + +``` + +![Screenshot of a Menu with MenuFlyoutItems that include accelerator key combos.](images/accelerators/accelerators-appbar-menuflyoutitem-small.png)
+*Accelerator key combo appended to MenuFlyoutItem's text* + +Control the presentation behavior by using the [KeyboardAcceleratorPlacementMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.KeyboardAcceleratorPlacementMode) property, which accepts two values: [Auto](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardacceleratorplacementmode) or [Hidden](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardacceleratorplacementmode). + +```xaml + +``` + +In some cases, you might need to present a tooltip relative to another element (typically a container object). + +Here, we show how to use the KeyboardAcceleratorPlacementTarget property to display the keyboard accelerator key combination for a Save button with the Grid container instead of the button. + +```xaml + + + +``` + +### Labels + +In some cases, we recommend using a control's label to identify whether the control has an associated keyboard accelerator and, if so, what the accelerator key combination is. + +Some platform controls do this by default, specifically the [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MenuFlyoutItem) and [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem) objects, while the [AppBarButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton) and the [AppBarToggleButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton) do it when they appear in the overflow menu of the [CommandBar](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbar). + +![Keyboard accelerators described in a menu item label.](images/accelerators/accelerators_menuitemlabel.png) +*Keyboard accelerators described in a menu item label* + +You can override the default accelerator text for the label through the [KeyboardAcceleratorTextOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton.KeyboardAcceleratorTextOverride) property of the [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.MenuFlyoutItem), [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem), [AppBarButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton), and [AppBarToggleButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton) controls (use a single space for no text). + +> [!NOTE] +> The override text is not be presented if the system cannot detect an attached keyboard (you can check this yourself through the [KeyboardPresent](/uwp/api/windows.devices.input.keyboardcapabilities.KeyboardPresent) property). + +## Advanced Concepts + +Here, we review some low-level aspects of keyboard accelerators. + +### Input event priority + +Input events occur in a specific sequence that you can intercept and handle based on the requirements of your app. + +#### The KeyDown/KeyUp bubbling event + +In XAML, a keystroke is processed as if there is just one input bubbling pipeline. This input pipeline is used by the KeyDown/KeyUp events and character input. For example, if an element has focus and the user presses a key down, a KeyDown event is raised on the element, followed by the parent of the element, and so on up the tree, until the args.Handled property is true. + +The KeyDown event is also used by some controls to implement the built-in control accelerators. When a control has a keyboard accelerator, it handles the KeyDown event, which means that there won't be KeyDown event bubbling. For example, the RichEditBox supports copy with Ctrl+C. When Ctrl is pressed, the KeyDown event is fired and bubbles, but when the user presses C at the same time, the KeyDown event is marked Handled and is not raised (unless the handledEventsToo parameter of [UIElement.AddHandler](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.addhandler) is set to true). + +#### The CharacterReceived event + +As the [CharacterReceived](/uwp/api/windows.ui.core.corewindow.CharacterReceived) event is fired after the [KeyDown](/uwp/api/windows.ui.core.corewindow.KeyDown) event for text controls such as TextBox, you can cancel character input in the KeyDown event handler. + +#### The PreviewKeyDown and PreviewKeyUp events + +The preview input events are fired before any other events. If you don't handle these events, the accelerator for the element that has the focus is fired, followed by the KeyDown event. Both events bubble until handled. + + +![Diagram showing the key event sequence](images/accelerators/accelerators_keyevents.png) +***Key event sequence*** + +Order of events: + +Preview KeyDown events
+…
+App accelerator
+OnKeyDown method
+KeyDown event
+App accelerators on the parent
+OnKeyDown method on the parent
+KeyDown event on the parent
+(Bubbles to the root)
+…
+CharacterReceived event
+PreviewKeyUp events
+KeyUpEvents
+ +When the accelerator event is handled, the KeyDown event is also marked as handled. The KeyUp event remains unhandled. + +### Resolving accelerators + +A keyboard accelerator event bubbles from the element that has focus up to the root. If the event isn't handled, the XAML framework looks for other unscoped app accelerators outside of the bubbling path. + +When two keyboard accelerators are defined with the same key combination, the first keyboard accelerator found on the visual tree is invoked. + +Scoped keyboard accelerators are invoked only when focus is inside a specific scope. For example, in a Grid that contains dozens of controls, a keyboard accelerator can be invoked for a control only when focus is within the Grid (the scope owner). + +### Scoping accelerators programmatically + +The [UIElement.TryInvokeKeyboardAccelerator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.tryinvokekeyboardaccelerator) method invokes any matching accelerators in the subtree of the element. + +The [UIElement.OnProcessKeyboardAccelerators](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.onprocesskeyboardaccelerators) method is executed before the keyboard accelerator. This method passes a [ProcessKeyboardAcceleratorArgs](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.processkeyboardacceleratoreventargs) object that contains the key, the modifier, and a Boolean indicating whether the keyboard accelerator is handled. If marked as handled, the keyboard accelerator bubbles (so the outside keyboard accelerator is never invoked). + +> [!NOTE] +> OnProcessKeyboardAccelerators always fires, whether handled or not (similar to the OnKeyDown event). You must check whether the event was marked as handled. + +In this example, we use OnProcessKeyboardAccelerators and TryInvokeKeyboardAccelerator to scope keyboard accelerators to the Page object: + +``` csharp +protected override void OnProcessKeyboardAccelerators( + ProcessKeyboardAcceleratorArgs args) +{ + if(args.Handled != true) + { + this.TryInvokeKeyboardAccelerator(args); + args.Handled = true; + } +} +``` + +### Localize the accelerators + +We recommend localizing all keyboard accelerators. You can do this with the standard resources (.resw) file and the x:Uid attribute in your XAML declarations. In this example, the Windows Runtime automatically loads the resources. + +![Diagram of keyboard accelerator localization with the resources file](images/accelerators/accelerators_localization.png) +***Keyboard accelerator localization with the resources file*** + +``` xaml + +``` + +> [!NOTE] +> Keyboard accelerators are implemented as virtual-keys. Localized accelerators must be chosen from the predefined collection of [Virtual-Key codes](/windows/win32/inputdev/virtual-key-codes) (otherwise, a XAML parser error will occur). + +### Setup an accelerator programmatically + +Here is an example of programmatically defining an accelerator: + +``` csharp +void AddAccelerator( + VirtualKeyModifiers keyModifiers, + VirtualKey key, + TypedEventHandler handler ) + { + var accelerator = + new KeyboardAccelerator() + { + Modifiers = keyModifiers, Key = key + }; + accelerator.Invoked += handler; + this.KeyboardAccelerators.Add(accelerator); + } +``` + +> [!NOTE] +> KeyboardAccelerator is not shareable, the same KeyboardAccelerator can't be added to multiple elements. + +### Override keyboard accelerator behavior + +You can handle the [KeyboardAccelerator.Invoked](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.keyboardaccelerator.Invoked) event to override the default KeyboardAccelerator behavior. + +This example shows how to override the "Select all" command (Ctrl+A keyboard accelerator) in a custom ListView control. We also set the Handled property to true to stop the event bubbling further. + +```csharp +public class MyListView : ListView +{ + … + protected override void OnKeyboardAcceleratorInvoked(KeyboardAcceleratorInvokedEventArgs args) + { + if(args.Accelerator.Key == VirtualKey.A + && args.Accelerator.Modifiers == KeyboardModifiers.Control) + { + CustomSelectAll(TypeOfSelection.OnlyNumbers); + args.Handled = true; + } + } + … +} +``` + +## Related articles + +- [Keyboard interactions](../../design/input/keyboard-interactions.md) +- [Access keys](../../design/input/access-keys.md) +- [VirtualKey Enum](/uwp/api/windows.system.virtualkey) + +### Samples + +- [WinUI 3 Gallery](https://github.com/Microsoft/WinUI-Gallery) diff --git a/hub/apps/develop/input/keyboard-interactions.md b/hub/apps/develop/input/keyboard-interactions.md index 5a91723193..63ff7bfec5 100644 --- a/hub/apps/develop/input/keyboard-interactions.md +++ b/hub/apps/develop/input/keyboard-interactions.md @@ -1,576 +1,576 @@ ---- -description: Learn how to design and optimize your Windows apps so they provide the best experience possible for both keyboard power users and those with disabilities and other accessibility requirements. -title: Keyboard interactions -ms.assetid: FF819BAC-67C0-4EC9-8921-F087BE188138 -label: Keyboard interactions -template: detail.hbs -keywords: keyboard, accessibility, navigation, focus, text, input, user interactions, gamepad, remote -ms.date: 06/11/2024 -ms.topic: article -pm-contact: chigy -design-contact: kimsea -dev-contact: niallm -doc-status: Published ---- - -# Keyboard interactions - -![keyboard hero image](images/keyboard/keyboard-hero.jpg) - -Learn how to design and optimize your Windows apps so they provide the best experiences for both keyboard power users and those with disabilities and other accessibility requirements. - -Across devices, keyboard input is an important part of the overall Windows app interaction experience. A well-designed keyboard experience lets users efficiently navigate the UI of your app and access its full functionality without ever lifting their hands from the keyboard. - -In this topic, we focus specifically on Windows app design for keyboard input on PCs. However, a well-designed keyboard experience is important for supporting accessibility tools such as Windows Narrator, using [software keyboards](#software-keyboard) such as the touch keyboard and the On-Screen Keyboard (OSK), and for handling other input device types, such as a game pad or remote control. - -Many of the guidelines and recommendations discussed here, including [focus visuals](#focus-visuals), [access keys](#access-keys), and [UI navigation](#navigation), are also applicable to these other scenarios. - -**NOTE** While both hardware and software keyboards are used for text input, the focus of this topic is navigation and interaction. - -## Built-in support - -Along with the mouse, the keyboard is the most widely used peripheral on PCs and, as such, is a fundamental part of the PC experience. PC users expect a comprehensive and consistent experience from both the system and individual apps in response to keyboard input. - -All WinUI controls include built-in support for rich keyboard experiences and user interactions, while the platform itself provides an extensive foundation for creating keyboard experiences that you feel are best suited to both your custom controls and apps. - -## Custom experiences and efficient keyboarding -As mentioned, keyboard support is integral to ensuring your applications work great for users with different skills, abilities, and expectations. We recommend that you prioritize the following. -- Support keyboard navigation and interaction - - Ensure actionable items are identified as tab stops (and non-actionable items are not), and navigation order is logical and predictable (see [Tab stops](#tab-stops)) - - Set initial focus on the most logical element (see [Initial focus](#initial-focus)) - - Provide arrow key navigation for "inner navigations" (see [Navigation](#navigation)) -- Support keyboard shortcuts - - Provide accelerator keys for quick actions (see [Accelerators](#accelerators)) - - Provide access keys to navigate your application's UI (see [Access keys](../../design/input/access-keys.md)) - -### Focus visuals - -WinUI supports a single focus visual design that works well for all input types and experiences. -![Focus visual](images/keyboard/focus-visual.png) - -A focus visual: - -- Is shown when a UI element receives focus from a keyboard and/or gamepad/remote control -- Is rendered as a highlighted border around the UI element to indicate an action can be taken -- Helps a user navigate an app UI without getting lost -- Can be customized for your app (See [High visibility focus visuals](guidelines-for-visualfeedback.md#high-visibility-focus-visuals)) - -**NOTE** The WinUI focus visual is not the same as the Narrator focus rectangle. - -### Tab stops - -To use a control (including navigation elements) with the keyboard, the control must have focus. One way for a control to receive keyboard focus is to make it accessible through tab navigation by identifying it as a tab stop in your application's tab order. - -For a control to be included in the tab order, the [IsEnabled](/uwp/api/windows.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_IsEnabled) property must be set to **true** and the [IsTabStop](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_IsTabStop) property must be set to **true**. - -To specifically exclude a control from the tab order, set the [IsTabStop](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_IsTabStop) property to **false**. - -By default, tab order reflects the order in which UI elements are created. For example, if a `StackPanel` contains a `Button`, a `Checkbox`, and a `TextBox`, tab order is `Button`, `Checkbox`, and `TextBox`. - -You can override the default tab order by setting the [TabIndex](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) property. - -#### Tab order should be logical and predictable - -A well-designed keyboard navigation model, using a logical and predictable tab order, makes your app more intuitive and helps users explore, discover, and access functionality more efficiently and effectively. - -All interactive controls should have tab stops (unless they are in a [group](#control-group)), while non-interactive controls, such as labels, should not. - -Avoid a custom tab order that makes the focus jump around in your application. For example, a list of controls in a form should have a tab order that flows from top to bottom and left to right (depending on locale). - -See [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md) for more details about customizing tab stops. - -#### Try to coordinate tab order and visual order - -Coordinating tab order and visual order (also referred to as reading order or display order) helps reduce confusion for users as they navigate through your application's UI. - -Try to rank and present the most important commands, controls, and content first in both the tab order and the visual order. However, the actual display position can depend on the parent layout container and certain properties of the child elements that influence the layout. Specifically, layouts that use a grid metaphor or a table metaphor can have a visual order quite different from the tab order. - -**NOTE** Visual order is also dependent on locale and language. - -### Initial focus - -Initial focus specifies the UI element that receives focus when an application or a page is first launched or activated. When using a keyboard, it is from this element that a user starts interacting with your application's UI. - -For WinUI apps, initial focus is set to the element with the highest [TabIndex](/uwp/api/Windows.UI.Xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) that can receive focus. Child elements of container controls are ignored. In a tie, the first element in the visual tree receives focus. - -#### Set initial focus on the most logical element - -Set initial focus on the UI element for the first, or primary, action that users are most likely to take when launching your app or navigating to a page. Some examples include: -- A photo app where focus is set to the first item in a gallery -- A music app where focus is set to the play button - -#### Don't set initial focus on an element that exposes a potentially negative, or even disastrous, outcome - -This level of functionality should be a user's choice. Setting initial focus to an element with a significant outcome might result in unintended data loss or system access. For example, don't set focus to the delete button when navigating to an e-mail. - -See [Focus navigation](../../design/input/focus-navigation.md) for more details about overriding tab order. - -### Navigation - -Keyboard navigation is typically supported through the Tab keys and the Arrow keys. - -![tab and arrow keys](images/keyboard/tab-and-arrow.png) - -By default, WinUI controls follow these basic keyboard behaviors: -- **Tab keys** navigate between actionable/active controls in tab order. -- **Shift + Tab** navigate controls in reverse tab order. If user has navigated inside the control using arrow key, focus is set to the last known value inside the control. -- **Arrow keys** expose control-specific "inner navigation" When user enters "inner navigation,"" arrow keys do not navigate out of a control. Some examples include: - - Up/Down arrow key moves focus inside `ListView` and `MenuFlyout` - - Modify currently selected values for `Slider` and `RatingsControl` - - Move caret inside `TextBox` - - Expand/collapse items inside `TreeView` - -Use these default behaviors to optimize your application's keyboard navigation. - -#### Use "inner navigation" with sets of related controls - -Providing arrow key navigation into a set of related controls reinforces their relationship within the overall organization of your application's UI. - -For example, the `ContentDialog` control shown here provides inner navigation by default for a horizontal row of buttons (for custom controls, see the [Control Group](#control-group) section). - -![dialog example](images/keyboard/dialog.png) - -***Interaction with a collection of related buttons is made easier with arrow key navigation*** - -If items are displayed in a single column, Up/Down arrow key navigates items. If items are displayed in a single row, Right/Left arrow key navigates items. If items are multiple columns, all 4 arrow keys navigate. - -#### Define a single tab stop for a collection of related controls - -By defining a single tab stop for a collection of related, or complementary, controls, you can minimize the number of overall tab stops in your app. - -For example, the following images show two stacked `ListView` controls. The image on the left shows arrow key navigation used with a tab stop to navigate between `ListView` controls, while the image on the right shows how navigation between child elements could be made easier and more efficient by eliminating the need for to traverse parent controls with a tab key. - - - - - -
arrow and tabarrow only
- -***Interaction with two stacked ListView controls can be made easier and more efficient by eliminating the tab stop and navigating with just arrow keys.*** - -Visit [Control Group](#control-group) section to learn how to apply the optimization examples to your application UI. - -### Interaction and commanding - -Once a control has focus, a user can interact with it and invoke any associated functionality using specific keyboard input. - -#### Text entry - -For those controls specifically designed for text input such as `TextBox` and `RichEditBox`, all keyboard input is used for entering or navigating text, which takes priority over other keyboard commands. For example, the drop down menu for an `AutoSuggestBox` control does not recognize the **Space** key as a selection command. - -![text entry](images/keyboard/text-entry.png) - -#### Space key - -When not in text entry mode, the **Space** key invokes the action or command associated with the focused control (just like a tap with touch or a click with a mouse). - -![space key](images/keyboard/space-key.png) - -#### Enter key - -The **Enter** key can perform a variety of common user interactions, depending on the control with focus: -- Activates command controls such as a `Button` or `Hyperlink`. To avoid end user confusion, the **Enter** key also activates controls that look like command controls such as `ToggleButton` or `AppBarToggleButton`. -- Displays the picker UI for controls such as `ComboBox` and `DatePicker`. The **Enter** key also commits and closes the picker UI. -- Activates list controls such as `ListView`, `GridView`, and `ComboBox`. - - The **Enter** key performs the selection action as the **Space** key for list and grid items, unless there is an additional action associated with these items (opening a new window). - - If an additional action is associated with the control, the **Enter** key performs the additional action and the **Space** key performs the selection action. - -**NOTE** The **Enter** key and **Space** key do not always perform the same action, but often do. - -![enter key](images/keyboard/enter-key.png) - -#### Esc key - -The Esc key lets a user cancel transient UI (along with any ongoing actions in that UI). - -Examples of this experience include: -- User opens a `ComboBox` with a selected value and uses the arrow keys to move the focus selection to a new value. Pressing the Esc key closes the `ComboBox` and resets the selected value back to the original value. -- User invokes a permanent delete action for an email and is prompted with a `ContentDialog` to confirm the action. The user decides this is not the intended action and presses the **Esc** key to close the dialog. As the **Esc** key is associated with the **Cancel** button, the dialog is closed and the action is canceled. The **Esc** key only affects transient UI, it does not close, or back navigate through, app UI. - -![Esc key](images/keyboard/esc-key.png) - -#### Home and End keys - -The **Home** and **End** keys let a user scroll to the beginning or end of a UI region. - -Examples of this experience include: -- For `ListView` and `GridView` controls, the **Home** key moves focus to the first element and scrolls it into view, whereas the **End** key moves focus to the last element and scrolls it into view. -- For a `ScrollView` control, the **Home** key scrolls to the top of the region, whereas the **End** key scrolls to the bottom of the region (focus is not changed). - -![home and end keys](images/keyboard/home-and-end.png) - -#### Page up and Page down keys - -The **Page** keys let a user scroll a UI region in discrete increments. - -For example, for `ListView` and `GridView` controls, the **Page up** key scrolls the region up by a "page" (typically the viewport height) and moves focus to the top of the region. Alternately, the **Page down** key scrolls the region down by a page and moves focus to the bottom of the region. - -![page up and down keys](images/keyboard/page-up-and-down.png) - -#### F6 key - -The **F6** key lets a user cycle between panes or important sections of your app or UI. **Shift-F6** typically cycles backwards (see [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md)). - -These are often related to [landmarks and headings](../../design/accessibility/landmarks-and-headings.md), but do not need to correspond directly. - -For example: - -- In Edge, pressing F6 will cycle between the tab bar, the address bar/app bar, and the page content. -- In File Explorer, pressing F6 will cycle between the sections of the app. -- On the desktop, pressing F6 will cycle between parts of the taskbar and the desktop. - -![f6 key](images/keyboard/f6.png) - -### Keyboard shortcuts - -In addition to implementing keyboard navigation and activation, it is also good practice to implement keyboard shortcuts such as [keyboard accelerators](../../design/input/keyboard-accelerators.md) and [access keys](../../design/input/access-keys.md) for important or frequently used functionality. - -Keyboard shortcuts can make your app easier to use by providing both enhanced support for accessibility and improved efficiency for keyboard users. - -A shortcut is a keyboard combination that enhances productivity by providing an efficient way for the user to access app functionality. There are two kinds of shortcut: - - -- [Accelerators](#accelerators) are shortcuts that invoke an app command. Your app may or may not provide specific UI that corresponds to the command. Accelerators typically consist of the Ctrl key plus a letter key. -- [Access keys](#access-keys) are shortcuts that set focus to specific UI in your application. Access keys typically consist of the Alt key plus a letter key. - - -Providing consistent keyboard shortcuts that support similar tasks across applications makes them much more useful and powerful and helps users remember them. - -#### Accelerators - -Accelerators help users perform common actions in an application much more quickly and efficiently. - -Examples of Accelerators: -- Pressing Ctrl + N key anywhere in the **Mail** app launches a new mail item. -- Pressing Ctrl + E key anywhere in Microsoft Edge (and many Microsoft Store applications) launches search. - -Accelerators have the following characteristics: -- They primarily use Ctrl and Function key sequences (Windows system shortcut keys also use Alt + non-alphanumeric keys and the Windows logo key). -- They are assigned only to the most commonly used commands. -- They are intended to be memorized, and are documented only in menus, tooltips, and Help. -- They have effect throughout the entire application, when supported. -- They should be assigned consistently as they are memorized and not directly documented. - -#### Access keys - -See [Access keys](../../design/input/access-keys.md) page for more in-depth information for supporting access keys with WinUI. - -Access keys help users with motor function disabilities an ability to press one key at a time to action on a specific item in the UI. Moreover, access keys can be used to communicate additional shortcut keys to help advanced users perform actions quickly. - -Access keys have the following characteristics: -- They use the Alt key plus an alphanumeric key. -- They are primarily for accessibility. -- They are documented directly in the UI, adjacent to the control, through [Key Tips](../../design/input/access-keys.md). -- They have effect only in the current window, and navigate to the corresponding menu item or control. -- Access keys should be assigned consistently to commonly used commands (especially commit buttons), whenever possible. -- They are localized. - -#### Common keyboard shortcuts - -The following table is a small sample of frequently used keyboard shortcuts. - -| Action | Key command | -|--------------------------------------|--------------------------------------------------| -| Select all | Ctrl+A | -| Continuously select | Shift+Arrow key | -| Save | Ctrl+S | -| Find | Ctrl+F | -| Print | Ctrl+P | -| Copy | Ctrl+C | -| Cut | Ctrl+X | -| Paste | Ctrl+V | -| Undo | Ctrl+Z | -| Next tab | Ctrl+Tab | -| Close tab | Ctrl+F4 or Ctrl+W | -| Semantic zoom | Ctrl++ or Ctrl+- | - -For a comprehensive list of Windows system shortcuts, see [keyboard shortcuts for Windows](https://support.microsoft.com/help/12445/windows-keyboard-shortcuts). For common application shortcuts, see [keyboard shortcuts for Microsoft applications](https://support.microsoft.com/help/13805/windows-keyboard-shortcuts-in-apps). - -## Advanced experiences - -In this section, we discuss some of the more complex keyboard interaction experiences supported by WinUI apps, along with some of the behaviors you should be aware of when your app is used on different devices and with different tools. - -### Control group - -You can group a set of related, or complementary, controls in a "control -group" (or directional area), which enables "inner navigation" using the -arrow keys. The control group can be a single tab stop, or you can -specify multiple tab stops within the control group. - -#### Arrow key navigation - -Users expect support for arrow key navigation when there is a group of similar, related controls in a UI region: -- `AppBarButtons` in a `CommandBar` -- `ListItems` or `GridItems` inside `ListView` or `GridView` -- `Buttons` inside `ContentDialog` - -WinUI controls support arrow key navigation by default. For custom layouts and control groups, use `XYFocusKeyboardNavigation="Enabled"` to provide similar behavior. - -Consider adding support for arrow key navigation when using the following controls: - - - - - - -
-

Dialog buttons

-

Dialog buttons

-

Radio buttons

-

RadioButtons

-
-

AppBar buttons

-

AppBarButtons

-

List and Grid items

-

ListItems and GridItems

-
- -#### Tab stops - -Depending on your application's functionality and layout, the best navigation option for a control group might be a single tab stop with arrow navigation to child elements, multiple tab stops, or some combination. - -##### Use multiple tab stops and arrow keys for buttons - -Accessibility users rely on well-established keyboard navigation rules, which do not typically use arrow keys to navigate a collection of buttons. However, users without visual impairments might feel that the behavior is natural. - -An example of default WinUI behavior in this case is the `ContentDialog`. While arrow keys can be used to navigate between buttons, each button is also a tab stop. - -##### Assign single tab stop to familiar UI patterns - -In cases where your layout follows a well-known UI pattern for control groups, assigning a single tab stop to the group can improve navigation efficiency for users. - -Examples include: -- `RadioButtons` -- Multiple `ListViews` that look like and behave like a single `ListView` -- Any UI made to look and behave like grid of tiles (such as the Start menu tiles) - -#### Specifying control group behavior - -Use the following APIs to support custom control group behavior (all are discussed in more detail later in this topic): - -- [XYFocusKeyboardNavigation](focus-navigation.md#2d-directional-navigation-for-keyboard) enables arrow key navigation between controls -- [TabFocusNavigation](focus-navigation.md#tab-navigation) indicates whether there are multiple tab stops or single tab stop -- [FindFirstFocusableElement and FindLastFocusableElement](focus-navigation-programmatic.md#find-the-first-and-last-focusable-element) sets focus on the first item with **Home** key and the last item with **End** key - -The following image shows an intuitive keyboard navigation behavior for a control group of associated radio buttons. In this case, we recommend a single tab stop for the control group, inner navigation between the radio buttons using the arrow keys, **Home** key bound to the first radio button, and **End** key bound to the last radio button. - -![putting it all together](images/keyboard/putting-it-all-together.png) - -### Keyboard and Narrator - -Narrator is a UI accessibility tool geared towards keyboard users (other input types are also supported). However, Narrator functionality goes beyond the keyboard interactions supported by WinUI apps and extra care is required when designing your WinUI app for Narrator. (The [Narrator basics page](https://support.microsoft.com/help/22808/windows-10-narrator-basics) guides you through the Narrator user experience.) - -Some of the differences between WinUI keyboard behaviors and those supported by Narrator include: -- Extra key combinations for navigation to UI elements that are not exposed through standard keyboard navigation, such as Caps lock + arrow keys to read control labels. -- Navigation to disabled items. By default, disabled items are not exposed through standard keyboard navigation. -- Control "views" for quicker navigation based on UI granularity. Users can navigate to items, characters, word, lines, paragraphs, links, headings, tables, landmarks, and suggestions. Standard keyboard navigation exposes these objects as a flat list, which might make navigation cumbersome unless you provide shortcut keys. - -#### Case Study – AutoSuggestBox control - -The search button for the `AutoSuggestBox` is not accessible to standard keyboard navigation using tab and arrow keys because the user can press the **Enter** key to submit the search query. However, it is accessible through Narrator when the user presses Caps Lock + an arrow key. - -![autosuggest keyboard focus](images/keyboard/auto-suggest-keyboard.png) - -*With keyboard, users press the* ***Enter*** *key to submit search query* - - - - - - -
-

autosuggest narrator focus

-

With Narrator, users press the Enter key to submit search query

-
-

autosuggest narrator focus on search

-

With Narrator, users are also able to access the search button using the Caps Lock + Right arrow key, then pressing Space key

-
- -### Keyboard, game pad, and remote control - -Game pads and remote controls support many WinUI keyboard behaviors and experiences. However, due to the lack of various key options available on a keyboard, game pad and remote control lack many keyboard optimizations (remote control is even more limited than game pad). - -See [Game pad and remote control interactions](../../design/input/gamepad-and-remote-interactions.md) for more detail on WinUI support for game pad and remote control input. - -The following shows some key mappings between keyboard, game pad, and remote control. - -| **Keyboard** | **Game pad** | **Remote control** | -|---------------|-------------------------------------|---------------------| -| Space | A button | Select button | -| Enter | A button | Select button | -| Escape | B button | Back button | -| Home/End | N/A | N/A | -| Page Up/Down | Trigger button for vertical scroll, Bumper button for horizontal scroll | N/A | - -Some key differences you should be aware of when designing your WinUI app for use with game pad and remote control usage include: -- Text entry requires the user to press A to activate a text control. -- Focus navigation is not limited to control groups, users can navigate freely to any focusable UI element in the app. - - **NOTE** Focus can move to any focusable UI element in the key press direction unless it is in an overlay UI or [focus engagement](gamepad-and-remote-interactions.md#focus-engagement) is specified, which prevents focus from entering/exiting a region until engaged/disengaged with the A button. For more info, see the [directional navigation](#directional-navigation) section. -- D-pad and left stick buttons are used to move focus between controls and for inner navigation. - - **NOTE** Gamepad and remote control only navigate to items that are in the same visual order as the directional key pressed. Navigation is disabled in that direction when there is no subsequent element that can receive focus. Depending on the situation, keyboard users do not always have that constraint. See the [Built in keyboard optimization](#built-in-keyboard-optimization) section for more info. - -#### Directional navigation - -Directional navigation is managed by a WinUI [Focus Manager](/uwp/api/Windows.UI.Xaml.Input.FocusManager) helper class, which takes the directional key pressed (arrow key, D-pad) and attempts to move focus in the corresponding visual direction. - -**NOTE** Navigation using the keyboard Tab key is not considered directional navigation. For more info, see the [Tab stops](#tab-stops) section. - - - - - - -
-

directional navigation

-

Directional navigation supported
Using directional keys (keyboard arrows, gamepad and remote control D-pad), user can navigate between different controls.

-
-

no directional navigation

-

Directional navigation not supported
User cannot navigate between different controls using directional keys. Other methods of navigating between controls (tab key) are not impacted.

-
- -### Built in keyboard optimization - -Depending on the layout and controls used, WinUI apps can be optimized specifically for keyboard input. - -The following example shows a group of list items, grid items, and menu items that have been assigned to a single tab stop (see the [Tab stops](#tab-stops) section). When the group has focus, inner navigation is performed with the directional arrow keys in the corresponding visual order (see [Navigation](#navigation) section). - -![single column arrow key navigation](images/keyboard/single-column-arrow.png) - -***Single Column Arrow Key Navigation*** - -![single row arrow key navigation](images/keyboard/single-row-arrow.png) - -***Single Row Arrow Key Navigation*** - -![multiple column and row arrow key navigation](images/keyboard/multiple-column-and-row-navigation.png) - -***Multiple Column/Row Arrow Key Navigation*** - -#### Wrapping homogeneous List and Grid View Items - -Directional navigation is not always the most efficient way to navigate multiple rows and columns of List and GridView items. - -**NOTE** Menu items are typically single column lists, but special focus rules might apply in some cases (see [Popup UI](#popup-ui)). - -List and Grid objects can be created with multiple rows and columns. These are typically in row-major (where items fill entire row first before filling in the next row) or column-major (where items fill entire column first before filling in the next column) order. Row or column major order depends on scroll direction and you should ensure that item -order does not conflict with this direction. - -In row-major order (where items fill in left to right, top to bottom), when the focus is on the last item in a row and the Right arrow key is pressed, focus is moved to the first item in the next row. This same behavior occurs in reverse: When focus is set to the first item in a row and the Left arrow key is pressed, focus is moved to the last item in -the previous row. - -In column-major order (where items fill in top to bottom, left to right), when the focus is on the last item in a column and user presses the Down arrow key, focus is moved to the first item in the next column. This same behavior occurs in reverse: When focus is set to the first item in a column and the Up arrow key is pressed, focus is moved to the -last item in the previous column. - - - - - - -
-

row major keyboard navigation

-

Row major keyboard navigation

-
-

column major keyboard navigation

-

Column major keyboard navigation

-
- -#### Popup UI - -As mentioned, you should try to ensure directional navigation corresponds to the visual order of the controls in your application's UI. - -Some controls (such as the context menu, CommandBar overflow menu, and AutoSuggest menu) display a menu popup in a location and direction (downwards by default) relative to the primary control and available screen space. Note that the opening direction can be affected by a variety of factors at run time. - - - - -
command bar opens down with down arrow keycommand bar opens up with down arrow key
- -For these controls, when the menu is first opened (and no item has been selected by the user), the Down arrow key always sets focus to the first item while the Up arrow key always sets focus to the last item on the menu. - -If the last item has focus and the Down arrow key is pressed, focus moves to the first item on the menu. Similarly, if the first item has focus and the Up arrow key is pressed, focus moves to the last item on the menu. This behavior is referred to as *cycling* and is useful for navigating popup menus that can open in unpredictable directions. - -> [!NOTE] -> Cycling should be avoided in non-popup UIs where users might come to feel trapped in an endless loop. - -We recommend that you emulate these same behaviors in your custom controls. Code sample on how to implement this behavior can be found in [Programmatic focus navigation](focus-navigation-programmatic.md#find-the-first-and-last-focusable-element) documentation. - - -## Test your app - -Test your app with all supported input devices to ensure UI elements can be navigated to in a coherent and intuitive way and that no unexpected elements interfere with the desired tab order. - -## Related articles - -* [Keyboard events](../../design/input/keyboard-events.md) -* [Identify input devices](../../design/input/identify-input-devices.md) -* [Respond to the presence of the touch keyboard](../../design/input/respond-to-the-presence-of-the-touch-keyboard.md) -* [Focus visuals sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlFocusVisuals) -* [NavigationView control keyboarding specifics](../ui/controls/navigationview.md#hierarchical-navigation) -* [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md) - -## Appendix - -### Software keyboard - -A software keyboard is displayed on screen and used instead of the physical keyboard to type and enter data using touch, mouse, pen/stylus or other pointing device. On gaming devices, individual keys need to be selected by moving focus visual or using shortcut keys on a game pad or remote control. - -#### Touch keyboard - -![Windows 11 touch keyboard](images/keyboard/default.png) - -***Windows 11 Touch Keyboard*** - -Depending on the device, the touch keyboard appears when a text field or other editable text control gets focus, or when the user manually enables it through the **Notification Center**: - -![Screenshot of the touch keyboard icon in the notification center.](images/keyboard/touch-keyboard-notificationcenter.png) - -If your app sets focus programmatically to a text input control, the touch keyboard is not invoked. This eliminates unexpected behaviors not instigated directly by the user. However, the keyboard does automatically hide when focus is moved programmatically to a non-text input control. - -The touch keyboard typically remains visible while the user navigates between controls in a form. This behavior can vary based on the other control types within the form. - -The following is a list of non-edit controls that can receive focus during a text entry session using the touch keyboard without dismissing the keyboard. Rather than needlessly churn the UI and potentially disorient the user, the touch keyboard remains in view because the user is likely to go back and forth between these controls and text entry with the touch keyboard. - -- Check box -- Combo box -- Radio button -- Scroll bar -- Tree -- Tree item -- Menu -- Menu bar -- Menu item -- Toolbar -- List -- List item - -Here are examples of different modes for the touch keyboard. The first image is the default layout, the second is the expanded layout (which might not be available in all languages). - -![Screenshot of the touch keyboard in default layout mode.](images/keyboard/default.png) - -***The touch keyboard in default layout mode*** - -![Screenshot of the touch keyboard in expanded layout mode.](images/keyboard/extendedview.png) - -***The touch keyboard in expanded layout mode*** - -Successful keyboard interactions enable users to accomplish basic app scenarios using only the keyboard; that is, users can reach all interactive elements and activate default functionality. A number of factors can affect the degree of success, including keyboard navigation, access keys for accessibility, and accelerator (or shortcut) keys for advanced users. - -#### On-Screen Keyboard - -Like the touch keyboard, the On-Screen Keyboard (OSK) is a visual, software keyboard used instead of the physical keyboard to type and enter data using touch, mouse, pen/stylus or other pointing device (a touch screen is not required). The OSK is provided for systems that don't have a physical keyboard, or for users whose mobility impairments prevent them from using traditional physical input devices. The OSK emulates most, if not all, the functionality of a hardware keyboard. - -The OSK can be turned on from the Keyboard page in Settings > Ease of access. - -**NOTE** The OSK has priority over the touch keyboard, which won't be shown if the OSK is present. - -![Screenshot of the On-Screen Keyboard.](images/keyboard/osk.png) - -***On-Screen Keyboard*** - -![Screenshot of the Xbox One On-Screen Keyboard.](images/keyboard/xbox-onscreen-keyboard.png) - -***Xbox One On-Screen Keyboard*** - -For more details, see [Use the On-Screen Keyboard to type](https://support.microsoft.com/help/10762/windows-use-on-screen-keyboard). +--- +description: Learn how to design and optimize your Windows apps so they provide the best experience possible for both keyboard power users and those with disabilities and other accessibility requirements. +title: Keyboard interactions +ms.assetid: FF819BAC-67C0-4EC9-8921-F087BE188138 +label: Keyboard interactions +template: detail.hbs +keywords: keyboard, accessibility, navigation, focus, text, input, user interactions, gamepad, remote +ms.date: 06/11/2024 +ms.topic: article +pm-contact: chigy +design-contact: kimsea +dev-contact: niallm +doc-status: Published +--- + +# Keyboard interactions + +![keyboard hero image](images/keyboard/keyboard-hero.jpg) + +Learn how to design and optimize your Windows apps so they provide the best experiences for both keyboard power users and those with disabilities and other accessibility requirements. + +Across devices, keyboard input is an important part of the overall Windows app interaction experience. A well-designed keyboard experience lets users efficiently navigate the UI of your app and access its full functionality without ever lifting their hands from the keyboard. + +In this topic, we focus specifically on Windows app design for keyboard input on PCs. However, a well-designed keyboard experience is important for supporting accessibility tools such as Windows Narrator, using [software keyboards](#software-keyboard) such as the touch keyboard and the On-Screen Keyboard (OSK), and for handling other input device types, such as a game pad or remote control. + +Many of the guidelines and recommendations discussed here, including [focus visuals](#focus-visuals), [access keys](#access-keys), and [UI navigation](#navigation), are also applicable to these other scenarios. + +**NOTE** While both hardware and software keyboards are used for text input, the focus of this topic is navigation and interaction. + +## Built-in support + +Along with the mouse, the keyboard is the most widely used peripheral on PCs and, as such, is a fundamental part of the PC experience. PC users expect a comprehensive and consistent experience from both the system and individual apps in response to keyboard input. + +All WinUI controls include built-in support for rich keyboard experiences and user interactions, while the platform itself provides an extensive foundation for creating keyboard experiences that you feel are best suited to both your custom controls and apps. + +## Custom experiences and efficient keyboarding +As mentioned, keyboard support is integral to ensuring your applications work great for users with different skills, abilities, and expectations. We recommend that you prioritize the following. +- Support keyboard navigation and interaction + - Ensure actionable items are identified as tab stops (and non-actionable items are not), and navigation order is logical and predictable (see [Tab stops](#tab-stops)) + - Set initial focus on the most logical element (see [Initial focus](#initial-focus)) + - Provide arrow key navigation for "inner navigations" (see [Navigation](#navigation)) +- Support keyboard shortcuts + - Provide accelerator keys for quick actions (see [Accelerators](#accelerators)) + - Provide access keys to navigate your application's UI (see [Access keys](../../design/input/access-keys.md)) + +### Focus visuals + +WinUI supports a single focus visual design that works well for all input types and experiences. +![Focus visual](images/keyboard/focus-visual.png) + +A focus visual: + +- Is shown when a UI element receives focus from a keyboard and/or gamepad/remote control +- Is rendered as a highlighted border around the UI element to indicate an action can be taken +- Helps a user navigate an app UI without getting lost +- Can be customized for your app (See [High visibility focus visuals](guidelines-for-visualfeedback.md#high-visibility-focus-visuals)) + +**NOTE** The WinUI focus visual is not the same as the Narrator focus rectangle. + +### Tab stops + +To use a control (including navigation elements) with the keyboard, the control must have focus. One way for a control to receive keyboard focus is to make it accessible through tab navigation by identifying it as a tab stop in your application's tab order. + +For a control to be included in the tab order, the [IsEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control#Windows_UI_Xaml_Controls_Control_IsEnabled) property must be set to **true** and the [IsTabStop](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_IsTabStop) property must be set to **true**. + +To specifically exclude a control from the tab order, set the [IsTabStop](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_IsTabStop) property to **false**. + +By default, tab order reflects the order in which UI elements are created. For example, if a `StackPanel` contains a `Button`, a `Checkbox`, and a `TextBox`, tab order is `Button`, `Checkbox`, and `TextBox`. + +You can override the default tab order by setting the [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) property. + +#### Tab order should be logical and predictable + +A well-designed keyboard navigation model, using a logical and predictable tab order, makes your app more intuitive and helps users explore, discover, and access functionality more efficiently and effectively. + +All interactive controls should have tab stops (unless they are in a [group](#control-group)), while non-interactive controls, such as labels, should not. + +Avoid a custom tab order that makes the focus jump around in your application. For example, a list of controls in a form should have a tab order that flows from top to bottom and left to right (depending on locale). + +See [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md) for more details about customizing tab stops. + +#### Try to coordinate tab order and visual order + +Coordinating tab order and visual order (also referred to as reading order or display order) helps reduce confusion for users as they navigate through your application's UI. + +Try to rank and present the most important commands, controls, and content first in both the tab order and the visual order. However, the actual display position can depend on the parent layout container and certain properties of the child elements that influence the layout. Specifically, layouts that use a grid metaphor or a table metaphor can have a visual order quite different from the tab order. + +**NOTE** Visual order is also dependent on locale and language. + +### Initial focus + +Initial focus specifies the UI element that receives focus when an application or a page is first launched or activated. When using a keyboard, it is from this element that a user starts interacting with your application's UI. + +For WinUI apps, initial focus is set to the element with the highest [TabIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Control#Windows_UI_Xaml_Controls_Control_TabIndex) that can receive focus. Child elements of container controls are ignored. In a tie, the first element in the visual tree receives focus. + +#### Set initial focus on the most logical element + +Set initial focus on the UI element for the first, or primary, action that users are most likely to take when launching your app or navigating to a page. Some examples include: +- A photo app where focus is set to the first item in a gallery +- A music app where focus is set to the play button + +#### Don't set initial focus on an element that exposes a potentially negative, or even disastrous, outcome + +This level of functionality should be a user's choice. Setting initial focus to an element with a significant outcome might result in unintended data loss or system access. For example, don't set focus to the delete button when navigating to an e-mail. + +See [Focus navigation](../../design/input/focus-navigation.md) for more details about overriding tab order. + +### Navigation + +Keyboard navigation is typically supported through the Tab keys and the Arrow keys. + +![tab and arrow keys](images/keyboard/tab-and-arrow.png) + +By default, WinUI controls follow these basic keyboard behaviors: +- **Tab keys** navigate between actionable/active controls in tab order. +- **Shift + Tab** navigate controls in reverse tab order. If user has navigated inside the control using arrow key, focus is set to the last known value inside the control. +- **Arrow keys** expose control-specific "inner navigation" When user enters "inner navigation,"" arrow keys do not navigate out of a control. Some examples include: + - Up/Down arrow key moves focus inside `ListView` and `MenuFlyout` + - Modify currently selected values for `Slider` and `RatingsControl` + - Move caret inside `TextBox` + - Expand/collapse items inside `TreeView` + +Use these default behaviors to optimize your application's keyboard navigation. + +#### Use "inner navigation" with sets of related controls + +Providing arrow key navigation into a set of related controls reinforces their relationship within the overall organization of your application's UI. + +For example, the `ContentDialog` control shown here provides inner navigation by default for a horizontal row of buttons (for custom controls, see the [Control Group](#control-group) section). + +![dialog example](images/keyboard/dialog.png) + +***Interaction with a collection of related buttons is made easier with arrow key navigation*** + +If items are displayed in a single column, Up/Down arrow key navigates items. If items are displayed in a single row, Right/Left arrow key navigates items. If items are multiple columns, all 4 arrow keys navigate. + +#### Define a single tab stop for a collection of related controls + +By defining a single tab stop for a collection of related, or complementary, controls, you can minimize the number of overall tab stops in your app. + +For example, the following images show two stacked `ListView` controls. The image on the left shows arrow key navigation used with a tab stop to navigate between `ListView` controls, while the image on the right shows how navigation between child elements could be made easier and more efficient by eliminating the need for to traverse parent controls with a tab key. + + + + + +
arrow and tabarrow only
+ +***Interaction with two stacked ListView controls can be made easier and more efficient by eliminating the tab stop and navigating with just arrow keys.*** + +Visit [Control Group](#control-group) section to learn how to apply the optimization examples to your application UI. + +### Interaction and commanding + +Once a control has focus, a user can interact with it and invoke any associated functionality using specific keyboard input. + +#### Text entry + +For those controls specifically designed for text input such as `TextBox` and `RichEditBox`, all keyboard input is used for entering or navigating text, which takes priority over other keyboard commands. For example, the drop down menu for an `AutoSuggestBox` control does not recognize the **Space** key as a selection command. + +![text entry](images/keyboard/text-entry.png) + +#### Space key + +When not in text entry mode, the **Space** key invokes the action or command associated with the focused control (just like a tap with touch or a click with a mouse). + +![space key](images/keyboard/space-key.png) + +#### Enter key + +The **Enter** key can perform a variety of common user interactions, depending on the control with focus: +- Activates command controls such as a `Button` or `Hyperlink`. To avoid end user confusion, the **Enter** key also activates controls that look like command controls such as `ToggleButton` or `AppBarToggleButton`. +- Displays the picker UI for controls such as `ComboBox` and `DatePicker`. The **Enter** key also commits and closes the picker UI. +- Activates list controls such as `ListView`, `GridView`, and `ComboBox`. + - The **Enter** key performs the selection action as the **Space** key for list and grid items, unless there is an additional action associated with these items (opening a new window). + - If an additional action is associated with the control, the **Enter** key performs the additional action and the **Space** key performs the selection action. + +**NOTE** The **Enter** key and **Space** key do not always perform the same action, but often do. + +![enter key](images/keyboard/enter-key.png) + +#### Esc key + +The Esc key lets a user cancel transient UI (along with any ongoing actions in that UI). + +Examples of this experience include: +- User opens a `ComboBox` with a selected value and uses the arrow keys to move the focus selection to a new value. Pressing the Esc key closes the `ComboBox` and resets the selected value back to the original value. +- User invokes a permanent delete action for an email and is prompted with a `ContentDialog` to confirm the action. The user decides this is not the intended action and presses the **Esc** key to close the dialog. As the **Esc** key is associated with the **Cancel** button, the dialog is closed and the action is canceled. The **Esc** key only affects transient UI, it does not close, or back navigate through, app UI. + +![Esc key](images/keyboard/esc-key.png) + +#### Home and End keys + +The **Home** and **End** keys let a user scroll to the beginning or end of a UI region. + +Examples of this experience include: +- For `ListView` and `GridView` controls, the **Home** key moves focus to the first element and scrolls it into view, whereas the **End** key moves focus to the last element and scrolls it into view. +- For a `ScrollView` control, the **Home** key scrolls to the top of the region, whereas the **End** key scrolls to the bottom of the region (focus is not changed). + +![home and end keys](images/keyboard/home-and-end.png) + +#### Page up and Page down keys + +The **Page** keys let a user scroll a UI region in discrete increments. + +For example, for `ListView` and `GridView` controls, the **Page up** key scrolls the region up by a "page" (typically the viewport height) and moves focus to the top of the region. Alternately, the **Page down** key scrolls the region down by a page and moves focus to the bottom of the region. + +![page up and down keys](images/keyboard/page-up-and-down.png) + +#### F6 key + +The **F6** key lets a user cycle between panes or important sections of your app or UI. **Shift-F6** typically cycles backwards (see [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md)). + +These are often related to [landmarks and headings](../../design/accessibility/landmarks-and-headings.md), but do not need to correspond directly. + +For example: + +- In Edge, pressing F6 will cycle between the tab bar, the address bar/app bar, and the page content. +- In File Explorer, pressing F6 will cycle between the sections of the app. +- On the desktop, pressing F6 will cycle between parts of the taskbar and the desktop. + +![f6 key](images/keyboard/f6.png) + +### Keyboard shortcuts + +In addition to implementing keyboard navigation and activation, it is also good practice to implement keyboard shortcuts such as [keyboard accelerators](../../design/input/keyboard-accelerators.md) and [access keys](../../design/input/access-keys.md) for important or frequently used functionality. + +Keyboard shortcuts can make your app easier to use by providing both enhanced support for accessibility and improved efficiency for keyboard users. + +A shortcut is a keyboard combination that enhances productivity by providing an efficient way for the user to access app functionality. There are two kinds of shortcut: + + +- [Accelerators](#accelerators) are shortcuts that invoke an app command. Your app may or may not provide specific UI that corresponds to the command. Accelerators typically consist of the Ctrl key plus a letter key. +- [Access keys](#access-keys) are shortcuts that set focus to specific UI in your application. Access keys typically consist of the Alt key plus a letter key. + + +Providing consistent keyboard shortcuts that support similar tasks across applications makes them much more useful and powerful and helps users remember them. + +#### Accelerators + +Accelerators help users perform common actions in an application much more quickly and efficiently. + +Examples of Accelerators: +- Pressing Ctrl + N key anywhere in the **Mail** app launches a new mail item. +- Pressing Ctrl + E key anywhere in Microsoft Edge (and many Microsoft Store applications) launches search. + +Accelerators have the following characteristics: +- They primarily use Ctrl and Function key sequences (Windows system shortcut keys also use Alt + non-alphanumeric keys and the Windows logo key). +- They are assigned only to the most commonly used commands. +- They are intended to be memorized, and are documented only in menus, tooltips, and Help. +- They have effect throughout the entire application, when supported. +- They should be assigned consistently as they are memorized and not directly documented. + +#### Access keys + +See [Access keys](../../design/input/access-keys.md) page for more in-depth information for supporting access keys with WinUI. + +Access keys help users with motor function disabilities an ability to press one key at a time to action on a specific item in the UI. Moreover, access keys can be used to communicate additional shortcut keys to help advanced users perform actions quickly. + +Access keys have the following characteristics: +- They use the Alt key plus an alphanumeric key. +- They are primarily for accessibility. +- They are documented directly in the UI, adjacent to the control, through [Key Tips](../../design/input/access-keys.md). +- They have effect only in the current window, and navigate to the corresponding menu item or control. +- Access keys should be assigned consistently to commonly used commands (especially commit buttons), whenever possible. +- They are localized. + +#### Common keyboard shortcuts + +The following table is a small sample of frequently used keyboard shortcuts. + +| Action | Key command | +|--------------------------------------|--------------------------------------------------| +| Select all | Ctrl+A | +| Continuously select | Shift+Arrow key | +| Save | Ctrl+S | +| Find | Ctrl+F | +| Print | Ctrl+P | +| Copy | Ctrl+C | +| Cut | Ctrl+X | +| Paste | Ctrl+V | +| Undo | Ctrl+Z | +| Next tab | Ctrl+Tab | +| Close tab | Ctrl+F4 or Ctrl+W | +| Semantic zoom | Ctrl++ or Ctrl+- | + +For a comprehensive list of Windows system shortcuts, see [keyboard shortcuts for Windows](https://support.microsoft.com/help/12445/windows-keyboard-shortcuts). For common application shortcuts, see [keyboard shortcuts for Microsoft applications](https://support.microsoft.com/help/13805/windows-keyboard-shortcuts-in-apps). + +## Advanced experiences + +In this section, we discuss some of the more complex keyboard interaction experiences supported by WinUI apps, along with some of the behaviors you should be aware of when your app is used on different devices and with different tools. + +### Control group + +You can group a set of related, or complementary, controls in a "control +group" (or directional area), which enables "inner navigation" using the +arrow keys. The control group can be a single tab stop, or you can +specify multiple tab stops within the control group. + +#### Arrow key navigation + +Users expect support for arrow key navigation when there is a group of similar, related controls in a UI region: +- `AppBarButtons` in a `CommandBar` +- `ListItems` or `GridItems` inside `ListView` or `GridView` +- `Buttons` inside `ContentDialog` + +WinUI controls support arrow key navigation by default. For custom layouts and control groups, use `XYFocusKeyboardNavigation="Enabled"` to provide similar behavior. + +Consider adding support for arrow key navigation when using the following controls: + + + + + + +
+

Dialog buttons

+

Dialog buttons

+

Radio buttons

+

RadioButtons

+
+

AppBar buttons

+

AppBarButtons

+

List and Grid items

+

ListItems and GridItems

+
+ +#### Tab stops + +Depending on your application's functionality and layout, the best navigation option for a control group might be a single tab stop with arrow navigation to child elements, multiple tab stops, or some combination. + +##### Use multiple tab stops and arrow keys for buttons + +Accessibility users rely on well-established keyboard navigation rules, which do not typically use arrow keys to navigate a collection of buttons. However, users without visual impairments might feel that the behavior is natural. + +An example of default WinUI behavior in this case is the `ContentDialog`. While arrow keys can be used to navigate between buttons, each button is also a tab stop. + +##### Assign single tab stop to familiar UI patterns + +In cases where your layout follows a well-known UI pattern for control groups, assigning a single tab stop to the group can improve navigation efficiency for users. + +Examples include: +- `RadioButtons` +- Multiple `ListViews` that look like and behave like a single `ListView` +- Any UI made to look and behave like grid of tiles (such as the Start menu tiles) + +#### Specifying control group behavior + +Use the following APIs to support custom control group behavior (all are discussed in more detail later in this topic): + +- [XYFocusKeyboardNavigation](focus-navigation.md#2d-directional-navigation-for-keyboard) enables arrow key navigation between controls +- [TabFocusNavigation](focus-navigation.md#tab-navigation) indicates whether there are multiple tab stops or single tab stop +- [FindFirstFocusableElement and FindLastFocusableElement](focus-navigation-programmatic.md#find-the-first-and-last-focusable-element) sets focus on the first item with **Home** key and the last item with **End** key + +The following image shows an intuitive keyboard navigation behavior for a control group of associated radio buttons. In this case, we recommend a single tab stop for the control group, inner navigation between the radio buttons using the arrow keys, **Home** key bound to the first radio button, and **End** key bound to the last radio button. + +![putting it all together](images/keyboard/putting-it-all-together.png) + +### Keyboard and Narrator + +Narrator is a UI accessibility tool geared towards keyboard users (other input types are also supported). However, Narrator functionality goes beyond the keyboard interactions supported by WinUI apps and extra care is required when designing your WinUI app for Narrator. (The [Narrator basics page](https://support.microsoft.com/help/22808/windows-10-narrator-basics) guides you through the Narrator user experience.) + +Some of the differences between WinUI keyboard behaviors and those supported by Narrator include: +- Extra key combinations for navigation to UI elements that are not exposed through standard keyboard navigation, such as Caps lock + arrow keys to read control labels. +- Navigation to disabled items. By default, disabled items are not exposed through standard keyboard navigation. +- Control "views" for quicker navigation based on UI granularity. Users can navigate to items, characters, word, lines, paragraphs, links, headings, tables, landmarks, and suggestions. Standard keyboard navigation exposes these objects as a flat list, which might make navigation cumbersome unless you provide shortcut keys. + +#### Case Study – AutoSuggestBox control + +The search button for the `AutoSuggestBox` is not accessible to standard keyboard navigation using tab and arrow keys because the user can press the **Enter** key to submit the search query. However, it is accessible through Narrator when the user presses Caps Lock + an arrow key. + +![autosuggest keyboard focus](images/keyboard/auto-suggest-keyboard.png) + +*With keyboard, users press the* ***Enter*** *key to submit search query* + + + + + + +
+

autosuggest narrator focus

+

With Narrator, users press the Enter key to submit search query

+
+

autosuggest narrator focus on search

+

With Narrator, users are also able to access the search button using the Caps Lock + Right arrow key, then pressing Space key

+
+ +### Keyboard, game pad, and remote control + +Game pads and remote controls support many WinUI keyboard behaviors and experiences. However, due to the lack of various key options available on a keyboard, game pad and remote control lack many keyboard optimizations (remote control is even more limited than game pad). + +See [Game pad and remote control interactions](../../design/input/gamepad-and-remote-interactions.md) for more detail on WinUI support for game pad and remote control input. + +The following shows some key mappings between keyboard, game pad, and remote control. + +| **Keyboard** | **Game pad** | **Remote control** | +|---------------|-------------------------------------|---------------------| +| Space | A button | Select button | +| Enter | A button | Select button | +| Escape | B button | Back button | +| Home/End | N/A | N/A | +| Page Up/Down | Trigger button for vertical scroll, Bumper button for horizontal scroll | N/A | + +Some key differences you should be aware of when designing your WinUI app for use with game pad and remote control usage include: +- Text entry requires the user to press A to activate a text control. +- Focus navigation is not limited to control groups, users can navigate freely to any focusable UI element in the app. + + **NOTE** Focus can move to any focusable UI element in the key press direction unless it is in an overlay UI or [focus engagement](gamepad-and-remote-interactions.md#focus-engagement) is specified, which prevents focus from entering/exiting a region until engaged/disengaged with the A button. For more info, see the [directional navigation](#directional-navigation) section. +- D-pad and left stick buttons are used to move focus between controls and for inner navigation. + + **NOTE** Gamepad and remote control only navigate to items that are in the same visual order as the directional key pressed. Navigation is disabled in that direction when there is no subsequent element that can receive focus. Depending on the situation, keyboard users do not always have that constraint. See the [Built in keyboard optimization](#built-in-keyboard-optimization) section for more info. + +#### Directional navigation + +Directional navigation is managed by a WinUI [Focus Manager](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.FocusManager) helper class, which takes the directional key pressed (arrow key, D-pad) and attempts to move focus in the corresponding visual direction. + +**NOTE** Navigation using the keyboard Tab key is not considered directional navigation. For more info, see the [Tab stops](#tab-stops) section. + + + + + + +
+

directional navigation

+

Directional navigation supported
Using directional keys (keyboard arrows, gamepad and remote control D-pad), user can navigate between different controls.

+
+

no directional navigation

+

Directional navigation not supported
User cannot navigate between different controls using directional keys. Other methods of navigating between controls (tab key) are not impacted.

+
+ +### Built in keyboard optimization + +Depending on the layout and controls used, WinUI apps can be optimized specifically for keyboard input. + +The following example shows a group of list items, grid items, and menu items that have been assigned to a single tab stop (see the [Tab stops](#tab-stops) section). When the group has focus, inner navigation is performed with the directional arrow keys in the corresponding visual order (see [Navigation](#navigation) section). + +![single column arrow key navigation](images/keyboard/single-column-arrow.png) + +***Single Column Arrow Key Navigation*** + +![single row arrow key navigation](images/keyboard/single-row-arrow.png) + +***Single Row Arrow Key Navigation*** + +![multiple column and row arrow key navigation](images/keyboard/multiple-column-and-row-navigation.png) + +***Multiple Column/Row Arrow Key Navigation*** + +#### Wrapping homogeneous List and Grid View Items + +Directional navigation is not always the most efficient way to navigate multiple rows and columns of List and GridView items. + +**NOTE** Menu items are typically single column lists, but special focus rules might apply in some cases (see [Popup UI](#popup-ui)). + +List and Grid objects can be created with multiple rows and columns. These are typically in row-major (where items fill entire row first before filling in the next row) or column-major (where items fill entire column first before filling in the next column) order. Row or column major order depends on scroll direction and you should ensure that item +order does not conflict with this direction. + +In row-major order (where items fill in left to right, top to bottom), when the focus is on the last item in a row and the Right arrow key is pressed, focus is moved to the first item in the next row. This same behavior occurs in reverse: When focus is set to the first item in a row and the Left arrow key is pressed, focus is moved to the last item in +the previous row. + +In column-major order (where items fill in top to bottom, left to right), when the focus is on the last item in a column and user presses the Down arrow key, focus is moved to the first item in the next column. This same behavior occurs in reverse: When focus is set to the first item in a column and the Up arrow key is pressed, focus is moved to the +last item in the previous column. + + + + + + +
+

row major keyboard navigation

+

Row major keyboard navigation

+
+

column major keyboard navigation

+

Column major keyboard navigation

+
+ +#### Popup UI + +As mentioned, you should try to ensure directional navigation corresponds to the visual order of the controls in your application's UI. + +Some controls (such as the context menu, CommandBar overflow menu, and AutoSuggest menu) display a menu popup in a location and direction (downwards by default) relative to the primary control and available screen space. Note that the opening direction can be affected by a variety of factors at run time. + + + + +
command bar opens down with down arrow keycommand bar opens up with down arrow key
+ +For these controls, when the menu is first opened (and no item has been selected by the user), the Down arrow key always sets focus to the first item while the Up arrow key always sets focus to the last item on the menu. + +If the last item has focus and the Down arrow key is pressed, focus moves to the first item on the menu. Similarly, if the first item has focus and the Up arrow key is pressed, focus moves to the last item on the menu. This behavior is referred to as *cycling* and is useful for navigating popup menus that can open in unpredictable directions. + +> [!NOTE] +> Cycling should be avoided in non-popup UIs where users might come to feel trapped in an endless loop. + +We recommend that you emulate these same behaviors in your custom controls. Code sample on how to implement this behavior can be found in [Programmatic focus navigation](focus-navigation-programmatic.md#find-the-first-and-last-focusable-element) documentation. + + +## Test your app + +Test your app with all supported input devices to ensure UI elements can be navigated to in a coherent and intuitive way and that no unexpected elements interfere with the desired tab order. + +## Related articles + +* [Keyboard events](../../design/input/keyboard-events.md) +* [Identify input devices](../../design/input/identify-input-devices.md) +* [Respond to the presence of the touch keyboard](../../design/input/respond-to-the-presence-of-the-touch-keyboard.md) +* [Focus visuals sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlFocusVisuals) +* [NavigationView control keyboarding specifics](../ui/controls/navigationview.md#hierarchical-navigation) +* [Keyboard accessibility](../../design/accessibility/keyboard-accessibility.md) + +## Appendix + +### Software keyboard + +A software keyboard is displayed on screen and used instead of the physical keyboard to type and enter data using touch, mouse, pen/stylus or other pointing device. On gaming devices, individual keys need to be selected by moving focus visual or using shortcut keys on a game pad or remote control. + +#### Touch keyboard + +![Windows 11 touch keyboard](images/keyboard/default.png) + +***Windows 11 Touch Keyboard*** + +Depending on the device, the touch keyboard appears when a text field or other editable text control gets focus, or when the user manually enables it through the **Notification Center**: + +![Screenshot of the touch keyboard icon in the notification center.](images/keyboard/touch-keyboard-notificationcenter.png) + +If your app sets focus programmatically to a text input control, the touch keyboard is not invoked. This eliminates unexpected behaviors not instigated directly by the user. However, the keyboard does automatically hide when focus is moved programmatically to a non-text input control. + +The touch keyboard typically remains visible while the user navigates between controls in a form. This behavior can vary based on the other control types within the form. + +The following is a list of non-edit controls that can receive focus during a text entry session using the touch keyboard without dismissing the keyboard. Rather than needlessly churn the UI and potentially disorient the user, the touch keyboard remains in view because the user is likely to go back and forth between these controls and text entry with the touch keyboard. + +- Check box +- Combo box +- Radio button +- Scroll bar +- Tree +- Tree item +- Menu +- Menu bar +- Menu item +- Toolbar +- List +- List item + +Here are examples of different modes for the touch keyboard. The first image is the default layout, the second is the expanded layout (which might not be available in all languages). + +![Screenshot of the touch keyboard in default layout mode.](images/keyboard/default.png) + +***The touch keyboard in default layout mode*** + +![Screenshot of the touch keyboard in expanded layout mode.](images/keyboard/extendedview.png) + +***The touch keyboard in expanded layout mode*** + +Successful keyboard interactions enable users to accomplish basic app scenarios using only the keyboard; that is, users can reach all interactive elements and activate default functionality. A number of factors can affect the degree of success, including keyboard navigation, access keys for accessibility, and accelerator (or shortcut) keys for advanced users. + +#### On-Screen Keyboard + +Like the touch keyboard, the On-Screen Keyboard (OSK) is a visual, software keyboard used instead of the physical keyboard to type and enter data using touch, mouse, pen/stylus or other pointing device (a touch screen is not required). The OSK is provided for systems that don't have a physical keyboard, or for users whose mobility impairments prevent them from using traditional physical input devices. The OSK emulates most, if not all, the functionality of a hardware keyboard. + +The OSK can be turned on from the Keyboard page in Settings > Ease of access. + +**NOTE** The OSK has priority over the touch keyboard, which won't be shown if the OSK is present. + +![Screenshot of the On-Screen Keyboard.](images/keyboard/osk.png) + +***On-Screen Keyboard*** + +![Screenshot of the Xbox One On-Screen Keyboard.](images/keyboard/xbox-onscreen-keyboard.png) + +***Xbox One On-Screen Keyboard*** + +For more details, see [Use the On-Screen Keyboard to type](https://support.microsoft.com/help/10762/windows-use-on-screen-keyboard). diff --git a/hub/apps/develop/input/mouse-interactions.md b/hub/apps/develop/input/mouse-interactions.md index 91a2a73ea6..7fde3c0efc 100644 --- a/hub/apps/develop/input/mouse-interactions.md +++ b/hub/apps/develop/input/mouse-interactions.md @@ -1,118 +1,118 @@ ---- -description: Respond to mouse input in your apps by handling the same basic pointer events that you use for touch and pen input. -title: Mouse interactions -ms.assetid: C8A158EF-70A9-4BA2-A270-7D08125700AC -label: Mouse -template: detail.hbs -ms.date: 09/24/2020 -ms.topic: article -keywords: windows 10, uwp -ms.localizationpriority: medium ---- -# Mouse interactions - -Optimize your Windows app design for touch input and get basic mouse support by default.  - -Mouse input is best suited for user interactions that require precision when pointing and clicking. This inherent precision is naturally supported by the UI of Windows, which is optimized for the imprecise nature of touch. - -Where mouse and touch input diverge is the ability for touch to more closely emulate the direct manipulation of UI elements through physical gestures performed directly on those objects (such as swiping, sliding, dragging, rotating, and so on). Manipulations with a mouse typically require some other UI affordance, such as the use of handles to resize or rotate an object. - -This topic describes design considerations for mouse interactions. - -## The Windows mouse language - -A concise set of mouse interactions are used consistently throughout the system. - -| Term | Description | -|---|---| -| Hover to learn | Hover over an element to display more detailed info or teaching visuals (such as a tooltip) without a commitment to an action. | -| Left-click for primary action | Left-click an element to invoke its primary action (such as launching an app or executing a command). | -| Scroll to change view | Display scroll bars to move up, down, left, and right within a content area. Users can scroll by clicking scroll bars or rotating the mouse wheel. Scroll bars can indicate the location of the current view within the content area (panning with touch displays a similar UI). | -| Right-click to select and command | Right-click to display the navigation bar (if available) and the app bar with global commands. Right-click an element to select it and display the app bar with contextual commands for the selected element.
**Note:** Right-click to display a context menu if selection or app bar commands are not appropriate UI behaviors. But we strongly recommend that you use the app bar for all command behaviors. | -| UI commands to zoom | Display UI commands in the app bar (such as + and -), or press Ctrl and rotate mouse wheel, to emulate pinch and stretch gestures for zooming. | -| UI commands to rotate | Display UI commands in the app bar, or press Ctrl+Shift and rotate mouse wheel, to emulate the turn gesture for rotating. Rotate the device itself to rotate the entire screen. | -| Left-click and drag to rearrange | Left-click and drag an element to move it. | -| Left-click and drag to select text | Left-click within selectable text and drag to select it. Double-click to select a word. | - -## Mouse input events - -Most mouse input can be handled through the common routed input events supported by all [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) objects. These include: - -- [**BringIntoViewRequested**](/uwp/api/windows.ui.xaml.uielement.bringintoviewrequested) -- [**CharacterReceived**](/uwp/api/windows.ui.xaml.uielement.characterreceived) -- [**ContextCanceled**](/uwp/api/windows.ui.xaml.uielement.contextcanceled) -- [**ContextRequested**](/uwp/api/windows.ui.xaml.uielement.contextrequested) -- [**DoubleTapped**](/uwp/api/windows.ui.xaml.uielement.doubletapped) -- [**DragEnter**](/uwp/api/windows.ui.xaml.uielement.dragenter) -- [**DragLeave**](/uwp/api/windows.ui.xaml.uielement.dragleave) -- [**DragOver**](/uwp/api/windows.ui.xaml.uielement.dragover) -- [**DragStarting**](/uwp/api/windows.ui.xaml.uielement.dragstarting) -- [**Drop**](/uwp/api/windows.ui.xaml.uielement.drop) -- [**DropCompleted**](/uwp/api/windows.ui.xaml.uielement.dropcompleted) -- [**GettingFocus**](/uwp/api/windows.ui.xaml.uielement.gettingfocus) -- [**GotFocus**](/uwp/api/windows.ui.xaml.uielement.gotfocus) -- [**Holding**](/uwp/api/windows.ui.xaml.uielement.holding) -- [**KeyDown**](/uwp/api/windows.ui.xaml.uielement.keydown) -- [**KeyUp**](/uwp/api/windows.ui.xaml.uielement.keyup) -- [**LosingFocus**](/uwp/api/windows.ui.xaml.uielement.losingfocus) -- [**LostFocus**](/uwp/api/windows.ui.xaml.uielement.lostfocus) -- [**ManipulationCompleted**](/uwp/api/windows.ui.xaml.uielement.manipulationcompleted) -- [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) -- [**ManipulationInertiaStarting**](/uwp/api/windows.ui.xaml.uielement.manipulationinertiastarting) -- [**ManipulationStarted**](/uwp/api/windows.ui.xaml.uielement.manipulationstarted) -- [**ManipulationStarting**](/uwp/api/windows.ui.xaml.uielement.manipulationstarting) -- [**NoFocusCandidateFound**](/uwp/api/windows.ui.xaml.uielement.nofocuscandidatefound) -- [**PointerCanceled**](/uwp/api/windows.ui.xaml.uielement.pointercanceled) -- [**PointerCaptureLost**](/uwp/api/windows.ui.xaml.uielement.pointercapturelost) -- [**PointerEntered**](/uwp/api/windows.ui.xaml.uielement.pointerentered) -- [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) -- [**PointerMoved**](/uwp/api/windows.ui.xaml.uielement.pointermoved) -- [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) -- [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) -- [**PointerWheelChanged**](/uwp/api/windows.ui.xaml.uielement.pointerwheelchanged) -- [**PreviewKeyDown**](/uwp/api/windows.ui.xaml.uielement.previewkeydown) -- [**PreviewKeyUp**](/uwp/api/windows.ui.xaml.uielement.previewkeyup) -- [**RightTapped**](/uwp/api/windows.ui.xaml.uielement.righttapped) -- [**Tapped**](/uwp/api/windows.ui.xaml.uielement.tapped) - -However, you can take advantage of the specific capabilities of each device (such as mouse wheel events) using the pointer, gesture, and manipulation events in [Windows.UI.Input](/uwp/api/windows.ui.input). - -**Samples:** See our [BasicInput sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BasicInput), for . - -## Guidelines for visual feedback - -- When a mouse is detected (through move or hover events), show mouse-specific UI to indicate functionality exposed by the element. If the mouse doesn't move for a certain amount of time, or if the user initiates a touch interaction, make the mouse UI gradually fade away. This keeps the UI clean and uncluttered. -- Don't use the cursor for hover feedback, the feedback provided by the element is sufficient (see Cursors below). -- Don't display visual feedback if an element doesn't support interaction (such as static text). -- Don't use focus rectangles with mouse interactions. Reserve these for keyboard interactions. -- Display visual feedback concurrently for all elements that represent the same input target. -- Provide buttons (such as + and -) for emulating touch-based manipulations such as panning, rotating, zooming, and so on. - -For more general guidance on visual feedback, see [Guidelines for visual feedback](../../design/input/guidelines-for-visualfeedback.md). - -## Cursors - -A set of standard cursors is available for a mouse pointer. These are used to indicate the primary action of an element. - -Each standard cursor has a corresponding default image associated with it. The user or an app can replace the default image associated with any standard cursor at any time. Specify a cursor image through the [**PointerCursor**](/uwp/api/windows.ui.core.corewindow.pointercursor) function. - -If you need to customize the mouse cursor: - -- Always use the arrow cursor (![arrow cursor](images/cursor-arrow.png)) for clickable elements. don't use the pointing hand cursor (![pointing hand cursor](images/cursor-pointinghand.png)) for links or other interactive elements. Instead, use hover effects (described earlier). -- Use the text cursor (![text cursor](images/cursor-text.png)) for selectable text. -- Use the move cursor (![move cursor](images/cursor-move.png)) when moving is the primary action (such as dragging or cropping). Don't use the move cursor for elements where the primary action is navigation (such as Start tiles). -- Use the horizontal, vertical and diagonal resize cursors (![vertical resize cursor](images/cursor-vertical.png), ![horizontal resize cursor](images/cursor-horizontal.png), ![diagonal resize cursor (lower left, upper right)](images/cursor-diagonal2.png), ![diagonal resize cursor (upper left, lower right)](images/cursor-diagonal1.png)), when an object is resizable. -- Use the grasping hand cursors (![grasping hand cursor (open)](images/cursor-pan1.png), ![grasping hand cursor (closed)](images/cursor-pan2.png)) when panning content within a fixed canvas (such as a map). - -## Related articles - -- [Handle pointer input](../../design/input/handle-pointer-input.md) -- [Identify input devices](../../design/input/identify-input-devices.md) -- [Events and routed events overview](/windows/apps/develop/platform/xaml/events-and-routed-events-overview) - -### Samples - -- [Basic input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BasicInput) -- [Low latency input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput) -- [User interaction mode sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/UserInteractionMode) -- [Focus visuals sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlFocusVisuals) +--- +description: Respond to mouse input in your apps by handling the same basic pointer events that you use for touch and pen input. +title: Mouse interactions +ms.assetid: C8A158EF-70A9-4BA2-A270-7D08125700AC +label: Mouse +template: detail.hbs +ms.date: 09/24/2020 +ms.topic: article +keywords: windows 10, uwp +ms.localizationpriority: medium +--- +# Mouse interactions + +Optimize your Windows app design for touch input and get basic mouse support by default.  + +Mouse input is best suited for user interactions that require precision when pointing and clicking. This inherent precision is naturally supported by the UI of Windows, which is optimized for the imprecise nature of touch. + +Where mouse and touch input diverge is the ability for touch to more closely emulate the direct manipulation of UI elements through physical gestures performed directly on those objects (such as swiping, sliding, dragging, rotating, and so on). Manipulations with a mouse typically require some other UI affordance, such as the use of handles to resize or rotate an object. + +This topic describes design considerations for mouse interactions. + +## The Windows mouse language + +A concise set of mouse interactions are used consistently throughout the system. + +| Term | Description | +|---|---| +| Hover to learn | Hover over an element to display more detailed info or teaching visuals (such as a tooltip) without a commitment to an action. | +| Left-click for primary action | Left-click an element to invoke its primary action (such as launching an app or executing a command). | +| Scroll to change view | Display scroll bars to move up, down, left, and right within a content area. Users can scroll by clicking scroll bars or rotating the mouse wheel. Scroll bars can indicate the location of the current view within the content area (panning with touch displays a similar UI). | +| Right-click to select and command | Right-click to display the navigation bar (if available) and the app bar with global commands. Right-click an element to select it and display the app bar with contextual commands for the selected element.
**Note:** Right-click to display a context menu if selection or app bar commands are not appropriate UI behaviors. But we strongly recommend that you use the app bar for all command behaviors. | +| UI commands to zoom | Display UI commands in the app bar (such as + and -), or press Ctrl and rotate mouse wheel, to emulate pinch and stretch gestures for zooming. | +| UI commands to rotate | Display UI commands in the app bar, or press Ctrl+Shift and rotate mouse wheel, to emulate the turn gesture for rotating. Rotate the device itself to rotate the entire screen. | +| Left-click and drag to rearrange | Left-click and drag an element to move it. | +| Left-click and drag to select text | Left-click within selectable text and drag to select it. Double-click to select a word. | + +## Mouse input events + +Most mouse input can be handled through the common routed input events supported by all [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) objects. These include: + +- [**BringIntoViewRequested**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.bringintoviewrequested) +- [**CharacterReceived**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.characterreceived) +- [**ContextCanceled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextcanceled) +- [**ContextRequested**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextrequested) +- [**DoubleTapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.doubletapped) +- [**DragEnter**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragenter) +- [**DragLeave**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragleave) +- [**DragOver**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragover) +- [**DragStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dragstarting) +- [**Drop**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.drop) +- [**DropCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.dropcompleted) +- [**GettingFocus**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.gettingfocus) +- [**GotFocus**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.gotfocus) +- [**Holding**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.holding) +- [**KeyDown**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.keydown) +- [**KeyUp**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.keyup) +- [**LosingFocus**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.losingfocus) +- [**LostFocus**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.lostfocus) +- [**ManipulationCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationcompleted) +- [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) +- [**ManipulationInertiaStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationinertiastarting) +- [**ManipulationStarted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarted) +- [**ManipulationStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarting) +- [**NoFocusCandidateFound**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.nofocuscandidatefound) +- [**PointerCanceled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercanceled) +- [**PointerCaptureLost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercapturelost) +- [**PointerEntered**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerentered) +- [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) +- [**PointerMoved**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) +- [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) +- [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) +- [**PointerWheelChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerwheelchanged) +- [**PreviewKeyDown**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.previewkeydown) +- [**PreviewKeyUp**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.previewkeyup) +- [**RightTapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.righttapped) +- [**Tapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.tapped) + +However, you can take advantage of the specific capabilities of each device (such as mouse wheel events) using the pointer, gesture, and manipulation events in [Windows.UI.Input](/uwp/api/windows.ui.input). + +**Samples:** See our [BasicInput sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BasicInput), for . + +## Guidelines for visual feedback + +- When a mouse is detected (through move or hover events), show mouse-specific UI to indicate functionality exposed by the element. If the mouse doesn't move for a certain amount of time, or if the user initiates a touch interaction, make the mouse UI gradually fade away. This keeps the UI clean and uncluttered. +- Don't use the cursor for hover feedback, the feedback provided by the element is sufficient (see Cursors below). +- Don't display visual feedback if an element doesn't support interaction (such as static text). +- Don't use focus rectangles with mouse interactions. Reserve these for keyboard interactions. +- Display visual feedback concurrently for all elements that represent the same input target. +- Provide buttons (such as + and -) for emulating touch-based manipulations such as panning, rotating, zooming, and so on. + +For more general guidance on visual feedback, see [Guidelines for visual feedback](../../design/input/guidelines-for-visualfeedback.md). + +## Cursors + +A set of standard cursors is available for a mouse pointer. These are used to indicate the primary action of an element. + +Each standard cursor has a corresponding default image associated with it. The user or an app can replace the default image associated with any standard cursor at any time. Specify a cursor image through the [**PointerCursor**](/uwp/api/windows.ui.core.corewindow.pointercursor) function. + +If you need to customize the mouse cursor: + +- Always use the arrow cursor (![arrow cursor](images/cursor-arrow.png)) for clickable elements. don't use the pointing hand cursor (![pointing hand cursor](images/cursor-pointinghand.png)) for links or other interactive elements. Instead, use hover effects (described earlier). +- Use the text cursor (![text cursor](images/cursor-text.png)) for selectable text. +- Use the move cursor (![move cursor](images/cursor-move.png)) when moving is the primary action (such as dragging or cropping). Don't use the move cursor for elements where the primary action is navigation (such as Start tiles). +- Use the horizontal, vertical and diagonal resize cursors (![vertical resize cursor](images/cursor-vertical.png), ![horizontal resize cursor](images/cursor-horizontal.png), ![diagonal resize cursor (lower left, upper right)](images/cursor-diagonal2.png), ![diagonal resize cursor (upper left, lower right)](images/cursor-diagonal1.png)), when an object is resizable. +- Use the grasping hand cursors (![grasping hand cursor (open)](images/cursor-pan1.png), ![grasping hand cursor (closed)](images/cursor-pan2.png)) when panning content within a fixed canvas (such as a map). + +## Related articles + +- [Handle pointer input](../../design/input/handle-pointer-input.md) +- [Identify input devices](../../design/input/identify-input-devices.md) +- [Events and routed events overview](/windows/apps/develop/platform/xaml/events-and-routed-events-overview) + +### Samples + +- [Basic input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BasicInput) +- [Low latency input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput) +- [User interaction mode sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/UserInteractionMode) +- [Focus visuals sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlFocusVisuals) diff --git a/hub/apps/develop/input/text-scaling.md b/hub/apps/develop/input/text-scaling.md index 75426249e6..fb7ccc5f67 100644 --- a/hub/apps/develop/input/text-scaling.md +++ b/hub/apps/develop/input/text-scaling.md @@ -127,7 +127,7 @@ If text wrapping is not the preferred behavior, most text controls let you eithe > [!NOTE] > If you need to clip your text, clip the end of the string, not the beginning. -In this example, we show how to clip text in a TextBlock using the [TextTrimming](/uwp/api/windows.ui.xaml.controls.textblock.texttrimming) property. +In this example, we show how to clip text in a TextBlock using the [TextTrimming](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock.texttrimming) property. ``` xaml @@ -157,7 +157,7 @@ Here, we add a tooltip to a TextBlock that doesn't support text wrapping: When using font-based icons for emphasis or decoration, disable scaling on these characters. -Set the [IsTextScaleFactorEnabled](/uwp/api/windows.ui.xaml.controls.control.istextscalefactorenabled) property to `false` for most XAML controls. +Set the [IsTextScaleFactorEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.istextscalefactorenabled) property to `false` for most XAML controls. ### Support text scaling natively @@ -171,5 +171,5 @@ This topic provides an overview of text scaling support in Windows and includes ### API reference -- [IsTextScaleFactorEnabled](/uwp/api/windows.ui.xaml.controls.control.istextscalefactorenabled) +- [IsTextScaleFactorEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.istextscalefactorenabled) - [TextScaleFactorChanged](/uwp/api/windows.ui.viewmanagement.uisettings.textscalefactorchanged) diff --git a/hub/apps/develop/input/touch-developer-guide.md b/hub/apps/develop/input/touch-developer-guide.md index 61f762bb18..40842202e2 100644 --- a/hub/apps/develop/input/touch-developer-guide.md +++ b/hub/apps/develop/input/touch-developer-guide.md @@ -15,7 +15,7 @@ Design your app with the expectation that touch will be the primary input method However, keep in mind that a UI optimized for touch is not always superior to a traditional UI. Both provide advantages and disadvantages that are unique to a technology and application. In the move to a touch-first UI, it is important to understand the core differences between touch, touchpad, pen/stylus, mouse, and keyboard input. -> **Important APIs**: [**Windows.UI.Xaml.Input**](/uwp/api/Windows.UI.Xaml.Input), [**Windows.UI.Core**](/uwp/api/Windows.UI.Core), [**Windows.Devices.Input**](/uwp/api/Windows.Devices.Input) +> **Important APIs**: [**Windows.UI.Xaml.Input**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input), [**Windows.UI.Core**](/uwp/api/Windows.UI.Core), [**Windows.Devices.Input**](/uwp/api/Windows.Devices.Input) Many devices have multi-touch screens that support using one or more fingers (or touch contacts) as input. The touch contacts, and their movement, are interpreted as touch gestures and manipulations to support various user interactions. @@ -141,9 +141,9 @@ In addition, the following are strongly recommended: Tweak the user interaction experience through the pan/scroll and zoom settings of your app views. An app view dictates how a user accesses and manipulates your app and its content. Views also provide behaviors such as inertia, content boundary bounce, and snap points. -Pan and scroll settings of the [**ScrollViewer**](/uwp/api/Windows.UI.Xaml.Controls.ScrollViewer) control dictate how users navigate within a single view, when the content of the view doesn't fit within the viewport. A single view, for example, can be a page of a magazine or book, the folder structure of a computer, a library of documents, or a photo album. +Pan and scroll settings of the [**ScrollViewer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ScrollViewer) control dictate how users navigate within a single view, when the content of the view doesn't fit within the viewport. A single view, for example, can be a page of a magazine or book, the folder structure of a computer, a library of documents, or a photo album. -Zoom settings apply to both optical zoom (supported by the [**ScrollViewer**](/uwp/api/Windows.UI.Xaml.Controls.ScrollViewer) control) and the [**Semantic Zoom**](/uwp/api/Windows.UI.Xaml.Controls.SemanticZoom) control. Semantic Zoom is a touch-optimized technique for presenting and navigating large sets of related data or content within a single view. It works by using two distinct modes of classification, or zoom levels. This is analogous to panning and scrolling within a single view. Panning and scrolling can be used in conjunction with Semantic Zoom. +Zoom settings apply to both optical zoom (supported by the [**ScrollViewer**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.ScrollViewer) control) and the [**Semantic Zoom**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.SemanticZoom) control. Semantic Zoom is a touch-optimized technique for presenting and navigating large sets of related data or content within a single view. It works by using two distinct modes of classification, or zoom levels. This is analogous to panning and scrolling within a single view. Panning and scrolling can be used in conjunction with Semantic Zoom. Use app views and events to modify the pan/scroll and zoom behaviors. This can provide a smoother interaction experience than is possible through the handling of pointer and gesture events. @@ -170,17 +170,17 @@ If you implement your own interaction support, keep in mind that users expect an > > If your application must support these interactions, we recommend that you inform users of this setting and provide a link that launches Windows Settings to the relevant page (ms-settings:devices-touch). For more details, see [Launch Windows Settings](/windows/apps/develop/launch/launch-settings). -To provide customized touch support, you can handle various [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) events. These events are grouped into three levels of abstraction. +To provide customized touch support, you can handle various [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) events. These events are grouped into three levels of abstraction. -- Static gesture events are triggered after an interaction is complete. Gesture events include [**Tapped**](/uwp/api/windows.ui.xaml.uielement.tapped), [**DoubleTapped**](/uwp/api/windows.ui.xaml.uielement.doubletapped), [**RightTapped**](/uwp/api/windows.ui.xaml.uielement.righttapped), and [**Holding**](/uwp/api/windows.ui.xaml.uielement.holding). +- Static gesture events are triggered after an interaction is complete. Gesture events include [**Tapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.tapped), [**DoubleTapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.doubletapped), [**RightTapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.righttapped), and [**Holding**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.holding). - You can disable gesture events on specific elements by setting [**IsTapEnabled**](/uwp/api/windows.ui.xaml.uielement.istapenabled), [**IsDoubleTapEnabled**](/uwp/api/windows.ui.xaml.uielement.isdoubletapenabled), [**IsRightTapEnabled**](/uwp/api/windows.ui.xaml.uielement.isrighttapenabled), and [**IsHoldingEnabled**](/uwp/api/windows.ui.xaml.uielement.isholdingenabled) to **false**. + You can disable gesture events on specific elements by setting [**IsTapEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.istapenabled), [**IsDoubleTapEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.isdoubletapenabled), [**IsRightTapEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.isrighttapenabled), and [**IsHoldingEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.isholdingenabled) to **false**. -- Pointer events such as [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) and [**PointerMoved**](/uwp/api/windows.ui.xaml.uielement.pointermoved) provide low-level details for each touch contact, including pointer motion and the ability to distinguish press and release events. +- Pointer events such as [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) and [**PointerMoved**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) provide low-level details for each touch contact, including pointer motion and the ability to distinguish press and release events. A pointer is a generic input type with a unified event mechanism. It exposes basic info, such as screen position, on the active input source, which can be touch, touchpad, mouse, or pen. -- Manipulation gesture events, such as [**ManipulationStarted**](/uwp/api/windows.ui.xaml.uielement.manipulationstarted), indicate an ongoing interaction. They start firing when the user touches an element and continue until the user lifts their finger(s), or the manipulation is canceled. +- Manipulation gesture events, such as [**ManipulationStarted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarted), indicate an ongoing interaction. They start firing when the user touches an element and continue until the user lifts their finger(s), or the manipulation is canceled. Manipulation events include multi-touch interactions such as zooming, panning, or rotating, and interactions that use inertia and velocity data such as dragging. The information provided by the manipulation events doesn't identify the form of the interaction that was performed, but rather includes data such as position, translation delta, and velocity. You can use this touch data to determine the type of interaction that should be performed. @@ -210,19 +210,19 @@ Here is a list of pointer events and their related event argument. | Event or class | Description | |----------------------------------------------------------------------|---------------------------------------------------------------| -| [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) | Occurs when a single finger touches the screen. | -| [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) | Occurs when that same touch contact is lifted. | -| [**PointerMoved**](/uwp/api/windows.ui.xaml.uielement.pointermoved) | Occurs when the pointer is dragged across the screen. | -| [**PointerEntered**](/uwp/api/windows.ui.xaml.uielement.pointerentered) | Occurs when a pointer enters the hit test area of an element. | -| [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) | Occurs when a pointer exits the hit test area of an element. | -| [**PointerCanceled**](/uwp/api/windows.ui.xaml.uielement.pointercanceled) | Occurs when a touch contact is abnormally lost. | -| [**PointerCaptureLost**](/uwp/api/windows.ui.xaml.uielement.pointercapturelost) | Occurs when a pointer capture is taken by another element. | -| [**PointerWheelChanged**](/uwp/api/windows.ui.xaml.uielement.pointerwheelchanged) | Occurs when the delta value of a mouse wheel changes and when the touchpad is pinched. | -| [**PointerRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.PointerRoutedEventArgs) | Provides data for all pointer events. | +| [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) | Occurs when a single finger touches the screen. | +| [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) | Occurs when that same touch contact is lifted. | +| [**PointerMoved**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointermoved) | Occurs when the pointer is dragged across the screen. | +| [**PointerEntered**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerentered) | Occurs when a pointer enters the hit test area of an element. | +| [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) | Occurs when a pointer exits the hit test area of an element. | +| [**PointerCanceled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercanceled) | Occurs when a touch contact is abnormally lost. | +| [**PointerCaptureLost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointercapturelost) | Occurs when a pointer capture is taken by another element. | +| [**PointerWheelChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerwheelchanged) | Occurs when the delta value of a mouse wheel changes and when the touchpad is pinched. | +| [**PointerRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.PointerRoutedEventArgs) | Provides data for all pointer events. | -The following example shows how to use the [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed), [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased), and [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) events to handle a tap interaction on a [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) object. +The following example shows how to use the [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed), [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased), and [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) events to handle a tap interaction on a [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle) object. -First, a [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) named `touchRectangle` is created in Extensible Application Markup Language (XAML). +First, a [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle) named `touchRectangle` is created in Extensible Application Markup Language (XAML). ```XAML @@ -231,7 +231,7 @@ First, a [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) named `touch ``` -Next, listeners for the [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed), [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased), and [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) events are specified. +Next, listeners for the [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed), [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased), and [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) events are specified. ```cpp MainPage::MainPage() @@ -271,7 +271,7 @@ Public Sub New() End Sub ``` -Finally, the [**PointerPressed**](/uwp/api/windows.ui.xaml.uielement.pointerpressed) event handler increases the [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) and [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width) of the [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle), while the [**PointerReleased**](/uwp/api/windows.ui.xaml.uielement.pointerreleased) and [**PointerExited**](/uwp/api/windows.ui.xaml.uielement.pointerexited) event handlers set the **Height** and **Width** back to their starting values. +Finally, the [**PointerPressed**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerpressed) event handler increases the [**Height**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.FrameworkElement.Height) and [**Width**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.FrameworkElement.Width) of the [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle), while the [**PointerReleased**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerreleased) and [**PointerExited**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerexited) event handlers set the **Height** and **Width** back to their starting values. ```cpp // Handler for pointer exited event. @@ -405,28 +405,28 @@ Here is a list of manipulation events and related event arguments. | Event or class | Description | |--------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------| -| [**ManipulationStarting event**](/uwp/api/windows.ui.xaml.uielement.manipulationstarting) | Occurs when the manipulation processor is first created. | -| [**ManipulationStarted event**](/uwp/api/windows.ui.xaml.uielement.manipulationstarted) | Occurs when an input device begins a manipulation on the [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement). | -| [**ManipulationDelta event**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) | Occurs when the input device changes position during a manipulation. | -| [**ManipulationInertiaStarting event**](/uwp/api/windows.ui.xaml.uielement.manipulationinertiastartingevent) | Occurs when the input device loses contact with the [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) object during a manipulation and inertia begins. | -| [**ManipulationCompleted event**](/uwp/api/windows.ui.xaml.uielement.manipulationcompleted) | Occurs when a manipulation and inertia on the [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) are complete. | -| [**ManipulationStartingRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.ManipulationStartingRoutedEventArgs) | Provides data for the [**ManipulationStarting**](/uwp/api/windows.ui.xaml.uielement.manipulationstarting) event. | -| [**ManipulationStartedRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.ManipulationStartedRoutedEventArgs) | Provides data for the [**ManipulationStarted**](/uwp/api/windows.ui.xaml.uielement.manipulationstarted) event. | -| [**ManipulationDeltaRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs) | Provides data for the [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) event. | -| [**ManipulationInertiaStartingRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.ManipulationInertiaStartingRoutedEventArgs) | Provides data for the [**ManipulationInertiaStarting**](/uwp/api/windows.ui.xaml.uielement.manipulationinertiastarting) event. | +| [**ManipulationStarting event**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarting) | Occurs when the manipulation processor is first created. | +| [**ManipulationStarted event**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarted) | Occurs when an input device begins a manipulation on the [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement). | +| [**ManipulationDelta event**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) | Occurs when the input device changes position during a manipulation. | +| [**ManipulationInertiaStarting event**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationinertiastartingevent) | Occurs when the input device loses contact with the [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) object during a manipulation and inertia begins. | +| [**ManipulationCompleted event**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationcompleted) | Occurs when a manipulation and inertia on the [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) are complete. | +| [**ManipulationStartingRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.ManipulationStartingRoutedEventArgs) | Provides data for the [**ManipulationStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarting) event. | +| [**ManipulationStartedRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.ManipulationStartedRoutedEventArgs) | Provides data for the [**ManipulationStarted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarted) event. | +| [**ManipulationDeltaRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.ManipulationDeltaRoutedEventArgs) | Provides data for the [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) event. | +| [**ManipulationInertiaStartingRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.ManipulationInertiaStartingRoutedEventArgs) | Provides data for the [**ManipulationInertiaStarting**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationinertiastarting) event. | | [**ManipulationVelocities**](/uwp/api/Windows.UI.Input.ManipulationVelocities) | Describes the speed at which manipulations occur. | -| [**ManipulationCompletedRoutedEventArgs**](/uwp/api/Windows.UI.Xaml.Input.ManipulationCompletedRoutedEventArgs) | Provides data for the [**ManipulationCompleted**](/uwp/api/windows.ui.xaml.uielement.manipulationcompleted) event. | +| [**ManipulationCompletedRoutedEventArgs**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.ManipulationCompletedRoutedEventArgs) | Provides data for the [**ManipulationCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationcompleted) event. | -A gesture consists of a series of manipulation events. Each gesture starts with a [**ManipulationStarted**](/uwp/api/windows.ui.xaml.uielement.manipulationstarted) event, such as when a user touches the screen. +A gesture consists of a series of manipulation events. Each gesture starts with a [**ManipulationStarted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationstarted) event, such as when a user touches the screen. -Next, one or more [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) events are fired. For example, if you touch the screen and then drag your finger across the screen. Finally, a [**ManipulationCompleted**](/uwp/api/windows.ui.xaml.uielement.manipulationcompleted) event is raised when the interaction finishes. +Next, one or more [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) events are fired. For example, if you touch the screen and then drag your finger across the screen. Finally, a [**ManipulationCompleted**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationcompleted) event is raised when the interaction finishes. > [!NOTE] > If you don't have a touch-screen monitor, you can test your manipulation event code in the simulator using a mouse and mouse wheel interface. -The following example shows how to use the [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) events to handle a slide interaction on a [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) and move it across the screen. +The following example shows how to use the [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) events to handle a slide interaction on a [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle) and move it across the screen. -First, a [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) named `touchRectangle` is created in XAML with a [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) and [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width) of 200. +First, a [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle) named `touchRectangle` is created in XAML with a [**Height**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.FrameworkElement.Height) and [**Width**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.FrameworkElement.Width) of 200. ```XAML @@ -436,7 +436,7 @@ First, a [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) named `touch ``` -Next, a global [**TranslateTransform**](/uwp/api/Windows.UI.Xaml.Media.TranslateTransform) named `dragTranslation` is created for translating the [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle). A [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) event listener is specified on the **Rectangle**, and `dragTranslation` is added to the [**RenderTransform**](/uwp/api/windows.ui.xaml.uielement.rendertransform) of the **Rectangle**. +Next, a global [**TranslateTransform**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.TranslateTransform) named `dragTranslation` is created for translating the [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle). A [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) event listener is specified on the **Rectangle**, and `dragTranslation` is added to the [**RenderTransform**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.rendertransform) of the **Rectangle**. ```cpp // Global translation transform used for changing the position of @@ -507,7 +507,7 @@ Public Sub New() End Sub ``` -Finally, in the [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) event handler, the position of the [**Rectangle**](/uwp/api/Windows.UI.Xaml.Shapes.Rectangle) is updated by using the [**TranslateTransform**](/uwp/api/Windows.UI.Xaml.Media.TranslateTransform) on the [**Delta**](/uwp/api/windows.ui.xaml.input.manipulationdeltaroutedeventargs.delta) property. +Finally, in the [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) event handler, the position of the [**Rectangle**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Shapes.Rectangle) is updated by using the [**TranslateTransform**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.TranslateTransform) on the [**Delta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.manipulationdeltaroutedeventargs.delta) property. ```cpp // Handler for the ManipulationDelta event. @@ -553,10 +553,10 @@ End Sub ## Routed events -All of the pointer events, gesture events and manipulation events mentioned here are implemented as *routed events*. This means that the event can potentially be handled by objects other than the one that originally raised the event. Successive parents in an object tree, such as the parent containers of a [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) or the root [**Page**](/uwp/api/Windows.UI.Xaml.Controls.Page) of your app, can choose to handle these events even if the original element does not. Conversely, any object that does handle the event can mark the event handled so that it no longer reaches any parent element. For more info about the routed event concept and how it affects how you write handlers for routed events, see [Events and routed events overview](/previous-versions/windows/apps/hh758286(v=win.10)). +All of the pointer events, gesture events and manipulation events mentioned here are implemented as *routed events*. This means that the event can potentially be handled by objects other than the one that originally raised the event. Successive parents in an object tree, such as the parent containers of a [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) or the root [**Page**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.Page) of your app, can choose to handle these events even if the original element does not. Conversely, any object that does handle the event can mark the event handled so that it no longer reaches any parent element. For more info about the routed event concept and how it affects how you write handlers for routed events, see [Events and routed events overview](/previous-versions/windows/apps/hh758286(v=win.10)). > [!Important] -> If you need to handle pointer events for a [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) in a scrollable view (such as a ScrollViewer or ListView), you must explicitly disable support for manipulation events on the element in the view by calling [UIElement.CancelDirectmanipulation()](/uwp/api/windows.ui.xaml.uielement.canceldirectmanipulations). To re-enable manipulation events in the view, call [UIElement.TryStartDirectManipulation()](/uwp/api/windows.ui.xaml.uielement.trystartdirectmanipulation). +> If you need to handle pointer events for a [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement) in a scrollable view (such as a ScrollViewer or ListView), you must explicitly disable support for manipulation events on the element in the view by calling [UIElement.CancelDirectmanipulation()](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.canceldirectmanipulations). To re-enable manipulation events in the view, call [UIElement.TryStartDirectManipulation()](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.trystartdirectmanipulation). ## Dos and don'ts diff --git a/hub/apps/develop/input/touchpad-interactions.md b/hub/apps/develop/input/touchpad-interactions.md index 20ff7c8f4e..c8455fa481 100644 --- a/hub/apps/develop/input/touchpad-interactions.md +++ b/hub/apps/develop/input/touchpad-interactions.md @@ -1,121 +1,121 @@ ---- -description: Create Windows apps with intuitive and distinctive user interaction experiences that are optimized for touchpad but are functionally consistent across input devices. -title: Touchpad interactions -ms.assetid: CEDEA30A-FE94-4553-A7FB-6C1FA44F06AB -label: Touchpad interactions -template: detail.hbs -keywords: touchpad, PTP, touch, pointer, input, user interaction -ms.date: 09/24/2020 -ms.topic: article - - -ms.localizationpriority: medium ---- -# Touchpad design guidelines - - -Design your app so that users can interact with it through a touchpad. A touchpad combines both indirect multi-touch input with the precision input of a pointing device, such as a mouse. This combination makes the touchpad suited to both a touch-optimized UI and the smaller targets of productivity apps. - -Touchpad interactions require three things: - -- A standard touchpad or a Windows Precision Touchpad. - - Precision touchpads are optimized for Windows app devices. They enable the system to handle certain aspects of the touchpad experience natively, such as finger tracking and palm detection, for a more consistent experience across devices. - -- The direct contact of one or more fingers on the touchpad. -- Movement of the touch contacts (or lack thereof, based on a time threshold). - -The input data provided by the touchpad sensor can be: - -- Interpreted as a physical gesture for direct manipulation of one or more UI elements (such as panning, rotating, resizing, or moving). In contrast, interacting with an element through its properties window or other dialog box is considered indirect manipulation. -- Recognized as an alternative input method, such as mouse or pen. -- Used to complement or modify aspects of other input methods, such as smudging an ink stroke drawn with a pen. - -A touchpad combines indirect multi-touch input with the precision input of a pointing device, such as a mouse. This combination makes the touchpad suited to both touch-optimized UI and the typically smaller targets of productivity apps and the desktop environment. Optimize your Windows app design for touch input and get touchpad support by default. - -Because of the convergence of interaction experiences supported by touchpads, we recommend using the [**PointerEntered**](/uwp/api/windows.ui.xaml.uielement.pointerentered) event to provide mouse-style UI commands in addition to the built-in support for touch input. For example, use previous and next buttons to let users flip through pages of content as well as pan through the content. - -The gestures and guidelines discussed in this topic can help to ensure that your app supports touchpad input seamlessly and with minimal code. - -## The touchpad language - - -A concise set of touchpad interactions are used consistently throughout the system. Optimize your app for touch and mouse input and this language makes your app feel instantly familiar for your users, increasing their confidence and making your app easier to learn and use. - -Users can set far more Precision Touchpad gestures and interaction behaviors than they can for a standard touchpad. These two images show the different touchpad settings pages from Settings > Devices > Mouse & touchpad for a standard touchpad and a Precision Touchpad, respectively. - -![standard touchpad settings](images/mouse-touchpad-settings-standard.png) - -Standard\\ touchpad\\ settings - -![windows precision touchpad settings](images/mouse-touchpad-settings-ptp.png) - -Windows\\ Precision\\ Touchpad\\ settings - -Here are some examples of touchpad-optimized gestures for performing common tasks. - -| Term | Description | -|---|---| -| Three-finger tap | User preference to search with **Cortana** or show **Action Center**. | -| Three finger slide | User preference to open the virtual desktop Task View, show Desktop, or switch between open apps. | -| Single finger tap for primary action | Use a single finger to tap an element and invoke its primary action (such as launching an app or executing a command). | -| Two finger tap to right-click | Tap with two fingers simultaneously on an element to select it and display contextual commands. | -| Two finger slide to pan | Slide is used primarily for panning interactions but can also be used for moving, drawing, or writing. | -| Pinch and stretch to zoom | The pinch and stretch gestures are commonly used for resizing and Semantic Zoom. | -| Single finger press and slide to rearrange | Drag an element. | -| Single finger press and slide to select text | Press within selectable text and slide to select it. Double-tap to select a word. | -| Left and right click zone | Emulate the left and right button functionality of a mouse device. | - -  - -## Hardware - - -Query the mouse device capabilities ([**MouseCapabilities**](/uwp/api/Windows.Devices.Input.MouseCapabilities)) to identify what aspects of your app UI the touchpad hardware can access directly. We recommend providing UI for both touch and mouse input. - -For more info about querying device capabilities, see [Identify input devices](../../design/input/identify-input-devices.md). - -## Visual feedback - - -- When a touchpad cursor is detected (through move or hover events), show mouse-specific UI to indicate functionality exposed by the element. If the touchpad cursor doesn't move for a certain amount of time, or if the user initiates a touch interaction, make the touchpad UI gradually fade away. This keeps the UI clean and uncluttered. -- Don't use the cursor for hover feedback, the feedback provided by the element is sufficient (see the Cursors section below). -- Don't display visual feedback if an element doesn't support interaction (such as static text). -- Don't use focus rectangles with touchpad interactions. Reserve these for keyboard interactions. -- Display visual feedback concurrently for all elements that represent the same input target. - -For more general guidance about visual feedback, see [Guidelines for visual feedback](../../design/input/guidelines-for-visualfeedback.md). - -## Cursors - - -A set of standard cursors is available for a touchpad pointer. These are used to indicate the primary action of an element. - -Each standard cursor has a corresponding default image associated with it. The user or an app can replace the default image associated with any standard cursor at any time. WinUI apps specify a cursor image through the [**PointerCursor**](/uwp/api/windows.ui.core.corewindow.pointercursor) function. - -If you need to customize the mouse cursor: - -- Always use the arrow cursor (![arrow cursor](images/cursor-arrow.png)) for clickable elements. don't use the pointing hand cursor (![pointing hand cursor](images/cursor-pointinghand.png)) for links or other interactive elements. Instead, use hover effects (described earlier). -- Use the text cursor (![text cursor](images/cursor-text.png)) for selectable text. -- Use the move cursor (![move cursor](images/cursor-move.png)) when moving is the primary action (such as dragging or cropping). Don't use the move cursor for elements where the primary action is navigation (such as Start tiles). -- Use the horizontal, vertical and diagonal resize cursors (![vertical resize cursor](images/cursor-vertical.png), ![horizontal resize cursor](images/cursor-horizontal.png), ![diagonal resize cursor (lower left, upper right)](images/cursor-diagonal2.png), ![diagonal resize cursor (upper left, lower right)](images/cursor-diagonal1.png)), when an object is resizable. -- Use the grasping hand cursors (![grasping hand cursor (open)](images/cursor-pan1.png), ![grasping hand cursor (closed)](images/cursor-pan2.png)) when panning content within a fixed canvas (such as a map). - -## Related articles - -- [Handle pointer input](../../design/input/handle-pointer-input.md) -- [Identify input devices](../../design/input/identify-input-devices.md) - -### Samples - -- [Basic input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BasicInput) -- [Low latency input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput) -- [User interaction mode sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/UserInteractionMode) -- [Focus visuals sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlFocusVisuals) - -### Archive Samples - -- [Input: Device capabilities sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Windows%208%20app%20samples/%5BC%23%5D-Windows%208%20app%20samples/C%23/Windows%208%20app%20samples/Input%20Device%20capabilities%20sample%20(Windows%208)) -- [Input: XAML user input events sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Input%20XAML%20user%20input%20events%20sample) -- [XAML scrolling, panning, and zooming sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Universal%20Windows%20app%20samples/111487-Universal%20Windows%20app%20samples/XAML%20scrolling%2C%20panning%2C%20and%20zooming%20sample) -- [Input: Gestures and manipulations with GestureRecognizer](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Input%20Gestures%20and%20manipulations%20with%20GestureRecognizer) +--- +description: Create Windows apps with intuitive and distinctive user interaction experiences that are optimized for touchpad but are functionally consistent across input devices. +title: Touchpad interactions +ms.assetid: CEDEA30A-FE94-4553-A7FB-6C1FA44F06AB +label: Touchpad interactions +template: detail.hbs +keywords: touchpad, PTP, touch, pointer, input, user interaction +ms.date: 09/24/2020 +ms.topic: article + + +ms.localizationpriority: medium +--- +# Touchpad design guidelines + + +Design your app so that users can interact with it through a touchpad. A touchpad combines both indirect multi-touch input with the precision input of a pointing device, such as a mouse. This combination makes the touchpad suited to both a touch-optimized UI and the smaller targets of productivity apps. + +Touchpad interactions require three things: + +- A standard touchpad or a Windows Precision Touchpad. + + Precision touchpads are optimized for Windows app devices. They enable the system to handle certain aspects of the touchpad experience natively, such as finger tracking and palm detection, for a more consistent experience across devices. + +- The direct contact of one or more fingers on the touchpad. +- Movement of the touch contacts (or lack thereof, based on a time threshold). + +The input data provided by the touchpad sensor can be: + +- Interpreted as a physical gesture for direct manipulation of one or more UI elements (such as panning, rotating, resizing, or moving). In contrast, interacting with an element through its properties window or other dialog box is considered indirect manipulation. +- Recognized as an alternative input method, such as mouse or pen. +- Used to complement or modify aspects of other input methods, such as smudging an ink stroke drawn with a pen. + +A touchpad combines indirect multi-touch input with the precision input of a pointing device, such as a mouse. This combination makes the touchpad suited to both touch-optimized UI and the typically smaller targets of productivity apps and the desktop environment. Optimize your Windows app design for touch input and get touchpad support by default. + +Because of the convergence of interaction experiences supported by touchpads, we recommend using the [**PointerEntered**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.pointerentered) event to provide mouse-style UI commands in addition to the built-in support for touch input. For example, use previous and next buttons to let users flip through pages of content as well as pan through the content. + +The gestures and guidelines discussed in this topic can help to ensure that your app supports touchpad input seamlessly and with minimal code. + +## The touchpad language + + +A concise set of touchpad interactions are used consistently throughout the system. Optimize your app for touch and mouse input and this language makes your app feel instantly familiar for your users, increasing their confidence and making your app easier to learn and use. + +Users can set far more Precision Touchpad gestures and interaction behaviors than they can for a standard touchpad. These two images show the different touchpad settings pages from Settings > Devices > Mouse & touchpad for a standard touchpad and a Precision Touchpad, respectively. + +![standard touchpad settings](images/mouse-touchpad-settings-standard.png) + +Standard\\ touchpad\\ settings + +![windows precision touchpad settings](images/mouse-touchpad-settings-ptp.png) + +Windows\\ Precision\\ Touchpad\\ settings + +Here are some examples of touchpad-optimized gestures for performing common tasks. + +| Term | Description | +|---|---| +| Three-finger tap | User preference to search with **Cortana** or show **Action Center**. | +| Three finger slide | User preference to open the virtual desktop Task View, show Desktop, or switch between open apps. | +| Single finger tap for primary action | Use a single finger to tap an element and invoke its primary action (such as launching an app or executing a command). | +| Two finger tap to right-click | Tap with two fingers simultaneously on an element to select it and display contextual commands. | +| Two finger slide to pan | Slide is used primarily for panning interactions but can also be used for moving, drawing, or writing. | +| Pinch and stretch to zoom | The pinch and stretch gestures are commonly used for resizing and Semantic Zoom. | +| Single finger press and slide to rearrange | Drag an element. | +| Single finger press and slide to select text | Press within selectable text and slide to select it. Double-tap to select a word. | +| Left and right click zone | Emulate the left and right button functionality of a mouse device. | + +  + +## Hardware + + +Query the mouse device capabilities ([**MouseCapabilities**](/uwp/api/Windows.Devices.Input.MouseCapabilities)) to identify what aspects of your app UI the touchpad hardware can access directly. We recommend providing UI for both touch and mouse input. + +For more info about querying device capabilities, see [Identify input devices](../../design/input/identify-input-devices.md). + +## Visual feedback + + +- When a touchpad cursor is detected (through move or hover events), show mouse-specific UI to indicate functionality exposed by the element. If the touchpad cursor doesn't move for a certain amount of time, or if the user initiates a touch interaction, make the touchpad UI gradually fade away. This keeps the UI clean and uncluttered. +- Don't use the cursor for hover feedback, the feedback provided by the element is sufficient (see the Cursors section below). +- Don't display visual feedback if an element doesn't support interaction (such as static text). +- Don't use focus rectangles with touchpad interactions. Reserve these for keyboard interactions. +- Display visual feedback concurrently for all elements that represent the same input target. + +For more general guidance about visual feedback, see [Guidelines for visual feedback](../../design/input/guidelines-for-visualfeedback.md). + +## Cursors + + +A set of standard cursors is available for a touchpad pointer. These are used to indicate the primary action of an element. + +Each standard cursor has a corresponding default image associated with it. The user or an app can replace the default image associated with any standard cursor at any time. WinUI apps specify a cursor image through the [**PointerCursor**](/uwp/api/windows.ui.core.corewindow.pointercursor) function. + +If you need to customize the mouse cursor: + +- Always use the arrow cursor (![arrow cursor](images/cursor-arrow.png)) for clickable elements. don't use the pointing hand cursor (![pointing hand cursor](images/cursor-pointinghand.png)) for links or other interactive elements. Instead, use hover effects (described earlier). +- Use the text cursor (![text cursor](images/cursor-text.png)) for selectable text. +- Use the move cursor (![move cursor](images/cursor-move.png)) when moving is the primary action (such as dragging or cropping). Don't use the move cursor for elements where the primary action is navigation (such as Start tiles). +- Use the horizontal, vertical and diagonal resize cursors (![vertical resize cursor](images/cursor-vertical.png), ![horizontal resize cursor](images/cursor-horizontal.png), ![diagonal resize cursor (lower left, upper right)](images/cursor-diagonal2.png), ![diagonal resize cursor (upper left, lower right)](images/cursor-diagonal1.png)), when an object is resizable. +- Use the grasping hand cursors (![grasping hand cursor (open)](images/cursor-pan1.png), ![grasping hand cursor (closed)](images/cursor-pan2.png)) when panning content within a fixed canvas (such as a map). + +## Related articles + +- [Handle pointer input](../../design/input/handle-pointer-input.md) +- [Identify input devices](../../design/input/identify-input-devices.md) + +### Samples + +- [Basic input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BasicInput) +- [Low latency input sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/LowLatencyInput) +- [User interaction mode sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/UserInteractionMode) +- [Focus visuals sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlFocusVisuals) + +### Archive Samples + +- [Input: Device capabilities sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Windows%208%20app%20samples/%5BC%23%5D-Windows%208%20app%20samples/C%23/Windows%208%20app%20samples/Input%20Device%20capabilities%20sample%20(Windows%208)) +- [Input: XAML user input events sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Input%20XAML%20user%20input%20events%20sample) +- [XAML scrolling, panning, and zooming sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Universal%20Windows%20app%20samples/111487-Universal%20Windows%20app%20samples/XAML%20scrolling%2C%20panning%2C%20and%20zooming%20sample) +- [Input: Gestures and manipulations with GestureRecognizer](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Input%20Gestures%20and%20manipulations%20with%20GestureRecognizer) diff --git a/hub/apps/develop/input/use-input-scope-to-change-the-touch-keyboard.md b/hub/apps/develop/input/use-input-scope-to-change-the-touch-keyboard.md index 99c99a3bbe..570b47a147 100644 --- a/hub/apps/develop/input/use-input-scope-to-change-the-touch-keyboard.md +++ b/hub/apps/develop/input/use-input-scope-to-change-the-touch-keyboard.md @@ -1,262 +1,262 @@ ---- -description: To help users to enter data using the touch keyboard, or Soft Input Panel (SIP), you can set the input scope of the text control to match the kind of data the user is expected to enter. -MS-HAID: dev\_ctrl\_layout\_txt.use\_input\_scope\_to\_change\_the\_touch\_keyboard -MSHAttr: PreferredLib:/library/windows/apps -Search.Product: eADQiWindows 10XVcnh -title: Use input scope to change the touch keyboard -ms.assetid: 6E5F55D7-24D6-47CC-B457-B6231EDE2A71 -template: detail.hbs -keywords: keyboard, accessibility, navigation, focus, text, input, user interaction -ms.date: 02/08/2017 -ms.topic: how-to - - ---- -# Use input scope to change the touch keyboard - -To help users to enter data using the touch keyboard, or Soft Input Panel (SIP), you can set the input scope of the text control to match the kind of data the user is expected to enter. - -### Important APIs -- [InputScope](/uwp/api/windows.ui.xaml.controls.textbox.inputscope) -- [InputScopeNameValue](/uwp/api/Windows.UI.Xaml.Input.InputScopeNameValue) - - -The touch keyboard can be used for text entry when your app runs on a device with a touch screen. The touch keyboard is invoked when the user taps on an editable input field, such as a **[TextBox](/uwp/api/Windows.UI.Xaml.Controls.TextBox)** or **[RichEditBox](/uwp/api/Windows.UI.Xaml.Controls.RichEditBox)**. You can make it much faster and easier for users to enter data in your app by setting the *input scope* of the text control to match the kind of data you expect the user to enter. The input scope provides a hint to the system about the type of text input expected by the control so the system can provide a specialized touch keyboard layout for the input type. - -For example, if a text box is used only to enter a 4-digit PIN, set the [**InputScope**](/uwp/api/windows.ui.xaml.controls.textbox.inputscope) property to **Number**. This tells the system to show the number keypad layout, which makes it easier for the user to enter the PIN. - -> [!IMPORTANT] -> - This info applies only to the SIP. It does not apply to hardware keyboards or the On-Screen Keyboard available in the Windows Ease of Access options. -> - The input scope does not cause any input validation to be performed, and does not prevent the user from providing any input through a hardware keyboard or other input device. You are still responsible for validating the input in your code as needed. - -## Changing the input scope of a text control - -The input scopes that are available to your app are members of the **[InputScopeNameValue](/uwp/api/Windows.UI.Xaml.Input.InputScopeNameValue)** enumeration. You can set the **InputScope** property of a **[TextBox](/uwp/api/Windows.UI.Xaml.Controls.TextBox)** or **[RichEditBox](/uwp/api/Windows.UI.Xaml.Controls.RichEditBox)** to one of these values. - -> [!IMPORTANT] -> The **[InputScope](/uwp/api/windows.ui.xaml.controls.passwordbox.inputscope)** property on **[PasswordBox](/uwp/api/Windows.UI.Xaml.Controls.PasswordBox)** supports only the **Password** and **NumericPin** values. Any other value is ignored. - -Here, you change the input scope of several text boxes to match the expected data for each text box. - -**To change the input scope in XAML** - -1. In the XAML file for your page, locate the tag for the text control that you want to change. -2. Add the [**InputScope**](/uwp/api/windows.ui.xaml.controls.textbox.inputscope) attribute to the tag and specify the [**InputScopeNameValue**](/uwp/api/Windows.UI.Xaml.Input.InputScopeNameValue) value that matches the expected input. - - Here are some text boxes that might appear on a common customer-contact form. With the [**InputScope**](/uwp/api/windows.ui.xaml.controls.textbox.inputscope) set, a touch keyboard with a suitable layout for the data shows for each text box. - - ```xaml - - - - - - - ``` - -**To change the input scope in code** - -1. In the XAML file for your page, locate the tag for the text control that you want to change. If it's not set, set the [x:Name attribute](/windows/apps/develop/platform/xaml/x-name-attribute) so you can reference the control in your code. - - ```csharp - - ``` - -2. Instantiate a new [**InputScope**](/uwp/api/Windows.UI.Xaml.Input.InputScope) object. - - ```csharp - InputScope scope = new InputScope(); - ``` - -3. Instantiate a new [**InputScopeName**](/uwp/api/Windows.UI.Xaml.Input.InputScopeName) object. - - ```csharp - InputScopeName scopeName = new InputScopeName(); - ``` - -4. Set the [**NameValue**](/uwp/api/windows.ui.xaml.input.inputscopename.namevalue) property of the [**InputScopeName**](/uwp/api/Windows.UI.Xaml.Input.InputScopeName) object to a value of the [**InputScopeNameValue**](/uwp/api/Windows.UI.Xaml.Input.InputScopeNameValue) enumeration. - - ```csharp - scopeName.NameValue = InputScopeNameValue.TelephoneNumber; - ``` - -5. Add the [**InputScopeName**](/uwp/api/Windows.UI.Xaml.Input.InputScopeName) object to the [**Names**](/uwp/api/windows.ui.xaml.input.inputscope.names) collection of the [**InputScope**](/uwp/api/Windows.UI.Xaml.Input.InputScope) object. - - ```csharp - scope.Names.Add(scopeName); - ``` - -6. Set the [**InputScope**](/uwp/api/Windows.UI.Xaml.Input.InputScope) object as the value of the text control's [**InputScope**](/uwp/api/windows.ui.xaml.controls.textbox.inputscope) property. - - ```csharp - phoneNumberTextBox.InputScope = scope; - ``` - -Here's the code all together. - -```CSharp -InputScope scope = new InputScope(); -InputScopeName scopeName = new InputScopeName(); -scopeName.NameValue = InputScopeNameValue.TelephoneNumber; -scope.Names.Add(scopeName); -phoneNumberTextBox.InputScope = scope; -``` - -The same steps can be condensed into this shorthand code. - -```CSharp -phoneNumberTextBox.InputScope = new InputScope() -{ - Names = {new InputScopeName(InputScopeNameValue.TelephoneNumber)} -}; -``` - -## Text prediction, spell checking, and auto-correction - -The [**TextBox**](/uwp/api/Windows.UI.Xaml.Controls.TextBox) and [**RichEditBox**](/uwp/api/Windows.UI.Xaml.Controls.RichEditBox) controls have several properties that influence the behavior of the SIP. To provide the best experience for your users, it's important to understand how these properties affect text input using touch. - -- [**IsSpellCheckEnabled**](/uwp/api/windows.ui.xaml.controls.textbox.isspellcheckenabled)—When spell check is enabled for a text control, the control interacts with the system's spell-check engine to mark words that are not recognized. You can tap a word to see a list of suggested corrections. Spell checking is enabled by default. - - For the **Default** input scope, this property also enables automatic capitalization of the first word in a sentence and auto-correction of words as you type. These auto-correction features might be disabled in other input scopes. For more info, see the tables later in this topic. - -- [**IsTextPredictionEnabled**](/uwp/api/windows.ui.xaml.controls.textbox.istextpredictionenabled)—When text prediction is enabled for a text control, the system shows a list of words that you might be beginning to type. You can select from the list so you don't have to type the whole word. Text prediction is enabled by default. - - Text prediction might be disabled if the input scope is other than **Default**, even if the [**IsTextPredictionEnabled**](/uwp/api/windows.ui.xaml.controls.textbox.istextpredictionenabled) property is **true**. For more info, see the tables later in this topic. - -- [**PreventKeyboardDisplayOnProgrammaticFocus**](/uwp/api/windows.ui.xaml.controls.textbox.preventkeyboarddisplayonprogrammaticfocus)—When this property is **true**, it prevents the system from showing the SIP when focus is programmatically set on a text control. Instead, the keyboard is shown only when the user interacts with the control. - -## Touch keyboard index for Windows - -These tables show the Windows Soft Input Panel (SIP) layouts for common input scope values. The effect of the input scope on the features enabled by the **IsSpellCheckEnabled** and **IsTextPredictionEnabled** properties is listed for each input scope. This is not a comprehensive list of available input scopes. - -> [!Tip] -> You can toggle most touch keyboards between an alphabetic layout and a numbers-and-symbols layout by pressing the **&123** key to change to the numbers-and-symbols layout, and press the **abcd** key to change to the alphabetic layout. - -### Default - -`` - -The default Windows touch keyboard. - -![Default Windows touch keyboard](images/input-scopes/default.png) -- Spell check: enabled if **IsSpellCheckEnabled** = **true**, disabled if **IsSpellCheckEnabled** = **false** -- Auto-correction: enabled if **IsSpellCheckEnabled** = **true**, disabled if **IsSpellCheckEnabled** = **false** -- Automatic capitalization: enabled if **IsSpellCheckEnabled** = **true**, disabled if **IsSpellCheckEnabled** = **false** -- Text prediction: enabled if **IsTextPredictionEnabled** = **true**, disabled if **IsTextPredictionEnabled** = **false** - -### CurrencyAmountAndSymbol - -`` - -The default numbers and symbols keyboard layout. - -![Windows touch keyboard for currency](images/input-scopes/currencyamountandsymbol.png) - -- Includes page left/right keys to show more symbols -- Spell check: on by default, can be disabled -- Auto-correction: on by default, can be disabled -- Automatic capitalization: always disabled -- Text prediction: on by default, can be disabled - -### Url - -`` - -![Windows touch keyboard for URLs](images/input-scopes/url.png) - -- Includes the **.com** and ![go key](images/input-scopes/kbdgokey.png) (Go) keys. Press and hold the **.com** key to display additional options (**.org**, **.net**, and region-specific suffixes) -- Includes the **:**, **-**, and **/** keys -- Spell check: off by default, can be enabled -- Auto-correction: off by default, can be enabled -- Automatic capitalization: off by default, can be enabled -- Text prediction: off by default, can be enabled - - -### EmailSmtpAddress - -`` - -![Windows touch keyboard for email addresses](images/input-scopes/emailsmtpaddress.png) -- Includes the **@** and **.com** keys. Press and hold the **.com** key to display additional options (**.org**, **.net**, and region-specific suffixes) -- Includes the **_** and **-** keys -- Spell check: off by default, can be enabled -- Auto-correction: off by default, can be enabled -- Automatic capitalization: off by default, can be enabled -- Text prediction: off by default, can be enabled - - -### Number - -`` - -![Windows touch keyboard for numbers](images/input-scopes/number.png) -- Spell check: on by default, can be disabled -- Auto-correction: on by default, can be disabled -- Automatic capitalization: always disabled -- Text prediction: on by default, can be disabled - -### TelephoneNumber - -`` - -![Windows touch keyboard for telephone numbers](images/input-scopes/telephonenumber.png) -- Spell check: on by default, can be disabled -- Auto-correction: on by default, can be disabled -- Automatic capitalization: always disabled -- Text prediction: on by default, can be disabled - -### Search - -`` - -![Windows touch keyboard for search](images/input-scopes/search.png) -- Includes the **Search** key instead of the **Enter** key -- Spell check: on by default, can be disabled -- Auto-correction: on by default, can be disabled -- Auto-capitalization: always disabled -- Text prediction: on by default, can be disabled - -### SearchIncremental - -`` - -![Windows touch keyboard for incremental search](images/input-scopes/searchincremental.png) -- Same layout as **Default** -- Spell check: off by default, can be enabled -- Auto-correction: always disabled -- Automatic capitalization: always disabled -- Text prediction: always disabled - -### Formula - -`` - -![Windows touch keyboard for formula](images/input-scopes/formula.png) -- Includes the **=** key -- Also includes the **%**, **$**, and **+** keys -- Spell check: on by default, can be disabled -- Auto-correction: on by default, can be disabled -- Automatic capitalization: always disabled -- Text prediction: on by default, can be disabled - -### Chat - -`` - -![Default Windows touch keyboard](images/input-scopes/default.png) -- Same layout as **Default** -- Spell check: on by default, can be disabled -- Auto-correction: on by default, can be disabled -- Automatic capitalization: on by default, can be disabled -- Text prediction: on by default, can be disabled - -### NameOrPhoneNumber - -`` - -![Default Windows touch keyboard](images/input-scopes/default.png) -- Same layout as **Default** -- Spell check: off by default, can be enabled -- Auto-correction: off by default, can be enabled -- Automatic capitalization: off by default, can be enabled (first letter of each word is capitalized) -- Text prediction: off by default, can be enabled +--- +description: To help users to enter data using the touch keyboard, or Soft Input Panel (SIP), you can set the input scope of the text control to match the kind of data the user is expected to enter. +MS-HAID: dev\_ctrl\_layout\_txt.use\_input\_scope\_to\_change\_the\_touch\_keyboard +MSHAttr: PreferredLib:/library/windows/apps +Search.Product: eADQiWindows 10XVcnh +title: Use input scope to change the touch keyboard +ms.assetid: 6E5F55D7-24D6-47CC-B457-B6231EDE2A71 +template: detail.hbs +keywords: keyboard, accessibility, navigation, focus, text, input, user interaction +ms.date: 02/08/2017 +ms.topic: how-to + + +--- +# Use input scope to change the touch keyboard + +To help users to enter data using the touch keyboard, or Soft Input Panel (SIP), you can set the input scope of the text control to match the kind of data the user is expected to enter. + +### Important APIs +- [InputScope](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) +- [InputScopeNameValue](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeNameValue) + + +The touch keyboard can be used for text entry when your app runs on a device with a touch screen. The touch keyboard is invoked when the user taps on an editable input field, such as a **[TextBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TextBox)** or **[RichEditBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RichEditBox)**. You can make it much faster and easier for users to enter data in your app by setting the *input scope* of the text control to match the kind of data you expect the user to enter. The input scope provides a hint to the system about the type of text input expected by the control so the system can provide a specialized touch keyboard layout for the input type. + +For example, if a text box is used only to enter a 4-digit PIN, set the [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) property to **Number**. This tells the system to show the number keypad layout, which makes it easier for the user to enter the PIN. + +> [!IMPORTANT] +> - This info applies only to the SIP. It does not apply to hardware keyboards or the On-Screen Keyboard available in the Windows Ease of Access options. +> - The input scope does not cause any input validation to be performed, and does not prevent the user from providing any input through a hardware keyboard or other input device. You are still responsible for validating the input in your code as needed. + +## Changing the input scope of a text control + +The input scopes that are available to your app are members of the **[InputScopeNameValue](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeNameValue)** enumeration. You can set the **InputScope** property of a **[TextBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TextBox)** or **[RichEditBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RichEditBox)** to one of these values. + +> [!IMPORTANT] +> The **[InputScope](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.passwordbox.inputscope)** property on **[PasswordBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.PasswordBox)** supports only the **Password** and **NumericPin** values. Any other value is ignored. + +Here, you change the input scope of several text boxes to match the expected data for each text box. + +**To change the input scope in XAML** + +1. In the XAML file for your page, locate the tag for the text control that you want to change. +2. Add the [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) attribute to the tag and specify the [**InputScopeNameValue**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeNameValue) value that matches the expected input. + + Here are some text boxes that might appear on a common customer-contact form. With the [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) set, a touch keyboard with a suitable layout for the data shows for each text box. + + ```xaml + + + + + + + ``` + +**To change the input scope in code** + +1. In the XAML file for your page, locate the tag for the text control that you want to change. If it's not set, set the [x:Name attribute](/windows/apps/develop/platform/xaml/x-name-attribute) so you can reference the control in your code. + + ```csharp + + ``` + +2. Instantiate a new [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScope) object. + + ```csharp + InputScope scope = new InputScope(); + ``` + +3. Instantiate a new [**InputScopeName**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeName) object. + + ```csharp + InputScopeName scopeName = new InputScopeName(); + ``` + +4. Set the [**NameValue**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.inputscopename.namevalue) property of the [**InputScopeName**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeName) object to a value of the [**InputScopeNameValue**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeNameValue) enumeration. + + ```csharp + scopeName.NameValue = InputScopeNameValue.TelephoneNumber; + ``` + +5. Add the [**InputScopeName**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScopeName) object to the [**Names**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.inputscope.names) collection of the [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScope) object. + + ```csharp + scope.Names.Add(scopeName); + ``` + +6. Set the [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Input.InputScope) object as the value of the text control's [**InputScope**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) property. + + ```csharp + phoneNumberTextBox.InputScope = scope; + ``` + +Here's the code all together. + +```CSharp +InputScope scope = new InputScope(); +InputScopeName scopeName = new InputScopeName(); +scopeName.NameValue = InputScopeNameValue.TelephoneNumber; +scope.Names.Add(scopeName); +phoneNumberTextBox.InputScope = scope; +``` + +The same steps can be condensed into this shorthand code. + +```CSharp +phoneNumberTextBox.InputScope = new InputScope() +{ + Names = {new InputScopeName(InputScopeNameValue.TelephoneNumber)} +}; +``` + +## Text prediction, spell checking, and auto-correction + +The [**TextBox**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.TextBox) and [**RichEditBox**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Controls.RichEditBox) controls have several properties that influence the behavior of the SIP. To provide the best experience for your users, it's important to understand how these properties affect text input using touch. + +- [**IsSpellCheckEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.isspellcheckenabled)—When spell check is enabled for a text control, the control interacts with the system's spell-check engine to mark words that are not recognized. You can tap a word to see a list of suggested corrections. Spell checking is enabled by default. + + For the **Default** input scope, this property also enables automatic capitalization of the first word in a sentence and auto-correction of words as you type. These auto-correction features might be disabled in other input scopes. For more info, see the tables later in this topic. + +- [**IsTextPredictionEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.istextpredictionenabled)—When text prediction is enabled for a text control, the system shows a list of words that you might be beginning to type. You can select from the list so you don't have to type the whole word. Text prediction is enabled by default. + + Text prediction might be disabled if the input scope is other than **Default**, even if the [**IsTextPredictionEnabled**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.istextpredictionenabled) property is **true**. For more info, see the tables later in this topic. + +- [**PreventKeyboardDisplayOnProgrammaticFocus**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.preventkeyboarddisplayonprogrammaticfocus)—When this property is **true**, it prevents the system from showing the SIP when focus is programmatically set on a text control. Instead, the keyboard is shown only when the user interacts with the control. + +## Touch keyboard index for Windows + +These tables show the Windows Soft Input Panel (SIP) layouts for common input scope values. The effect of the input scope on the features enabled by the **IsSpellCheckEnabled** and **IsTextPredictionEnabled** properties is listed for each input scope. This is not a comprehensive list of available input scopes. + +> [!Tip] +> You can toggle most touch keyboards between an alphabetic layout and a numbers-and-symbols layout by pressing the **&123** key to change to the numbers-and-symbols layout, and press the **abcd** key to change to the alphabetic layout. + +### Default + +`` + +The default Windows touch keyboard. + +![Default Windows touch keyboard](images/input-scopes/default.png) +- Spell check: enabled if **IsSpellCheckEnabled** = **true**, disabled if **IsSpellCheckEnabled** = **false** +- Auto-correction: enabled if **IsSpellCheckEnabled** = **true**, disabled if **IsSpellCheckEnabled** = **false** +- Automatic capitalization: enabled if **IsSpellCheckEnabled** = **true**, disabled if **IsSpellCheckEnabled** = **false** +- Text prediction: enabled if **IsTextPredictionEnabled** = **true**, disabled if **IsTextPredictionEnabled** = **false** + +### CurrencyAmountAndSymbol + +`` + +The default numbers and symbols keyboard layout. + +![Windows touch keyboard for currency](images/input-scopes/currencyamountandsymbol.png) + +- Includes page left/right keys to show more symbols +- Spell check: on by default, can be disabled +- Auto-correction: on by default, can be disabled +- Automatic capitalization: always disabled +- Text prediction: on by default, can be disabled + +### Url + +`` + +![Windows touch keyboard for URLs](images/input-scopes/url.png) + +- Includes the **.com** and ![go key](images/input-scopes/kbdgokey.png) (Go) keys. Press and hold the **.com** key to display additional options (**.org**, **.net**, and region-specific suffixes) +- Includes the **:**, **-**, and **/** keys +- Spell check: off by default, can be enabled +- Auto-correction: off by default, can be enabled +- Automatic capitalization: off by default, can be enabled +- Text prediction: off by default, can be enabled + + +### EmailSmtpAddress + +`` + +![Windows touch keyboard for email addresses](images/input-scopes/emailsmtpaddress.png) +- Includes the **@** and **.com** keys. Press and hold the **.com** key to display additional options (**.org**, **.net**, and region-specific suffixes) +- Includes the **_** and **-** keys +- Spell check: off by default, can be enabled +- Auto-correction: off by default, can be enabled +- Automatic capitalization: off by default, can be enabled +- Text prediction: off by default, can be enabled + + +### Number + +`` + +![Windows touch keyboard for numbers](images/input-scopes/number.png) +- Spell check: on by default, can be disabled +- Auto-correction: on by default, can be disabled +- Automatic capitalization: always disabled +- Text prediction: on by default, can be disabled + +### TelephoneNumber + +`` + +![Windows touch keyboard for telephone numbers](images/input-scopes/telephonenumber.png) +- Spell check: on by default, can be disabled +- Auto-correction: on by default, can be disabled +- Automatic capitalization: always disabled +- Text prediction: on by default, can be disabled + +### Search + +`` + +![Windows touch keyboard for search](images/input-scopes/search.png) +- Includes the **Search** key instead of the **Enter** key +- Spell check: on by default, can be disabled +- Auto-correction: on by default, can be disabled +- Auto-capitalization: always disabled +- Text prediction: on by default, can be disabled + +### SearchIncremental + +`` + +![Windows touch keyboard for incremental search](images/input-scopes/searchincremental.png) +- Same layout as **Default** +- Spell check: off by default, can be enabled +- Auto-correction: always disabled +- Automatic capitalization: always disabled +- Text prediction: always disabled + +### Formula + +`` + +![Windows touch keyboard for formula](images/input-scopes/formula.png) +- Includes the **=** key +- Also includes the **%**, **$**, and **+** keys +- Spell check: on by default, can be disabled +- Auto-correction: on by default, can be disabled +- Automatic capitalization: always disabled +- Text prediction: on by default, can be disabled + +### Chat + +`` + +![Default Windows touch keyboard](images/input-scopes/default.png) +- Same layout as **Default** +- Spell check: on by default, can be disabled +- Auto-correction: on by default, can be disabled +- Automatic capitalization: on by default, can be disabled +- Text prediction: on by default, can be disabled + +### NameOrPhoneNumber + +`` + +![Default Windows touch keyboard](images/input-scopes/default.png) +- Same layout as **Default** +- Spell check: off by default, can be enabled +- Auto-correction: off by default, can be enabled +- Automatic capitalization: off by default, can be enabled (first letter of each word is capitalized) +- Text prediction: off by default, can be enabled diff --git a/hub/apps/develop/notifications/push-notifications/wns-overview.md b/hub/apps/develop/notifications/push-notifications/wns-overview.md index f99b6dd7a0..b601eec9d7 100644 --- a/hub/apps/develop/notifications/push-notifications/wns-overview.md +++ b/hub/apps/develop/notifications/push-notifications/wns-overview.md @@ -1,298 +1,298 @@ ---- -description: The Windows Push Notification Services (WNS) enables third-party developers to send toast, tile, badge, and raw updates from their own cloud service. This provides a mechanism to deliver new updates to your users in a power-efficient and dependable way. -title: Windows Push Notification Services (WNS) overview -ms.assetid: 2125B09F-DB90-4515-9AA6-516C7E9ACCCD -template: detail.hbs -ms.date: 04/09/2026 -ms.topic: article -keywords: windows 10, uwp -ms.localizationpriority: medium ---- - -# Windows Push Notification Services (WNS) overview - -The Windows Push Notification Services (WNS) enable third-party developers to send toast, tile, badge, and raw updates from their own cloud service. This provides a mechanism to deliver new updates to your users in a power-efficient and dependable way. - -## How it works - -The following diagram shows the complete data flow for sending a push notification. It involves these steps: - -1. Your app requests a push notification channel from WNS. -2. Windows asks WNS to create a notification channel. This channel is returned to the calling device in the form of a Uniform Resource Identifier (URI). -3. The notification channel URI is returned by WNS to your app. -4. Your app sends the URI to your own cloud service. You then store the URI on your own cloud service so that you can access the URI when you send notifications. The URI is an interface between your own app and your own service; it's your responsibility to implement this interface with safe and secure web standards. -5. When your cloud service has an update to send, it notifies WNS using the channel URI. This is done by issuing an HTTP POST request, including the notification payload, over Secure Sockets Layer (SSL). This step requires authentication. -6. WNS receives the request and routes the notification to the appropriate device. - -![wns data flow diagram for push notification](images/wns-diagram-01.jpg) - -## Registering your app and receiving the credentials for your cloud service - -Before you can send notifications using WNS, your app must be registered with the Store Dashboard, as described [here](/azure/notification-hubs/notification-hubs-windows-store-dotnet-get-started-wns-push-notification). - -## Requesting a notification channel - -> [!NOTE] -> The channel-request guidance in this section applies to UWP apps that use [**CreatePushNotificationChannelForApplicationAsync**](/uwp/api/Windows.Networking.PushNotifications.PushNotificationChannelManager#Windows_Networking_PushNotifications_PushNotificationChannelManager_CreatePushNotificationChannelForApplicationAsync_System_String_). If you're building a Windows App SDK desktop app (WinUI 3, WPF, or WinForms), use `PushNotificationManager` instead — see the [Push notifications quickstart](push-quickstart.md). - -When an app that is capable of receiving push notifications runs, it must first request a notification channel through the [**CreatePushNotificationChannelForApplicationAsync**](/uwp/api/Windows.Networking.PushNotifications.PushNotificationChannelManager#Windows_Networking_PushNotifications_PushNotificationChannelManager_CreatePushNotificationChannelForApplicationAsync_System_String_). For a full discussion and example code, see [How to request, create, and save a notification channel](request-create-save-notification-channel.md). This API returns a channel URI that is uniquely linked to the calling application and its tile, and through which all notification types can be sent. - -After the app has successfully created a channel URI, it sends it to its cloud service, together with any app-specific metadata that should be associated with this URI. - -### Important notes - -- We do not guarantee that the notification channel URI for an app will always remain the same. We advise that the app requests a new channel every time it runs and updates its service when the URI changes. The developer should never modify the channel URI and should consider it as a black-box string. At this time, channel URIs expire after 30 days. If your Windows 10 app will periodically renew its channel in the background then you can download the [Push and periodic notifications sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Windows%208%20app%20samples/%5BC%23%5D-Windows%208%20app%20samples/C%23/Windows%208%20app%20samples/Push%20and%20periodic%20notifications%20client-side%20sample%20(Windows%208)) for Windows 8.1 and re-use its source code and/or the pattern it demonstrates. -- The interface between the cloud service and the client app is implemented by you, the developer. We recommend that the app go through an authentication process with its own service and transmit data over a secure protocol such as HTTPS. -- It is important that the cloud service always ensures that the channel URI uses the domain "notify.windows.com". The service should never push notifications to a channel on any other domain. If the callback for your app is ever compromised, a malicious attacker could submit a channel URI to spoof WNS. Without inspecting the domain, your cloud service could potentially disclose information to this attacker unknowingly. The subdomain of the channel URI is subject to change and should not be considered when validating the channel URI. -- If your cloud service attempts to deliver a notification to an expired channel, WNS will return [response code 410](push-request-response-headers.md). In response to that code, your service should no longer attempt to send notifications to that URI. - -## Authenticating your cloud service - -> [!WARNING] -> This section describes the legacy UWP authentication flow using a **Package SID** and **secret key** obtained from the Microsoft Store Dashboard, which authenticates to `login.live.com`. This flow is specific to UWP apps registered via Partner Center and is **not compatible** with Windows App SDK push notifications. -> -> If you are building a WPF, WinForms, or WinUI 3 app using the Windows App SDK, use the **Azure Active Directory (Azure AD)** authentication flow described in the [Push notifications quickstart](push-quickstart.md) instead. - -To send a notification, the cloud service must be authenticated through WNS. The first step in this process occurs when you register your app with the Microsoft Store Dashboard. During the registration process, your app is given a Package security identifier (SID) and a secret key. This information is used by your cloud service to authenticate with WNS. - -The WNS authentication scheme is implemented using the client credentials profile from the [OAuth 2.0](https://tools.ietf.org/html/draft-ietf-oauth-v2-23) protocol. The cloud service authenticates with WNS by providing its credentials (Package SID and secret key). In return, it receives an access token. This access token allows a cloud service to send a notification. The token is required with every notification request sent to the WNS. - -At a high level, the information chain is as follows: - -1. The cloud service sends its credentials to WNS over HTTPS following the OAuth 2.0 protocol. This authenticates the service with WNS. -2. WNS returns an access token if the authentication was successful. This access token is used in all subsequent notification requests until it expires. - -![wns diagram for cloud service authentication](images/wns-diagram-02.jpg) - -In the authentication with WNS, the cloud service submits an HTTP request over Secure Sockets Layer (SSL). The parameters are supplied in the "application/x-www-form-urlencoded" format. Supply your Package SID in the "client\_id" field and your secret key in the "client\_secret" field as shown in the following example. For syntax details, see the [access token request](push-request-response-headers.md) reference. - -> [!NOTE] -> This is just an example, not cut-and-paste code that you can successfully use in your own code.  - -``` http - POST /accesstoken.srf HTTP/1.1 - Content-Type: application/x-www-form-urlencoded - Host: https://login.live.com - Content-Length: 211 - - grant_type=client_credentials&client_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-1345238579-3987825745-2155616079-650196962&client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7&scope=notify.windows.com -``` - -The WNS authenticates the cloud service and, if successful, sends a response of "200 OK". The access token is returned in the parameters included in the body of the HTTP response, using the "application/json" media type. After your service has received the access token, you are ready to send notifications. - -The following example shows a successful authentication response, including the access token. For syntax details, see [Push notification service request and response headers](push-request-response-headers.md). - -``` http - HTTP/1.1 200 OK - Cache-Control: no-store - Content-Length: 422 - Content-Type: application/json - - { - "access_token":"EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=", - "token_type":"bearer" - } -``` - -### Important notes - -- The OAuth 2.0 protocol supported in this procedure follows draft version V16. -- The OAuth Request for Comments (RFC) uses the term "client" to refer to the cloud service. -- There might be changes to this procedure when the OAuth draft is finalized. -- The access token can be reused for multiple notification requests. This allows the cloud service to authenticate just once to send many notifications. However, when the access token expires, the cloud service must authenticate again to receive a new access token. - -## Sending a notification - - -Using the channel URI, the cloud service can send a notification whenever it has an update for the user. - -The access token described above can be reused for multiple notification requests; the cloud server is not required to request a new access token for every notification. If the access token has expired, the notification request will return an error. We recommend that you do not try to re-send your notification more than once if the access token is rejected. If you encounter this error, you will need to request a new access token and resend the notification. For the exact error code, see [Push notification service request and response headers](push-request-response-headers.md). - -1. The cloud service makes an HTTP POST to the channel URI. This request must be made over SSL and contains the necessary headers and the notification payload. The authorization header must include the acquired access token for authorization. - - An example request is shown here. For syntax details, see [Push notification service request and response headers](push-request-response-headers.md). - - For details on composing the notification payload, see [Quickstart: Push notifications in the Windows App SDK](push-quickstart.md). The payload of a tile, toast, or badge push notification is supplied as XML content that adheres to their respective defined [Adaptive tiles schema](/windows/uwp/launch-resume/adaptive-tiles-schema) or [Legacy tiles schema](/uwp/schemas/tiles/tiles-xml-schema-portal). The payload of a raw notification does not have a specified structure. It is strictly app-defined. - - ``` http - POST https://cloud.notify.windows.com/?token=AQE%bU%2fSjZOCvRjjpILow%3d%3d HTTP/1.1 - Content-Type: text/xml - X-WNS-Type: wns/tile - Authorization: Bearer EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA= - Host: cloud.notify.windows.com - Content-Length: 24 - - - .... - ``` - -2. WNS responds to indicate that the notification has been received and will be delivered at the next available opportunity. However, WNS does not provide end-to-end confirmation that your notification has been received by the device or application. - -This diagram illustrates the data flow: - -![wns diagram for sending a notification](images/wns-diagram-03.jpg) - -### Important notes - -- WNS does not guarantee the reliability or latency of a notification. -- Notifications should never include confidential, sensitive, or personal data. -- To send a notification, the cloud service must first authenticate with WNS and receive an access token. -- An access token only allows a cloud service to send notifications to the single app for which the token was created. One access token cannot be used to send notifications across multiple apps. Therefore, if your cloud service supports multiple apps, it must provide the correct access token for the app when pushing a notification to each channel URI. -- When the device is offline, by default WNS will store one of each notification type (tile, badge, toast) for each channel URI and no raw notifications. -- In scenarios where the notification content is personalized to the user, WNS recommends that the cloud service immediately send those updates when those are received. Examples of this scenario include social media feed updates, instant communication invitations, new message notifications, or alerts. As an alternative, you can have scenarios in which the same generic update is frequently delivered to a large subset of your users; for example, weather, stock, and news updates. WNS guidelines specify that the frequency of these updates should be at most one every 30 minutes. The end user or WNS may determine more frequent routine updates to be abusive. -- Windows Notification Platform maintains a periodic data connection with WNS to keep the socket alive and healthy. If there are no applications requesting or using notification channels then the socket will not be created. - -## Expiration of tile and badge notifications - -By default, tile and badge notifications expire three days after being downloaded. When a notification expires, the content is removed from the tile or queue and is no longer shown to the user. It's a best practice to set an expiration (using a time that makes sense for your app) on all tile and badge notifications so that your tile's content doesn't persist longer than it is relevant. An explicit expiration time is essential for content with a defined lifespan. This also assures the removal of stale content if your cloud service stops sending notifications, or if the user disconnects from the network for an extended period. - -Your cloud service can set an expiration for each notification by setting the X-WNS-TTL HTTP header to specify the time (in seconds) that your notification will remain valid after it is sent. For more information, see [Push notification service request and response headers](push-request-response-headers.md). - -For example, during a stock market's active trading day, you can set the expiration for a stock price update to twice that of your sending interval (such as one hour after receipt if you are sending notifications every half-hour). As another example, a news app might determine that one day is an appropriate expiration time for a daily news tile update. - -## Push notifications and battery saver - -Battery saver extends battery life by limiting background activity on the device. Windows 10 lets the user set battery saver to turn on automatically when the battery drops below a specified threshold. When battery saver is on, the receipt of push notifications is disabled to save energy. But there are a couple exceptions to this. The following Windows 10 battery saver settings (found in Windows Settings) allow your app to receive push notifications even when battery saver is on. - -- **Allow push notifications from any app while in battery saver**: This setting lets all apps receive push notifications while battery saver is on. Note that this setting applies only to Windows 10 for desktop editions (Home, Pro, Enterprise, and Education). -- **Always allowed**: This setting lets specific apps run in the background while battery saver is on - including receiving push notifications. This list is maintained manually by the user. - -There is no way to check the state of these two settings, but you can check the state of battery saver. In Windows 10, use the [**EnergySaverStatus**](/uwp/api/Windows.System.Power.PowerManager.EnergySaverStatus) property to check battery saver state. Your app can also use the [**EnergySaverStatusChanged**](/uwp/api/Windows.System.Power.PowerManager.EnergySaverStatusChanged) event to listen for changes to battery saver. - -If your app depends heavily on push notifications, we recommend notifying users that they may not receive notifications while battery saver is on and to make it easy for them to adjust **battery saver settings**. Using the battery saver settings URI scheme in Windows, `ms-settings:batterysaver-settings`, you can provide a convenient link to Windows Settings. - -> [!TIP] -> When notifying the user about battery saver settings, we recommend providing a way to suppress the message in the future. For example, the `dontAskMeAgainBox` checkbox in the following example persists the user's preference in [**LocalSettings**](/uwp/api/Windows.Storage.ApplicationData.LocalSettings). - -Here's an example of how to check whether battery saver is turned on in Windows 10. This example notifies the user and launches Settings to **battery saver settings**. The `dontAskAgainSetting` lets the user suppress the message if they don't want to be notified again. - -```csharp -using System; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Navigation; -using Windows.System; -using Windows.System.Power; -... -... -async public void CheckForEnergySaving() -{ - //Get reminder preference from LocalSettings - bool dontAskAgain; - var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; - object dontAskSetting = localSettings.Values["dontAskAgainSetting"]; - if (dontAskSetting == null) - { // Setting does not exist - dontAskAgain = false; - } - else - { // Retrieve setting value - dontAskAgain = Convert.ToBoolean(dontAskSetting); - } - - // Check if battery saver is on and that it's okay to raise dialog - if ((PowerManager.EnergySaverStatus == EnergySaverStatus.On) - && (dontAskAgain == false)) - { - // Check dialog results - ContentDialogResult dialogResult = await saveEnergyDialog.ShowAsync(); - if (dialogResult == ContentDialogResult.Primary) - { - // Launch battery saver settings (settings are available only when a battery is present) - await Launcher.LaunchUriAsync(new Uri("ms-settings:batterysaver-settings")); - } - - // Save reminder preference - if (dontAskAgainBox.IsChecked == true) - { // Don't raise dialog again - localSettings.Values["dontAskAgainSetting"] = "true"; - } - } -} -``` - -```cppwinrt -#include -#include -#include -#include -#include -#include -#include -using namespace winrt; -using namespace winrt::Windows::Foundation; -using namespace winrt::Windows::Storage; -using namespace winrt::Windows::System; -using namespace winrt::Windows::System::Power; -using namespace winrt::Windows::UI::Xaml; -using namespace winrt::Windows::UI::Xaml::Controls; -using namespace winrt::Windows::UI::Xaml::Navigation; -... -winrt::fire_and_forget CheckForEnergySaving() -{ - // Get reminder preference from LocalSettings. - bool dontAskAgain{ false }; - auto localSettings = ApplicationData::Current().LocalSettings(); - IInspectable dontAskSetting = localSettings.Values().Lookup(L"dontAskAgainSetting"); - if (!dontAskSetting) - { - // Setting doesn't exist. - dontAskAgain = false; - } - else - { - // Retrieve setting value - dontAskAgain = winrt::unbox_value(dontAskSetting); - } - - // Check whether battery saver is on, and whether it's okay to raise dialog. - if ((PowerManager::EnergySaverStatus() == EnergySaverStatus::On) && (!dontAskAgain)) - { - // Check dialog results. - ContentDialogResult dialogResult = co_await saveEnergyDialog().ShowAsync(); - if (dialogResult == ContentDialogResult::Primary) - { - // Launch battery saver settings - // (settings are available only when a battery is present). - co_await Launcher::LaunchUriAsync(Uri(L"ms-settings:batterysaver-settings")); - } - - // Save reminder preference. - if (dontAskAgainBox().IsChecked()) - { - // Don't raise the dialog again. - localSettings.Values().Insert(L"dontAskAgainSetting", winrt::box_value(true)); - } - } -} -``` - -This is the XAML for the [**ContentDialog**](/uwp/api/Windows.UI.Xaml.Controls.ContentDialog) featured in this example. - -```xaml - - - - Battery saver is on and you may - not receive push notifications. - You can choose to allow this app to work normally - while in battery saver, including receiving push notifications. - - - - - -``` - -## Related topics - -* [Quickstart: Push notifications in the Windows App SDK](push-quickstart.md) -* [Push notification service request and response headers](push-request-response-headers.md) -* [How to request, create, and save a notification channel](request-create-save-notification-channel.md) -* [WNS notification priorities](wns-notification-priorities.md) -* [Raw notifications overview](raw-notification-overview.md) -* [Troubleshoot push notifications](troubleshoot-notifications.md) -* [Send a local tile notification](/windows/uwp/launch-resume/sending-a-local-tile-notification) +--- +description: The Windows Push Notification Services (WNS) enables third-party developers to send toast, tile, badge, and raw updates from their own cloud service. This provides a mechanism to deliver new updates to your users in a power-efficient and dependable way. +title: Windows Push Notification Services (WNS) overview +ms.assetid: 2125B09F-DB90-4515-9AA6-516C7E9ACCCD +template: detail.hbs +ms.date: 04/09/2026 +ms.topic: article +keywords: windows 10, uwp +ms.localizationpriority: medium +--- + +# Windows Push Notification Services (WNS) overview + +The Windows Push Notification Services (WNS) enable third-party developers to send toast, tile, badge, and raw updates from their own cloud service. This provides a mechanism to deliver new updates to your users in a power-efficient and dependable way. + +## How it works + +The following diagram shows the complete data flow for sending a push notification. It involves these steps: + +1. Your app requests a push notification channel from WNS. +2. Windows asks WNS to create a notification channel. This channel is returned to the calling device in the form of a Uniform Resource Identifier (URI). +3. The notification channel URI is returned by WNS to your app. +4. Your app sends the URI to your own cloud service. You then store the URI on your own cloud service so that you can access the URI when you send notifications. The URI is an interface between your own app and your own service; it's your responsibility to implement this interface with safe and secure web standards. +5. When your cloud service has an update to send, it notifies WNS using the channel URI. This is done by issuing an HTTP POST request, including the notification payload, over Secure Sockets Layer (SSL). This step requires authentication. +6. WNS receives the request and routes the notification to the appropriate device. + +![wns data flow diagram for push notification](images/wns-diagram-01.jpg) + +## Registering your app and receiving the credentials for your cloud service + +Before you can send notifications using WNS, your app must be registered with the Store Dashboard, as described [here](/azure/notification-hubs/notification-hubs-windows-store-dotnet-get-started-wns-push-notification). + +## Requesting a notification channel + +> [!NOTE] +> The channel-request guidance in this section applies to UWP apps that use [**CreatePushNotificationChannelForApplicationAsync**](/uwp/api/Windows.Networking.PushNotifications.PushNotificationChannelManager#Windows_Networking_PushNotifications_PushNotificationChannelManager_CreatePushNotificationChannelForApplicationAsync_System_String_). If you're building a Windows App SDK desktop app (WinUI 3, WPF, or WinForms), use `PushNotificationManager` instead — see the [Push notifications quickstart](push-quickstart.md). + +When an app that is capable of receiving push notifications runs, it must first request a notification channel through the [**CreatePushNotificationChannelForApplicationAsync**](/uwp/api/Windows.Networking.PushNotifications.PushNotificationChannelManager#Windows_Networking_PushNotifications_PushNotificationChannelManager_CreatePushNotificationChannelForApplicationAsync_System_String_). For a full discussion and example code, see [How to request, create, and save a notification channel](request-create-save-notification-channel.md). This API returns a channel URI that is uniquely linked to the calling application and its tile, and through which all notification types can be sent. + +After the app has successfully created a channel URI, it sends it to its cloud service, together with any app-specific metadata that should be associated with this URI. + +### Important notes + +- We do not guarantee that the notification channel URI for an app will always remain the same. We advise that the app requests a new channel every time it runs and updates its service when the URI changes. The developer should never modify the channel URI and should consider it as a black-box string. At this time, channel URIs expire after 30 days. If your Windows 10 app will periodically renew its channel in the background then you can download the [Push and periodic notifications sample](https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/411c271e537727d737a53fa2cbe99eaecac00cc0/Official%20Windows%20Platform%20Sample/Windows%208%20app%20samples/%5BC%23%5D-Windows%208%20app%20samples/C%23/Windows%208%20app%20samples/Push%20and%20periodic%20notifications%20client-side%20sample%20(Windows%208)) for Windows 8.1 and re-use its source code and/or the pattern it demonstrates. +- The interface between the cloud service and the client app is implemented by you, the developer. We recommend that the app go through an authentication process with its own service and transmit data over a secure protocol such as HTTPS. +- It is important that the cloud service always ensures that the channel URI uses the domain "notify.windows.com". The service should never push notifications to a channel on any other domain. If the callback for your app is ever compromised, a malicious attacker could submit a channel URI to spoof WNS. Without inspecting the domain, your cloud service could potentially disclose information to this attacker unknowingly. The subdomain of the channel URI is subject to change and should not be considered when validating the channel URI. +- If your cloud service attempts to deliver a notification to an expired channel, WNS will return [response code 410](push-request-response-headers.md). In response to that code, your service should no longer attempt to send notifications to that URI. + +## Authenticating your cloud service + +> [!WARNING] +> This section describes the legacy UWP authentication flow using a **Package SID** and **secret key** obtained from the Microsoft Store Dashboard, which authenticates to `login.live.com`. This flow is specific to UWP apps registered via Partner Center and is **not compatible** with Windows App SDK push notifications. +> +> If you are building a WPF, WinForms, or WinUI 3 app using the Windows App SDK, use the **Azure Active Directory (Azure AD)** authentication flow described in the [Push notifications quickstart](push-quickstart.md) instead. + +To send a notification, the cloud service must be authenticated through WNS. The first step in this process occurs when you register your app with the Microsoft Store Dashboard. During the registration process, your app is given a Package security identifier (SID) and a secret key. This information is used by your cloud service to authenticate with WNS. + +The WNS authentication scheme is implemented using the client credentials profile from the [OAuth 2.0](https://tools.ietf.org/html/draft-ietf-oauth-v2-23) protocol. The cloud service authenticates with WNS by providing its credentials (Package SID and secret key). In return, it receives an access token. This access token allows a cloud service to send a notification. The token is required with every notification request sent to the WNS. + +At a high level, the information chain is as follows: + +1. The cloud service sends its credentials to WNS over HTTPS following the OAuth 2.0 protocol. This authenticates the service with WNS. +2. WNS returns an access token if the authentication was successful. This access token is used in all subsequent notification requests until it expires. + +![wns diagram for cloud service authentication](images/wns-diagram-02.jpg) + +In the authentication with WNS, the cloud service submits an HTTP request over Secure Sockets Layer (SSL). The parameters are supplied in the "application/x-www-form-urlencoded" format. Supply your Package SID in the "client\_id" field and your secret key in the "client\_secret" field as shown in the following example. For syntax details, see the [access token request](push-request-response-headers.md) reference. + +> [!NOTE] +> This is just an example, not cut-and-paste code that you can successfully use in your own code.  + +``` http + POST /accesstoken.srf HTTP/1.1 + Content-Type: application/x-www-form-urlencoded + Host: https://login.live.com + Content-Length: 211 + + grant_type=client_credentials&client_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-1345238579-3987825745-2155616079-650196962&client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7&scope=notify.windows.com +``` + +The WNS authenticates the cloud service and, if successful, sends a response of "200 OK". The access token is returned in the parameters included in the body of the HTTP response, using the "application/json" media type. After your service has received the access token, you are ready to send notifications. + +The following example shows a successful authentication response, including the access token. For syntax details, see [Push notification service request and response headers](push-request-response-headers.md). + +``` http + HTTP/1.1 200 OK + Cache-Control: no-store + Content-Length: 422 + Content-Type: application/json + + { + "access_token":"EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=", + "token_type":"bearer" + } +``` + +### Important notes + +- The OAuth 2.0 protocol supported in this procedure follows draft version V16. +- The OAuth Request for Comments (RFC) uses the term "client" to refer to the cloud service. +- There might be changes to this procedure when the OAuth draft is finalized. +- The access token can be reused for multiple notification requests. This allows the cloud service to authenticate just once to send many notifications. However, when the access token expires, the cloud service must authenticate again to receive a new access token. + +## Sending a notification + + +Using the channel URI, the cloud service can send a notification whenever it has an update for the user. + +The access token described above can be reused for multiple notification requests; the cloud server is not required to request a new access token for every notification. If the access token has expired, the notification request will return an error. We recommend that you do not try to re-send your notification more than once if the access token is rejected. If you encounter this error, you will need to request a new access token and resend the notification. For the exact error code, see [Push notification service request and response headers](push-request-response-headers.md). + +1. The cloud service makes an HTTP POST to the channel URI. This request must be made over SSL and contains the necessary headers and the notification payload. The authorization header must include the acquired access token for authorization. + + An example request is shown here. For syntax details, see [Push notification service request and response headers](push-request-response-headers.md). + + For details on composing the notification payload, see [Quickstart: Push notifications in the Windows App SDK](push-quickstart.md). The payload of a tile, toast, or badge push notification is supplied as XML content that adheres to their respective defined [Adaptive tiles schema](/windows/uwp/launch-resume/adaptive-tiles-schema) or [Legacy tiles schema](/uwp/schemas/tiles/tiles-xml-schema-portal). The payload of a raw notification does not have a specified structure. It is strictly app-defined. + + ``` http + POST https://cloud.notify.windows.com/?token=AQE%bU%2fSjZOCvRjjpILow%3d%3d HTTP/1.1 + Content-Type: text/xml + X-WNS-Type: wns/tile + Authorization: Bearer EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA= + Host: cloud.notify.windows.com + Content-Length: 24 + + + .... + ``` + +2. WNS responds to indicate that the notification has been received and will be delivered at the next available opportunity. However, WNS does not provide end-to-end confirmation that your notification has been received by the device or application. + +This diagram illustrates the data flow: + +![wns diagram for sending a notification](images/wns-diagram-03.jpg) + +### Important notes + +- WNS does not guarantee the reliability or latency of a notification. +- Notifications should never include confidential, sensitive, or personal data. +- To send a notification, the cloud service must first authenticate with WNS and receive an access token. +- An access token only allows a cloud service to send notifications to the single app for which the token was created. One access token cannot be used to send notifications across multiple apps. Therefore, if your cloud service supports multiple apps, it must provide the correct access token for the app when pushing a notification to each channel URI. +- When the device is offline, by default WNS will store one of each notification type (tile, badge, toast) for each channel URI and no raw notifications. +- In scenarios where the notification content is personalized to the user, WNS recommends that the cloud service immediately send those updates when those are received. Examples of this scenario include social media feed updates, instant communication invitations, new message notifications, or alerts. As an alternative, you can have scenarios in which the same generic update is frequently delivered to a large subset of your users; for example, weather, stock, and news updates. WNS guidelines specify that the frequency of these updates should be at most one every 30 minutes. The end user or WNS may determine more frequent routine updates to be abusive. +- Windows Notification Platform maintains a periodic data connection with WNS to keep the socket alive and healthy. If there are no applications requesting or using notification channels then the socket will not be created. + +## Expiration of tile and badge notifications + +By default, tile and badge notifications expire three days after being downloaded. When a notification expires, the content is removed from the tile or queue and is no longer shown to the user. It's a best practice to set an expiration (using a time that makes sense for your app) on all tile and badge notifications so that your tile's content doesn't persist longer than it is relevant. An explicit expiration time is essential for content with a defined lifespan. This also assures the removal of stale content if your cloud service stops sending notifications, or if the user disconnects from the network for an extended period. + +Your cloud service can set an expiration for each notification by setting the X-WNS-TTL HTTP header to specify the time (in seconds) that your notification will remain valid after it is sent. For more information, see [Push notification service request and response headers](push-request-response-headers.md). + +For example, during a stock market's active trading day, you can set the expiration for a stock price update to twice that of your sending interval (such as one hour after receipt if you are sending notifications every half-hour). As another example, a news app might determine that one day is an appropriate expiration time for a daily news tile update. + +## Push notifications and battery saver + +Battery saver extends battery life by limiting background activity on the device. Windows 10 lets the user set battery saver to turn on automatically when the battery drops below a specified threshold. When battery saver is on, the receipt of push notifications is disabled to save energy. But there are a couple exceptions to this. The following Windows 10 battery saver settings (found in Windows Settings) allow your app to receive push notifications even when battery saver is on. + +- **Allow push notifications from any app while in battery saver**: This setting lets all apps receive push notifications while battery saver is on. Note that this setting applies only to Windows 10 for desktop editions (Home, Pro, Enterprise, and Education). +- **Always allowed**: This setting lets specific apps run in the background while battery saver is on - including receiving push notifications. This list is maintained manually by the user. + +There is no way to check the state of these two settings, but you can check the state of battery saver. In Windows 10, use the [**EnergySaverStatus**](/uwp/api/Windows.System.Power.PowerManager.EnergySaverStatus) property to check battery saver state. Your app can also use the [**EnergySaverStatusChanged**](/uwp/api/Windows.System.Power.PowerManager.EnergySaverStatusChanged) event to listen for changes to battery saver. + +If your app depends heavily on push notifications, we recommend notifying users that they may not receive notifications while battery saver is on and to make it easy for them to adjust **battery saver settings**. Using the battery saver settings URI scheme in Windows, `ms-settings:batterysaver-settings`, you can provide a convenient link to Windows Settings. + +> [!TIP] +> When notifying the user about battery saver settings, we recommend providing a way to suppress the message in the future. For example, the `dontAskMeAgainBox` checkbox in the following example persists the user's preference in [**LocalSettings**](/uwp/api/Windows.Storage.ApplicationData.LocalSettings). + +Here's an example of how to check whether battery saver is turned on in Windows 10. This example notifies the user and launches Settings to **battery saver settings**. The `dontAskAgainSetting` lets the user suppress the message if they don't want to be notified again. + +```csharp +using System; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Navigation; +using Windows.System; +using Windows.System.Power; +... +... +async public void CheckForEnergySaving() +{ + //Get reminder preference from LocalSettings + bool dontAskAgain; + var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings; + object dontAskSetting = localSettings.Values["dontAskAgainSetting"]; + if (dontAskSetting == null) + { // Setting does not exist + dontAskAgain = false; + } + else + { // Retrieve setting value + dontAskAgain = Convert.ToBoolean(dontAskSetting); + } + + // Check if battery saver is on and that it's okay to raise dialog + if ((PowerManager.EnergySaverStatus == EnergySaverStatus.On) + && (dontAskAgain == false)) + { + // Check dialog results + ContentDialogResult dialogResult = await saveEnergyDialog.ShowAsync(); + if (dialogResult == ContentDialogResult.Primary) + { + // Launch battery saver settings (settings are available only when a battery is present) + await Launcher.LaunchUriAsync(new Uri("ms-settings:batterysaver-settings")); + } + + // Save reminder preference + if (dontAskAgainBox.IsChecked == true) + { // Don't raise dialog again + localSettings.Values["dontAskAgainSetting"] = "true"; + } + } +} +``` + +```cppwinrt +#include +#include +#include +#include +#include +#include +#include +using namespace winrt; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Storage; +using namespace winrt::Windows::System; +using namespace winrt::Windows::System::Power; +using namespace winrt::Microsoft::UI::Xaml; +using namespace winrt::Microsoft::UI::Xaml::Controls; +using namespace winrt::Microsoft::UI::Xaml::Navigation; +... +winrt::fire_and_forget CheckForEnergySaving() +{ + // Get reminder preference from LocalSettings. + bool dontAskAgain{ false }; + auto localSettings = ApplicationData::Current().LocalSettings(); + IInspectable dontAskSetting = localSettings.Values().Lookup(L"dontAskAgainSetting"); + if (!dontAskSetting) + { + // Setting doesn't exist. + dontAskAgain = false; + } + else + { + // Retrieve setting value + dontAskAgain = winrt::unbox_value(dontAskSetting); + } + + // Check whether battery saver is on, and whether it's okay to raise dialog. + if ((PowerManager::EnergySaverStatus() == EnergySaverStatus::On) && (!dontAskAgain)) + { + // Check dialog results. + ContentDialogResult dialogResult = co_await saveEnergyDialog().ShowAsync(); + if (dialogResult == ContentDialogResult::Primary) + { + // Launch battery saver settings + // (settings are available only when a battery is present). + co_await Launcher::LaunchUriAsync(Uri(L"ms-settings:batterysaver-settings")); + } + + // Save reminder preference. + if (dontAskAgainBox().IsChecked()) + { + // Don't raise the dialog again. + localSettings.Values().Insert(L"dontAskAgainSetting", winrt::box_value(true)); + } + } +} +``` + +This is the XAML for the [**ContentDialog**](/uwp/api/Windows.UI.Xaml.Controls.ContentDialog) featured in this example. + +```xaml + + + + Battery saver is on and you may + not receive push notifications. + You can choose to allow this app to work normally + while in battery saver, including receiving push notifications. + + + + + +``` + +## Related topics + +* [Quickstart: Push notifications in the Windows App SDK](push-quickstart.md) +* [Push notification service request and response headers](push-request-response-headers.md) +* [How to request, create, and save a notification channel](request-create-save-notification-channel.md) +* [WNS notification priorities](wns-notification-priorities.md) +* [Raw notifications overview](raw-notification-overview.md) +* [Troubleshoot push notifications](troubleshoot-notifications.md) +* [Send a local tile notification](/windows/uwp/launch-resume/sending-a-local-tile-notification) diff --git a/hub/apps/develop/platform/xaml/3-d-perspective-effects.md b/hub/apps/develop/platform/xaml/3-d-perspective-effects.md index 213d2c6bfa..d1d5b6202d 100644 --- a/hub/apps/develop/platform/xaml/3-d-perspective-effects.md +++ b/hub/apps/develop/platform/xaml/3-d-perspective-effects.md @@ -20,7 +20,7 @@ Another common usage for perspective transforms is to arrange objects in relatio Besides creating static 3-D effects, you can animate the perspective transform properties to create moving 3-D effects. -You just saw perspective transforms applied to images, but you can apply these effects to any [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement), including controls. For example, you can apply a 3-D effect to an entire container of controls like this: +You just saw perspective transforms applied to images, but you can apply these effects to any [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement), including controls. For example, you can apply a 3-D effect to an entire container of controls like this: ![3-D effect applied to a container of elements](images/skewedstackpanel.png) @@ -37,11 +37,11 @@ Here is the XAML code used to create this sample: ``` -Here we focus on the properties of [**PlaneProjection**](/uwp/api/Windows.UI.Xaml.Media.PlaneProjection) which is used to rotate and move objects in 3-D space. The next sample allows you to experiment with these properties and see their effect on an object. +Here we focus on the properties of [**PlaneProjection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.PlaneProjection) which is used to rotate and move objects in 3-D space. The next sample allows you to experiment with these properties and see their effect on an object. ## PlaneProjection class -You can apply 3D effects can to any [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement), by setting the UIElement's [**Projection**](/uwp/api/windows.ui.xaml.uielement.projection) property using a [**PlaneProjection**](/uwp/api/Windows.UI.Xaml.Media.PlaneProjection). The **PlaneProjection** defines how the transform is rendered in space. The next example shows a simple case. +You can apply 3D effects can to any [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement), by setting the UIElement's [**Projection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.projection) property using a [**PlaneProjection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.PlaneProjection). The **PlaneProjection** defines how the transform is rendered in space. The next example shows a simple case. ```xml @@ -51,11 +51,11 @@ You can apply 3D effects can to any [**UIElement**](/uwp/api/Windows.UI.Xaml.UIE ``` -This figure shows what the image renders as. The x-axis, y-axis, and z-axis are shown as red lines. The image is rotated backward 35 degrees around the x-axis using the [**RotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationx) property. +This figure shows what the image renders as. The x-axis, y-axis, and z-axis are shown as red lines. The image is rotated backward 35 degrees around the x-axis using the [**RotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationx) property. ![RotateX minus 35 degrees](images/3drotatexminus35.png) -The [**RotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationy) property rotates around the y-axis of the center of rotation. +The [**RotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationy) property rotates around the y-axis of the center of rotation. ```xml @@ -67,7 +67,7 @@ The [**RotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationy) pr ![RotateY minus 35 degrees](images/3drotateyminus35.png) -The [**RotationZ**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationz) property rotates around the z-axis of the center of rotation (a line that is perpendicular to the plane of the object). +The [**RotationZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationz) property rotates around the z-axis of the center of rotation (a line that is perpendicular to the plane of the object). ```xml @@ -81,9 +81,9 @@ The [**RotationZ**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationz) pr The rotation properties can specify a positive or negative value to rotate in either direction. The absolute number can be greater than 360, which rotates the object more than one full rotation. -You can move the center of rotation by using the [**CenterOfRotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationx), [**CenterOfRotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationy), and [**CenterOfRotationZ**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationz) properties. By default, the axes of rotation run directly through the center of the object, causing the object to rotate around its center. But if you move the center of rotation to the outer edge of the object, it will rotate around that edge. The default values for **CenterOfRotationX** and **CenterOfRotationY** are 0.5, and the default value for **CenterOfRotationZ** is 0. For **CenterOfRotationX** and **CenterOfRotationY**, values between 0 and 1 set the pivot point at some location within the object. A value of 0 denotes one object edge and 1 denotes the opposite edge. Values outside of this range are allowed and will move the center of rotation accordingly. Because the z-axis of the center of rotation is drawn through the plane of the object, you can move the center of rotation behind the object using a negative number and in front of the object (toward you) using a positive number. +You can move the center of rotation by using the [**CenterOfRotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationx), [**CenterOfRotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationy), and [**CenterOfRotationZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationz) properties. By default, the axes of rotation run directly through the center of the object, causing the object to rotate around its center. But if you move the center of rotation to the outer edge of the object, it will rotate around that edge. The default values for **CenterOfRotationX** and **CenterOfRotationY** are 0.5, and the default value for **CenterOfRotationZ** is 0. For **CenterOfRotationX** and **CenterOfRotationY**, values between 0 and 1 set the pivot point at some location within the object. A value of 0 denotes one object edge and 1 denotes the opposite edge. Values outside of this range are allowed and will move the center of rotation accordingly. Because the z-axis of the center of rotation is drawn through the plane of the object, you can move the center of rotation behind the object using a negative number and in front of the object (toward you) using a positive number. -[**CenterOfRotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationx) moves the center of rotation along the x-axis parallel to the object while [**CenterOfRotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationy) moves the center or rotation along the y-axis of the object. The next illustrations demonstrate using different values for **CenterOfRotationY**. +[**CenterOfRotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationx) moves the center of rotation along the x-axis parallel to the object while [**CenterOfRotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationy) moves the center or rotation along the y-axis of the object. The next illustrations demonstrate using different values for **CenterOfRotationY**. ```xml @@ -108,7 +108,7 @@ You can move the center of rotation by using the [**CenterOfRotationX**](/uwp/ap ![CenterOfRotationY equals 0.1](images/3dcenterofrotationy0point1.png) -Notice how the image rotates around the center when the [**CenterOfRotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationy) property is set to the default value of 0.5 and rotates near the upper edge when set to 0.1. You see similar behavior when changing the [**CenterOfRotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationx) property to move where the [**RotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationy) property rotates the object. +Notice how the image rotates around the center when the [**CenterOfRotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationy) property is set to the default value of 0.5 and rotates near the upper edge when set to 0.1. You see similar behavior when changing the [**CenterOfRotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationx) property to move where the [**RotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationy) property rotates the object. ```xml @@ -133,39 +133,39 @@ Notice how the image rotates around the center when the [**CenterOfRotationY**]( ![CenterOfRotationX equals 0.9](images/3dcenterofrotationx0point9.png) -Use the [**CenterOfRotationZ**](/uwp/api/windows.ui.xaml.media.planeprojection.centerofrotationz) to place the center of rotation above or below the plane of the object. This way, you can rotate the object around the point analogous to a planet orbiting around a star. +Use the [**CenterOfRotationZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.centerofrotationz) to place the center of rotation above or below the plane of the object. This way, you can rotate the object around the point analogous to a planet orbiting around a star. ## Positioning an object So far, you learned how to rotate an object in space. You can position these rotated objects in space relative to one another by using these properties: -- [**LocalOffsetX**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsetx) moves an object along the x-axis of the plane of a rotated object. -- [**LocalOffsetY**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsety) moves an object along the y-axis of the plane of a rotated object. -- [**LocalOffsetZ**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsetz) moves an object along the z-axis of the plane of a rotated object. -- [**GlobalOffsetX**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsetx) moves an object along the screen-aligned x-axis. -- [**GlobalOffsetY**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsety) moves an object along the screen-aligned y-axis. -- [**GlobalOffsetZ**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsetz) moves an object along the screen-aligned z-axis. +- [**LocalOffsetX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsetx) moves an object along the x-axis of the plane of a rotated object. +- [**LocalOffsetY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsety) moves an object along the y-axis of the plane of a rotated object. +- [**LocalOffsetZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsetz) moves an object along the z-axis of the plane of a rotated object. +- [**GlobalOffsetX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsetx) moves an object along the screen-aligned x-axis. +- [**GlobalOffsetY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsety) moves an object along the screen-aligned y-axis. +- [**GlobalOffsetZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsetz) moves an object along the screen-aligned z-axis. **Local offset** -The [**LocalOffsetX**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsetx), [**LocalOffsetY**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsety), and [**LocalOffsetZ**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsetz) properties translate an object along the respective axis of the plane of the object after it has been rotated. Therefore, the rotation of the object determines the direction that the object is translated. To demonstrate this concept, the next sample animates **LocalOffsetX** from 0 to 400 and [**RotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationy) from 0 to 65 degrees. +The [**LocalOffsetX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsetx), [**LocalOffsetY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsety), and [**LocalOffsetZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsetz) properties translate an object along the respective axis of the plane of the object after it has been rotated. Therefore, the rotation of the object determines the direction that the object is translated. To demonstrate this concept, the next sample animates **LocalOffsetX** from 0 to 400 and [**RotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationy) from 0 to 65 degrees. -Notice in the preceding sample that the object is moving along its own x-axis. At the very beginning of the animation, when the [**RotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationy) value is near zero (parallel to the screen), the object moves along the screen in the x direction, but as the object rotates toward you, the object moves along the x-axis of the plane of the object toward you. On the other hand, if you animated the **RotationY** property to -65 degrees, the object would curve away from you. +Notice in the preceding sample that the object is moving along its own x-axis. At the very beginning of the animation, when the [**RotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationy) value is near zero (parallel to the screen), the object moves along the screen in the x direction, but as the object rotates toward you, the object moves along the x-axis of the plane of the object toward you. On the other hand, if you animated the **RotationY** property to -65 degrees, the object would curve away from you. -[**LocalOffsetY**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsety) works similarly to [**LocalOffsetX**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsetx), except that it moves along the vertical axis, so changing [**RotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationx) affects the direction **LocalOffsetY** moves the object. In the next sample, **LocalOffsetY** is animated from 0 to 400 and **RotationX** from 0 to 65 degrees. +[**LocalOffsetY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsety) works similarly to [**LocalOffsetX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsetx), except that it moves along the vertical axis, so changing [**RotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationx) affects the direction **LocalOffsetY** moves the object. In the next sample, **LocalOffsetY** is animated from 0 to 400 and **RotationX** from 0 to 65 degrees. -[**LocalOffsetZ**](/uwp/api/windows.ui.xaml.media.planeprojection.localoffsetz) translates the object perpendicular to the plane of the object as though a vector was drawn directly through the center from behind the object out toward you. To demonstrate how **LocalOffsetZ** works, the next sample animates **LocalOffsetZ** from 0 to 400 and [**RotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationx) from 0 to 65 degrees. +[**LocalOffsetZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.localoffsetz) translates the object perpendicular to the plane of the object as though a vector was drawn directly through the center from behind the object out toward you. To demonstrate how **LocalOffsetZ** works, the next sample animates **LocalOffsetZ** from 0 to 400 and [**RotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationx) from 0 to 65 degrees. -At the beginning of the animation, when the [**RotationX**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationx) value is near zero (parallel to the screen), the object moves directly out toward you, but as the face of the object rotates down, the object moves down instead. +At the beginning of the animation, when the [**RotationX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationx) value is near zero (parallel to the screen), the object moves directly out toward you, but as the face of the object rotates down, the object moves down instead. **Global offset** -The [**GlobalOffsetX**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsetx), [**GlobalOffsetY**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsety), and [**GlobalOffsetZ**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsetz) properties translate the object along axes relative to the screen. That is, unlike the local offset properties, the axis the object moves along is independent of any rotation applied to the object. These properties are useful when you want to simply move the object along the x-, y-, or z-axis of the screen without worrying about the rotation applied to the object. +The [**GlobalOffsetX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsetx), [**GlobalOffsetY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsety), and [**GlobalOffsetZ**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsetz) properties translate the object along axes relative to the screen. That is, unlike the local offset properties, the axis the object moves along is independent of any rotation applied to the object. These properties are useful when you want to simply move the object along the x-, y-, or z-axis of the screen without worrying about the rotation applied to the object. -The next sample animates [**GlobalOffsetX**](/uwp/api/windows.ui.xaml.media.planeprojection.globaloffsetx) from 0 to 400 and [**RotationY**](/uwp/api/windows.ui.xaml.media.planeprojection.rotationy) from 0 to 65 degrees. +The next sample animates [**GlobalOffsetX**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.globaloffsetx) from 0 to 400 and [**RotationY**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.planeprojection.rotationy) from 0 to 65 degrees. Notice in this sample that the object does not change course as it rotates. That is because the object is being moved along the x-axis of the screen without regard to its rotation. ## More complex semi-3D scenarios -You can use the [**Matrix3DProjection**](/uwp/api/Windows.UI.Xaml.Media.Matrix3DProjection) and [**Matrix3D**](/uwp/api/Windows.UI.Xaml.Media.Media3D.Matrix3D) types for more complex semi-3D scenarios than are possible with the [**PlaneProjection**](/uwp/api/Windows.UI.Xaml.Media.PlaneProjection). **Matrix3DProjection** provides you with a complete 3D transform matrix to apply to any [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement), so that you can apply arbitrary model transformation matrices and perspective matrices to elements. Keep in mind that these API are minimal and therefore if you use them, you will need to write the code that correctly creates the 3D transform matrices. Because of this, it is easier to use **PlaneProjection** for simple 3D scenarios. +You can use the [**Matrix3DProjection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.Matrix3DProjection) and [**Matrix3D**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.Media3D.Matrix3D) types for more complex semi-3D scenarios than are possible with the [**PlaneProjection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.Media.PlaneProjection). **Matrix3DProjection** provides you with a complete 3D transform matrix to apply to any [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.UIElement), so that you can apply arbitrary model transformation matrices and perspective matrices to elements. Keep in mind that these API are minimal and therefore if you use them, you will need to write the code that correctly creates the 3D transform matrices. Because of this, it is easier to use **PlaneProjection** for simple 3D scenarios. diff --git a/hub/apps/develop/ui/controls/command-bar-flyout.md b/hub/apps/develop/ui/controls/command-bar-flyout.md index 28951d5a94..fb8d62919e 100644 --- a/hub/apps/develop/ui/controls/command-bar-flyout.md +++ b/hub/apps/develop/ui/controls/command-bar-flyout.md @@ -1,419 +1,419 @@ ---- -description: Command bar flyouts give users inline access to your app's most common tasks. -title: Command bar flyout -label: Command bar flyout -template: detail.hbs -ms.date: 02/26/2025 -ms.topic: how-to -doc-status: Published -ms.localizationpriority: medium -ms.custom: RS5 ---- -# Command bar flyout - -The command bar flyout lets you provide users with easy access to common tasks by showing commands in a floating toolbar related to an element on your UI canvas. - -![An expanded text proofing command bar flyout](images/command-bar-flyout-text-full-1-5.png) - -Like [CommandBar](../../../design/controls/command-bar.md), CommandBarFlyout has **PrimaryCommands** and **SecondaryCommands** properties you can use to add commands. You can place commands in either collection, or both. When and how the primary and secondary commands are displayed depends on the display mode. - -The command bar flyout has two display modes: *collapsed* and *expanded*. - -- In the collapsed mode, only the primary commands are shown. If your command bar flyout has both primary and secondary commands, a "see more" button, which is represented by an ellipsis \[...\], is displayed. This lets the user get access to the secondary commands by transitioning to expanded mode. -- In the expanded mode, both the primary and secondary commands are shown. (If the control has only secondary items, they are shown in a way similar to the MenuFlyout control.) - -## Is this the right control? - -Use the command bar flyout control to show a collection of commands to the user, such as buttons and menu items, in the context of an element on the app canvas. - -Command bar flyout is the recommended control for creating [context menus](../../../design/controls/menus-and-context-menus.md). This allows the common commands (such as Copy, Cut, Paste, Delete, Share or text selection commands) that are most contextually relevant for the context menu's scenario to be added as primary commands so that they will be shown as a single, horizontal row in the command bar flyout. The TextCommandBarFlyout is already configured appropriately to automatically display text commands in TextBox, TextBlock, RichEditBox, RichTextBlock, and PasswordBox controls. A CommandBarFlyout can be used to replace the default text commands on text controls. - -To show contextual commands on list items follow the guidance in [Contextual commanding for collections and lists](../../../design/controls/collection-commanding.md). - -## Proactive vs. reactive invocation - -There are typically two ways to invoke a flyout or menu that's associated with an element on your UI canvas: _proactive invocation_ and _reactive invocation_. - -In proactive invocation, commands appear automatically when the user interacts with the item that the commands are associated with. For example, text formatting commands might pop up when the user selects text in a text box. In this case, the command bar flyout does not take focus. Instead, it presents relevant commands close to the item the user is interacting with. If the user doesn't interact with the commands, they are dismissed. - -In reactive invocation, commands are shown in response to an explicit user action to request the commands; for example, a right-click. This corresponds to the traditional concept of a [context menu](../../../design/controls/menus-and-context-menus.md). - -You can use the CommandBarFlyout in either way, or even a mixture of the two. - -## Create a command bar flyout - -> [!div class="checklist"] -> -> - **Important APIs:** [CommandBarFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout), [TextCommandBarFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textcommandbarflyout), [AppBarButton class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton), [AppBarToggleButton class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton), [AppBarSeparator class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarseparator) - -> [!div class="nextstepaction"] -> [Open the WinUI 3 Gallery app and see the CommandBarFlyout in action](winui3gallery://item/CommandBarFlyout) - -[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] - -This example shows how to create a command bar flyout and use it both proactively and reactively. When the image is tapped, the flyout is shown in its collapsed mode. When shown as a context menu, the flyout is shown in its expanded mode. In either case, the user can expand or collapse the flyout after it's opened. - -```xaml - - - - - - - - - - - - - - - -``` - -```csharp -private void Image_Tapped(object sender, TappedRoutedEventArgs e) -{ - var flyout = FlyoutBase.GetAttachedFlyout((FrameworkElement)sender); - var options = new FlyoutShowOptions() - { - // Position shows the flyout next to the pointer. - // "Transient" ShowMode makes the flyout open in its collapsed state. - Position = e.GetPosition((FrameworkElement)sender), - ShowMode = FlyoutShowMode.Transient - }; - flyout?.ShowAt((FrameworkElement)sender, options); -} -``` - -Here's the command bar flyout in its collapsed state. - -![Example of a collapsed command bar flyout](images/command-bar-flyout-img-collapsed-1-5.png) - -Here's the same command bar flyout in its expanded state showing secondary commands. - -![Example of an expanded command bar flyout](images/command-bar-flyout-img-expanded-1-5.png) - -### Show commands proactively - -When you show contextual commands proactively, only the primary commands should be shown by default (the command bar flyout should be collapsed). Place the most important commands in the primary commands collection, and additional commands that would traditionally go in a context menu into the secondary commands collection. - -To proactively show commands, you typically handle the [Click](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.buttonbase.click) or [Tapped](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.tapped) event to show the command bar flyout. Set the flyout's [ShowMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.showmode) to **Transient** or **TransientWithDismissOnPointerMoveAway** to open the flyout in its collapsed mode without taking focus. - -Text controls have a **SelectionFlyout** property. When you assign a flyout to this property, it is automatically shown when text is selected. - -### Show commands reactively - -When you show contextual commands reactively, as a context menu, the secondary commands are shown by default (the command bar flyout should be expanded). In this case, the command bar flyout might have both primary and secondary commands, or secondary commands only. - -To show commands in a context menu, you typically assign the flyout to the [ContextFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout) property of a UI element. This way, opening the flyout is handled by the element, and you don't need to do anything more. - -If you handle showing the flyout yourself (for example, on a [RightTapped](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.righttapped) event), set the flyout's [ShowMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.showmode) to **Standard** to open the flyout in its expanded mode and give it focus. - -> [!TIP] -> For more info about options when showing a flyout and how to control placement of the flyout, see [Flyouts](../../../design/controls/dialogs-and-flyouts/flyouts.md). - -### Show an always expanded CommandBarFlyout - -When you have primary and secondary commands in a CommandBarFlyout, the "see more" \[...\] button is displayed by default, and can be used to expand and collapse the secondary commands. If you'd like to keep your CommandBarFlyout in expanded mode and show the secondary commands at all times, you can use the `CommandBarFlyout.AlwaysExpanded` property. - -When the `AlwaysExpanded` property is set to `true`, the "see more" button is not shown, and the user is not able to toggle the expanded state of the control. The CommandBarFlyout will still dismiss as usual when a secondary command is clicked or the user clicks outside of the flyout. - -This property only has an effect if the CommandBarFlyout has secondary commands. If there are no secondary commands, the CommandBarFlyout will always be in collapsed mode. - -> [!TIP] -> You can still collapse and expand the CommandBarFlyout programmatically by setting the [IsOpen](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.isopen) property even when the `AlwaysExpanded` property is set to `true`. - -## Commands and content - -The CommandBarFlyout control has 2 properties you can use to add commands and content: [PrimaryCommands](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout.primarycommands) and [SecondaryCommands](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout.secondarycommands). - -By default, command bar items are added to the **PrimaryCommands** collection. These commands are shown in the command bar and are visible in both the collapsed and expanded modes. Unlike CommandBar, primary commands do not automatically overflow to the secondary commands and might be truncated. - -You can also add commands to the **SecondaryCommands** collection. Secondary commands are shown in the menu portion of the control and are visible only in the expanded mode. - -If there are **common commands** (such as Copy, Cut, Paste, Delete, Share or text selection commands) that are important to the scenario, it is recommended to add them as primary commands rather than secondary commands. - -### App bar buttons - -You can populate the PrimaryCommands and SecondaryCommands directly with [AppBarButton](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.AppBarButton), [AppBarToggleButton](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.AppBarToggleButton), and [AppBarSeparator](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.AppBarSeparator) controls. - -The app bar button controls are characterized by an icon and text label. These controls are optimized for use in a command bar, and their appearance changes depending on whether the control is shown in the command bar or the overflow menu. - -- **In Windows App SDK 1.5 and later:** App bar buttons used as primary commands are shown in the command bar with both the text label and icon (if both are set). - ```xaml - - ``` -- **In Windows App SDK 1.4 and earlier:** App bar buttons used as primary commands are shown in the command bar with only their icon; the text label is not shown. We recommend that you use a [tooltip](../../../design/controls/tooltips.md) to show a text description of the command, as shown here. - ```xaml - - ``` -- App bar buttons used as secondary commands are shown in the menu, with both the label and icon visible. - -## Icons - -Consider providing menu item icons for: - -- The most commonly used items. -- Menu items whose icon is standard or well known. -- Menu items whose icon well illustrates what the command does. - -Don't feel obligated to provide icons for commands that don't have a standard visualization. Cryptic icons aren't helpful, create visual clutter, and prevent users from focusing on the important menu items. - -### Other content - -You can add other controls to a command bar flyout by wrapping them in an AppBarElementContainer. This lets you add controls like [DropDownButton](../../../design/controls/buttons.md) or [SplitButton](../../../design/controls/buttons.md), or add containers like [StackPanel](../../../design/controls/buttons.md) to create more complex UI. - -In order to be added to the primary or secondary command collections of a command bar flyout, an element must implement the [ICommandBarElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.icommandbarelement) interface. [AppBarElementContainer](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarelementcontainer) is a wrapper that implements this interface so you can add an element to a command bar even if it doesn't implement the interface itself. - -Here, an AppBarElementContainer is used to add extra elements to a command bar flyout. A SplitButton is added to the primary commands to enable text alignment. A StackPanel is added to the secondary commands to allow a more complex layout for zoom controls. - -> [!TIP] -> By default, elements designed for the app canvas might not look right in a command bar. When you add an element using AppBarElementContainer, there are some steps you should take to make the element match other command bar elements: -> -> - Override the default brushes with [lightweight styling](../../platform/xaml/xaml-styles.md#lightweight-styling) to make the element's background and border match the app bar buttons. -> - Adjust the size and position of the element. -> - Wrap icons in a Viewbox with a Width and Height of 16px. - -> [!NOTE] -> This example shows only the command bar flyout UI, it does not implement any of the commands that are shown. For more info about implementing the commands, see [Buttons](../../../design/controls/buttons.md) and [Command design basics](../../../design/basics/commanding-basics.md). - -```xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -Here's the collapsed command bar flyout with an open SplitButton. - -![A command bar flyout with a split button](images/command-bar-flyout-split-button-1-5.png) - -Here's the expanded command bar flyout with custom zoom UI in the menu. - -![A command bar flyout with complex UI](images/command-bar-flyout-custom-ui-1-5.png) - -## Create a context menu with secondary commands only - -You can use a command bar flyout with only secondary commands to create a context menu that achieves the same look and behavior of [menu flyout](../../../design/controls/menus.md). - -```xaml - - - - - - - - - - - - - - - - -``` - -Here's the command bar flyout as a context menu. - -![A command bar flyout with only secondary commands](images/context-menu-example.png) - -You can also use a CommandBarFlyout with a DropDownButton to create a standard menu. - -```xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -Here's a drop down button menu in a command bar flyout. - -![A command bar flyout with as a drop down button menu](images/command-bar-flyout-dropdown.png) - -## Command bar flyouts for text controls - -The [TextCommandBarFlyout](/uwp/api/microsoft.ui.xaml.controls.textcommandbarflyout) is a specialized command bar flyout that contains commands for editing text. Each text control shows the TextCommandBarFlyout automatically as a context menu (right-click), or when text is selected. The text command bar flyout adapts to the text selection to only show relevant commands. - -Here's a text command bar flyout on text selection. - -![A collapsed text command bar flyout](images/command-bar-flyout-text-selection.png) - -Here's an expanded text command bar flyout that shows the secondary commands. - -![An expanded text command bar flyout](images/command-bar-flyout-text-full.png) - -### Available commands - -This table shows the commands that are included in a TextCommandBarFlyout, and when they are shown. - -| Command | Shown... | -| ------- | -------- | -| Bold | when the text control is not read-only (RichEditBox only). | -| Italic | when the text control is not read-only (RichEditBox only). | -| Underline | when the text control is not read-only (RichEditBox only). | -| Proofing | when IsSpellCheckEnabled is **true** and misspelled text is selected. | -| Cut | when the text control is not read-only and text is selected. | -| Copy | when text is selected. | -| Paste | when the text control is not read-only and the clipboard has content. | -| Undo | when there is an action that can be undone. | -| Select all | when text can be selected. | - -### Custom text command bar flyouts - -TextCommandBarFlyout can't be customized, and is managed automatically by each text control. However, you can replace the default TextCommandBarFlyout with custom commands. - -- To replace the default TextCommandBarFlyout that's shown on text selection, you can create a custom CommandBarFlyout (or other flyout type) and assign it to the **SelectionFlyout** property. If you set SelectionFlyout to **null**, no commands are shown on selection. -- To replace the default TextCommandBarFlyout that's shown as the context menu, assign a custom CommandBarFlyout (or other flyout type) to the **ContextFlyout** property on a text control. If you set ContextFlyout to **null**, the menu flyout shown in previous versions of the text control is shown instead of the TextCommandBarFlyout. - -### Light dismiss - -Light dismiss controls–such as menus, context menus, and other flyouts–trap keyboard and gamepad focus inside the transient UI until dismissed. To provide a visual cue for this behavior, light dismiss controls on Xbox will draw an overlay that dims the visibility of out of scope UI. This behavior can be modified with the [LightDismissOverlayMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.lightdismissoverlaymode) property. By default, transient UIs will draw the light dismiss overlay on Xbox (**Auto**) but not other device families. You can choose to force the overlay to be always **On** or always **Off**. - -```xaml - > -``` - -## Related articles - -- [Command design basics for Windows apps](../../../design/basics/commanding-basics.md) -- [Contextual commanding for collections and lists](../../../design/controls/collection-commanding.md). -- [Menus and context menus](../../../design/controls/menus-and-context-menus.md) -- [Command bar](../../../design/controls/command-bar.md) -- [CommandBar class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.CommandBar) -- [CommandBarFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout) +--- +description: Command bar flyouts give users inline access to your app's most common tasks. +title: Command bar flyout +label: Command bar flyout +template: detail.hbs +ms.date: 02/26/2025 +ms.topic: how-to +doc-status: Published +ms.localizationpriority: medium +ms.custom: RS5 +--- +# Command bar flyout + +The command bar flyout lets you provide users with easy access to common tasks by showing commands in a floating toolbar related to an element on your UI canvas. + +![An expanded text proofing command bar flyout](images/command-bar-flyout-text-full-1-5.png) + +Like [CommandBar](../../../design/controls/command-bar.md), CommandBarFlyout has **PrimaryCommands** and **SecondaryCommands** properties you can use to add commands. You can place commands in either collection, or both. When and how the primary and secondary commands are displayed depends on the display mode. + +The command bar flyout has two display modes: *collapsed* and *expanded*. + +- In the collapsed mode, only the primary commands are shown. If your command bar flyout has both primary and secondary commands, a "see more" button, which is represented by an ellipsis \[...\], is displayed. This lets the user get access to the secondary commands by transitioning to expanded mode. +- In the expanded mode, both the primary and secondary commands are shown. (If the control has only secondary items, they are shown in a way similar to the MenuFlyout control.) + +## Is this the right control? + +Use the command bar flyout control to show a collection of commands to the user, such as buttons and menu items, in the context of an element on the app canvas. + +Command bar flyout is the recommended control for creating [context menus](../../../design/controls/menus-and-context-menus.md). This allows the common commands (such as Copy, Cut, Paste, Delete, Share or text selection commands) that are most contextually relevant for the context menu's scenario to be added as primary commands so that they will be shown as a single, horizontal row in the command bar flyout. The TextCommandBarFlyout is already configured appropriately to automatically display text commands in TextBox, TextBlock, RichEditBox, RichTextBlock, and PasswordBox controls. A CommandBarFlyout can be used to replace the default text commands on text controls. + +To show contextual commands on list items follow the guidance in [Contextual commanding for collections and lists](../../../design/controls/collection-commanding.md). + +## Proactive vs. reactive invocation + +There are typically two ways to invoke a flyout or menu that's associated with an element on your UI canvas: _proactive invocation_ and _reactive invocation_. + +In proactive invocation, commands appear automatically when the user interacts with the item that the commands are associated with. For example, text formatting commands might pop up when the user selects text in a text box. In this case, the command bar flyout does not take focus. Instead, it presents relevant commands close to the item the user is interacting with. If the user doesn't interact with the commands, they are dismissed. + +In reactive invocation, commands are shown in response to an explicit user action to request the commands; for example, a right-click. This corresponds to the traditional concept of a [context menu](../../../design/controls/menus-and-context-menus.md). + +You can use the CommandBarFlyout in either way, or even a mixture of the two. + +## Create a command bar flyout + +> [!div class="checklist"] +> +> - **Important APIs:** [CommandBarFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout), [TextCommandBarFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textcommandbarflyout), [AppBarButton class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarbutton), [AppBarToggleButton class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbartogglebutton), [AppBarSeparator class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarseparator) + +> [!div class="nextstepaction"] +> [Open the WinUI 3 Gallery app and see the CommandBarFlyout in action](winui3gallery://item/CommandBarFlyout) + +[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] + +This example shows how to create a command bar flyout and use it both proactively and reactively. When the image is tapped, the flyout is shown in its collapsed mode. When shown as a context menu, the flyout is shown in its expanded mode. In either case, the user can expand or collapse the flyout after it's opened. + +```xaml + + + + + + + + + + + + + + + +``` + +```csharp +private void Image_Tapped(object sender, TappedRoutedEventArgs e) +{ + var flyout = FlyoutBase.GetAttachedFlyout((FrameworkElement)sender); + var options = new FlyoutShowOptions() + { + // Position shows the flyout next to the pointer. + // "Transient" ShowMode makes the flyout open in its collapsed state. + Position = e.GetPosition((FrameworkElement)sender), + ShowMode = FlyoutShowMode.Transient + }; + flyout?.ShowAt((FrameworkElement)sender, options); +} +``` + +Here's the command bar flyout in its collapsed state. + +![Example of a collapsed command bar flyout](images/command-bar-flyout-img-collapsed-1-5.png) + +Here's the same command bar flyout in its expanded state showing secondary commands. + +![Example of an expanded command bar flyout](images/command-bar-flyout-img-expanded-1-5.png) + +### Show commands proactively + +When you show contextual commands proactively, only the primary commands should be shown by default (the command bar flyout should be collapsed). Place the most important commands in the primary commands collection, and additional commands that would traditionally go in a context menu into the secondary commands collection. + +To proactively show commands, you typically handle the [Click](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.buttonbase.click) or [Tapped](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.tapped) event to show the command bar flyout. Set the flyout's [ShowMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.showmode) to **Transient** or **TransientWithDismissOnPointerMoveAway** to open the flyout in its collapsed mode without taking focus. + +Text controls have a **SelectionFlyout** property. When you assign a flyout to this property, it is automatically shown when text is selected. + +### Show commands reactively + +When you show contextual commands reactively, as a context menu, the secondary commands are shown by default (the command bar flyout should be expanded). In this case, the command bar flyout might have both primary and secondary commands, or secondary commands only. + +To show commands in a context menu, you typically assign the flyout to the [ContextFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout) property of a UI element. This way, opening the flyout is handled by the element, and you don't need to do anything more. + +If you handle showing the flyout yourself (for example, on a [RightTapped](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.righttapped) event), set the flyout's [ShowMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.showmode) to **Standard** to open the flyout in its expanded mode and give it focus. + +> [!TIP] +> For more info about options when showing a flyout and how to control placement of the flyout, see [Flyouts](../../../design/controls/dialogs-and-flyouts/flyouts.md). + +### Show an always expanded CommandBarFlyout + +When you have primary and secondary commands in a CommandBarFlyout, the "see more" \[...\] button is displayed by default, and can be used to expand and collapse the secondary commands. If you'd like to keep your CommandBarFlyout in expanded mode and show the secondary commands at all times, you can use the `CommandBarFlyout.AlwaysExpanded` property. + +When the `AlwaysExpanded` property is set to `true`, the "see more" button is not shown, and the user is not able to toggle the expanded state of the control. The CommandBarFlyout will still dismiss as usual when a secondary command is clicked or the user clicks outside of the flyout. + +This property only has an effect if the CommandBarFlyout has secondary commands. If there are no secondary commands, the CommandBarFlyout will always be in collapsed mode. + +> [!TIP] +> You can still collapse and expand the CommandBarFlyout programmatically by setting the [IsOpen](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.isopen) property even when the `AlwaysExpanded` property is set to `true`. + +## Commands and content + +The CommandBarFlyout control has 2 properties you can use to add commands and content: [PrimaryCommands](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout.primarycommands) and [SecondaryCommands](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout.secondarycommands). + +By default, command bar items are added to the **PrimaryCommands** collection. These commands are shown in the command bar and are visible in both the collapsed and expanded modes. Unlike CommandBar, primary commands do not automatically overflow to the secondary commands and might be truncated. + +You can also add commands to the **SecondaryCommands** collection. Secondary commands are shown in the menu portion of the control and are visible only in the expanded mode. + +If there are **common commands** (such as Copy, Cut, Paste, Delete, Share or text selection commands) that are important to the scenario, it is recommended to add them as primary commands rather than secondary commands. + +### App bar buttons + +You can populate the PrimaryCommands and SecondaryCommands directly with [AppBarButton](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.AppBarButton), [AppBarToggleButton](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.AppBarToggleButton), and [AppBarSeparator](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.AppBarSeparator) controls. + +The app bar button controls are characterized by an icon and text label. These controls are optimized for use in a command bar, and their appearance changes depending on whether the control is shown in the command bar or the overflow menu. + +- **In Windows App SDK 1.5 and later:** App bar buttons used as primary commands are shown in the command bar with both the text label and icon (if both are set). + ```xaml + + ``` +- **In Windows App SDK 1.4 and earlier:** App bar buttons used as primary commands are shown in the command bar with only their icon; the text label is not shown. We recommend that you use a [tooltip](../../../design/controls/tooltips.md) to show a text description of the command, as shown here. + ```xaml + + ``` +- App bar buttons used as secondary commands are shown in the menu, with both the label and icon visible. + +## Icons + +Consider providing menu item icons for: + +- The most commonly used items. +- Menu items whose icon is standard or well known. +- Menu items whose icon well illustrates what the command does. + +Don't feel obligated to provide icons for commands that don't have a standard visualization. Cryptic icons aren't helpful, create visual clutter, and prevent users from focusing on the important menu items. + +### Other content + +You can add other controls to a command bar flyout by wrapping them in an AppBarElementContainer. This lets you add controls like [DropDownButton](../../../design/controls/buttons.md) or [SplitButton](../../../design/controls/buttons.md), or add containers like [StackPanel](../../../design/controls/buttons.md) to create more complex UI. + +In order to be added to the primary or secondary command collections of a command bar flyout, an element must implement the [ICommandBarElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.icommandbarelement) interface. [AppBarElementContainer](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.appbarelementcontainer) is a wrapper that implements this interface so you can add an element to a command bar even if it doesn't implement the interface itself. + +Here, an AppBarElementContainer is used to add extra elements to a command bar flyout. A SplitButton is added to the primary commands to enable text alignment. A StackPanel is added to the secondary commands to allow a more complex layout for zoom controls. + +> [!TIP] +> By default, elements designed for the app canvas might not look right in a command bar. When you add an element using AppBarElementContainer, there are some steps you should take to make the element match other command bar elements: +> +> - Override the default brushes with [lightweight styling](../../platform/xaml/xaml-styles.md#lightweight-styling) to make the element's background and border match the app bar buttons. +> - Adjust the size and position of the element. +> - Wrap icons in a Viewbox with a Width and Height of 16px. + +> [!NOTE] +> This example shows only the command bar flyout UI, it does not implement any of the commands that are shown. For more info about implementing the commands, see [Buttons](../../../design/controls/buttons.md) and [Command design basics](../../../design/basics/commanding-basics.md). + +```xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +Here's the collapsed command bar flyout with an open SplitButton. + +![A command bar flyout with a split button](images/command-bar-flyout-split-button-1-5.png) + +Here's the expanded command bar flyout with custom zoom UI in the menu. + +![A command bar flyout with complex UI](images/command-bar-flyout-custom-ui-1-5.png) + +## Create a context menu with secondary commands only + +You can use a command bar flyout with only secondary commands to create a context menu that achieves the same look and behavior of [menu flyout](../../../design/controls/menus.md). + +```xaml + + + + + + + + + + + + + + + + +``` + +Here's the command bar flyout as a context menu. + +![A command bar flyout with only secondary commands](images/context-menu-example.png) + +You can also use a CommandBarFlyout with a DropDownButton to create a standard menu. + +```xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +Here's a drop down button menu in a command bar flyout. + +![A command bar flyout with as a drop down button menu](images/command-bar-flyout-dropdown.png) + +## Command bar flyouts for text controls + +The [TextCommandBarFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textcommandbarflyout) is a specialized command bar flyout that contains commands for editing text. Each text control shows the TextCommandBarFlyout automatically as a context menu (right-click), or when text is selected. The text command bar flyout adapts to the text selection to only show relevant commands. + +Here's a text command bar flyout on text selection. + +![A collapsed text command bar flyout](images/command-bar-flyout-text-selection.png) + +Here's an expanded text command bar flyout that shows the secondary commands. + +![An expanded text command bar flyout](images/command-bar-flyout-text-full.png) + +### Available commands + +This table shows the commands that are included in a TextCommandBarFlyout, and when they are shown. + +| Command | Shown... | +| ------- | -------- | +| Bold | when the text control is not read-only (RichEditBox only). | +| Italic | when the text control is not read-only (RichEditBox only). | +| Underline | when the text control is not read-only (RichEditBox only). | +| Proofing | when IsSpellCheckEnabled is **true** and misspelled text is selected. | +| Cut | when the text control is not read-only and text is selected. | +| Copy | when text is selected. | +| Paste | when the text control is not read-only and the clipboard has content. | +| Undo | when there is an action that can be undone. | +| Select all | when text can be selected. | + +### Custom text command bar flyouts + +TextCommandBarFlyout can't be customized, and is managed automatically by each text control. However, you can replace the default TextCommandBarFlyout with custom commands. + +- To replace the default TextCommandBarFlyout that's shown on text selection, you can create a custom CommandBarFlyout (or other flyout type) and assign it to the **SelectionFlyout** property. If you set SelectionFlyout to **null**, no commands are shown on selection. +- To replace the default TextCommandBarFlyout that's shown as the context menu, assign a custom CommandBarFlyout (or other flyout type) to the **ContextFlyout** property on a text control. If you set ContextFlyout to **null**, the menu flyout shown in previous versions of the text control is shown instead of the TextCommandBarFlyout. + +### Light dismiss + +Light dismiss controls–such as menus, context menus, and other flyouts–trap keyboard and gamepad focus inside the transient UI until dismissed. To provide a visual cue for this behavior, light dismiss controls on Xbox will draw an overlay that dims the visibility of out of scope UI. This behavior can be modified with the [LightDismissOverlayMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.lightdismissoverlaymode) property. By default, transient UIs will draw the light dismiss overlay on Xbox (**Auto**) but not other device families. You can choose to force the overlay to be always **On** or always **Off**. + +```xaml + > +``` + +## Related articles + +- [Command design basics for Windows apps](../../../design/basics/commanding-basics.md) +- [Contextual commanding for collections and lists](../../../design/controls/collection-commanding.md). +- [Menus and context menus](../../../design/controls/menus-and-context-menus.md) +- [Command bar](../../../design/controls/command-bar.md) +- [CommandBar class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.CommandBar) +- [CommandBarFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.commandbarflyout) diff --git a/hub/apps/develop/ui/controls/menus.md b/hub/apps/develop/ui/controls/menus.md index 9052eaa1a2..8226b4dcfd 100644 --- a/hub/apps/develop/ui/controls/menus.md +++ b/hub/apps/develop/ui/controls/menus.md @@ -1,217 +1,217 @@ ---- -description: Menus and context menus display a list of commands or options when the user requests them. -title: Menu flyout and menu bar -label: Menu flyout and menu bar -template: detail.hbs -ms.date: 02/26/2025 -ms.topic: article -ms.custom: RS5, 19H1 -ms.assetid: 0327d8c1-8329-4be2-84e3-66e1e9a0aa60 -doc-status: Published -ms.localizationpriority: medium ---- -# Menu flyout and menu bar - -Menu flyouts are used in menu and context menu scenarios to display a list of commands or options when requested by the user. A menu flyout shows a single, inline, top-level menu that can have menu items and sub-menus. To show a set of multiple top-level menus in a horizontal row, use menu bar (which you typically position at the top of the app window). - -![Example of a typical context menu](images/contextmenu_rs2_icons.png) - -## Is this the right control? - -See [menus and context menus](../../../design/controls/menus-and-context-menus.md) for help identifying menu vs. context menu scenarios and guidance on when to use menu flyout vs. [command bar flyout](../../../design/controls/command-bar-flyout.md). - -Menu flyouts can be used as menus and context menus to organize commands. To display arbitrary content, such as a notification or confirmation request, use a [dialog or a flyout](../../../design/controls/dialogs-and-flyouts/index.md). - -If a particular command will be used frequently and you have the space available, see [collection commanding](../../../design/controls/collection-commanding.md) for examples on placing a command directly in its own element so that users don't have to go through a menu to get to it. - -## Create a menu flyout - -> [!div class="checklist"] -> -> - **Important APIs:** [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout), [ContextFlyout property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout), [FlyoutBase.AttachedFlyout property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.attachedflyout) - -> [!div class="nextstepaction"] -> [Open the WinUI 3 Gallery app and see MenuFlyout in action](winui3gallery://item/MenuFlyout) - -[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] - -To create a menu flyout, you use the [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout). You define the contents of the menu by adding [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem), [MenuFlyoutSubItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem), [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem), [RadioMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem) and [MenuFlyoutSeparator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator) objects to the MenuFlyout. - -These objects are for: - -- [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem)—Performing an immediate action. -- [MenuFlyoutSubItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem)—Containing a cascading list of menu items. -- [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem)—Switching an option on or off. -- [RadioMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem)—Switching between mutually-exclusive menu items. -- [MenuFlyoutSeparator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator)—Visually separating menu items. - -This example creates a [MenuFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout) and uses the [ContextFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout) property, a property available to most controls, to show the MenuFlyout as a context menu. - -````xaml - - - - - - - - - - -```` - -````csharp -private void ChangeColorItem_Click(object sender, RoutedEventArgs e) -{ - // Change the color from red to blue or blue to red. - if (rectangleFill.Color == Windows.UI.Colors.Red) - { - rectangleFill.Color = Windows.UI.Colors.Blue; - } - else - { - rectangleFill.Color = Windows.UI.Colors.Red; - } -} -```` - -The next example is nearly identical, but instead of using the [ContextFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout) property to show the [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout) as a context menu, the example uses the [FlyoutBase.ShowAttachedFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.showattachedflyout) property to show it as a menu. - -````xaml - - - - - - - - - - -```` - -````csharp -private void Rectangle_Tapped(object sender, TappedRoutedEventArgs e) -{ - FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender); -} - -private void ChangeColorItem_Click(object sender, RoutedEventArgs e) -{ - // Change the color from red to blue or blue to red. - if (rectangleFill.Color == Windows.UI.Colors.Red) - { - rectangleFill.Color = Windows.UI.Colors.Blue; - } - else - { - rectangleFill.Color = Windows.UI.Colors.Red; - } -} -```` - -## Icons - -Consider providing menu item icons for: - -- The most commonly used items. -- Menu items whose icon is standard or well known. -- Menu items whose icon well illustrates what the command does. - -Don't feel obligated to provide icons for commands that don't have a standard visualization. Cryptic icons aren't helpful, create visual clutter, and prevent users from focusing on the important menu items. - -![Example context menu with icons](images/contextmenu_rs2_icons.png) - -````xaml - - - - - - - - - - - - -```` - -> [!TIP] -> The size of the icon in a MenuFlyoutItem is 16x16px. If you use SymbolIcon, FontIcon, or PathIcon, the icon automatically scales to the correct size with no loss of fidelity. If you use BitmapIcon, ensure that your asset is 16x16px. - - -### Light dismiss - -Light dismiss controls such as menus, context menus, and other flyouts, trap keyboard and gamepad focus inside the transient UI until dismissed. To provide a visual cue for this behavior, light dismiss controls on Xbox will draw an overlay that dims the visibility of out of scope UI. This behavior can be modified with the [LightDismissOverlayMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.lightdismissoverlaymode) property. By default, transient UIs will draw the light dismiss overlay on Xbox (**Auto**) but not other device families. You can choose to force the overlay to be always **On** or always **Off**. - -```xaml - -``` - -## Create a menu bar - -> [!div class="checklist"] -> -> - **Important APIs:** [MenuBar class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menubar). [MenuBarItem class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menubaritem) - -> [!div class="nextstepaction"] -> [Open the WinUI 3 Gallery app and see MenuBar in action](winui3gallery://item/MenuBar) - -[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] - -You use the same elements to create menus in a menu bar as in a menu flyout. However, instead of grouping MenuFlyoutItem objects in a MenuFlyout, you group them in a MenuBarItem element. Each MenuBarItem is added to the MenuBar as a top level menu. - -![Example of a menu bar](images/menu-bar-submenu.png) - -> [!NOTE] -> This example shows only how to create the UI structure, but does not show implementation of any of the commands. - -```xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -## Related articles - -- [Command design basics for Windows apps](../../../design/basics/commanding-basics.md) -- [Menus and context menus](../../../design/controls/menus-and-context-menus.md) -- [Contextual commanding for collections and lists](../../../design/controls/collection-commanding.md) -- [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout) -- [MenuBar class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menubar) +--- +description: Menus and context menus display a list of commands or options when the user requests them. +title: Menu flyout and menu bar +label: Menu flyout and menu bar +template: detail.hbs +ms.date: 02/26/2025 +ms.topic: article +ms.custom: RS5, 19H1 +ms.assetid: 0327d8c1-8329-4be2-84e3-66e1e9a0aa60 +doc-status: Published +ms.localizationpriority: medium +--- +# Menu flyout and menu bar + +Menu flyouts are used in menu and context menu scenarios to display a list of commands or options when requested by the user. A menu flyout shows a single, inline, top-level menu that can have menu items and sub-menus. To show a set of multiple top-level menus in a horizontal row, use menu bar (which you typically position at the top of the app window). + +![Example of a typical context menu](images/contextmenu_rs2_icons.png) + +## Is this the right control? + +See [menus and context menus](../../../design/controls/menus-and-context-menus.md) for help identifying menu vs. context menu scenarios and guidance on when to use menu flyout vs. [command bar flyout](../../../design/controls/command-bar-flyout.md). + +Menu flyouts can be used as menus and context menus to organize commands. To display arbitrary content, such as a notification or confirmation request, use a [dialog or a flyout](../../../design/controls/dialogs-and-flyouts/index.md). + +If a particular command will be used frequently and you have the space available, see [collection commanding](../../../design/controls/collection-commanding.md) for examples on placing a command directly in its own element so that users don't have to go through a menu to get to it. + +## Create a menu flyout + +> [!div class="checklist"] +> +> - **Important APIs:** [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout), [ContextFlyout property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout), [FlyoutBase.AttachedFlyout property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.attachedflyout) + +> [!div class="nextstepaction"] +> [Open the WinUI 3 Gallery app and see MenuFlyout in action](winui3gallery://item/MenuFlyout) + +[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] + +To create a menu flyout, you use the [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout). You define the contents of the menu by adding [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem), [MenuFlyoutSubItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem), [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem), [RadioMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem) and [MenuFlyoutSeparator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator) objects to the MenuFlyout. + +These objects are for: + +- [MenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutitem)—Performing an immediate action. +- [MenuFlyoutSubItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutsubitem)—Containing a cascading list of menu items. +- [ToggleMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.togglemenuflyoutitem)—Switching an option on or off. +- [RadioMenuFlyoutItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.radiomenuflyoutitem)—Switching between mutually-exclusive menu items. +- [MenuFlyoutSeparator](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyoutseparator)—Visually separating menu items. + +This example creates a [MenuFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout) and uses the [ContextFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout) property, a property available to most controls, to show the MenuFlyout as a context menu. + +````xaml + + + + + + + + + + +```` + +````csharp +private void ChangeColorItem_Click(object sender, RoutedEventArgs e) +{ + // Change the color from red to blue or blue to red. + if (rectangleFill.Color == Microsoft.UI.Colors.Red) + { + rectangleFill.Color = Microsoft.UI.Colors.Blue; + } + else + { + rectangleFill.Color = Microsoft.UI.Colors.Red; + } +} +```` + +The next example is nearly identical, but instead of using the [ContextFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.contextflyout) property to show the [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout) as a context menu, the example uses the [FlyoutBase.ShowAttachedFlyout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.showattachedflyout) property to show it as a menu. + +````xaml + + + + + + + + + + +```` + +````csharp +private void Rectangle_Tapped(object sender, TappedRoutedEventArgs e) +{ + FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender); +} + +private void ChangeColorItem_Click(object sender, RoutedEventArgs e) +{ + // Change the color from red to blue or blue to red. + if (rectangleFill.Color == Microsoft.UI.Colors.Red) + { + rectangleFill.Color = Microsoft.UI.Colors.Blue; + } + else + { + rectangleFill.Color = Microsoft.UI.Colors.Red; + } +} +```` + +## Icons + +Consider providing menu item icons for: + +- The most commonly used items. +- Menu items whose icon is standard or well known. +- Menu items whose icon well illustrates what the command does. + +Don't feel obligated to provide icons for commands that don't have a standard visualization. Cryptic icons aren't helpful, create visual clutter, and prevent users from focusing on the important menu items. + +![Example context menu with icons](images/contextmenu_rs2_icons.png) + +````xaml + + + + + + + + + + + + +```` + +> [!TIP] +> The size of the icon in a MenuFlyoutItem is 16x16px. If you use SymbolIcon, FontIcon, or PathIcon, the icon automatically scales to the correct size with no loss of fidelity. If you use BitmapIcon, ensure that your asset is 16x16px. + + +### Light dismiss + +Light dismiss controls such as menus, context menus, and other flyouts, trap keyboard and gamepad focus inside the transient UI until dismissed. To provide a visual cue for this behavior, light dismiss controls on Xbox will draw an overlay that dims the visibility of out of scope UI. This behavior can be modified with the [LightDismissOverlayMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.flyoutbase.lightdismissoverlaymode) property. By default, transient UIs will draw the light dismiss overlay on Xbox (**Auto**) but not other device families. You can choose to force the overlay to be always **On** or always **Off**. + +```xaml + +``` + +## Create a menu bar + +> [!div class="checklist"] +> +> - **Important APIs:** [MenuBar class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menubar). [MenuBarItem class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menubaritem) + +> [!div class="nextstepaction"] +> [Open the WinUI 3 Gallery app and see MenuBar in action](winui3gallery://item/MenuBar) + +[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] + +You use the same elements to create menus in a menu bar as in a menu flyout. However, instead of grouping MenuFlyoutItem objects in a MenuFlyout, you group them in a MenuBarItem element. Each MenuBarItem is added to the MenuBar as a top level menu. + +![Example of a menu bar](images/menu-bar-submenu.png) + +> [!NOTE] +> This example shows only how to create the UI structure, but does not show implementation of any of the commands. + +```xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +## Related articles + +- [Command design basics for Windows apps](../../../design/basics/commanding-basics.md) +- [Menus and context menus](../../../design/controls/menus-and-context-menus.md) +- [Contextual commanding for collections and lists](../../../design/controls/collection-commanding.md) +- [MenuFlyout class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menuflyout) +- [MenuBar class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.menubar) diff --git a/hub/apps/develop/ui/controls/navigationview.md b/hub/apps/develop/ui/controls/navigationview.md index 8481ff7b6b..b13f71c088 100644 --- a/hub/apps/develop/ui/controls/navigationview.md +++ b/hub/apps/develop/ui/controls/navigationview.md @@ -403,7 +403,7 @@ You can hide or disable the back button by setting these properties: This example shows how you can use NavigationView with both a top navigation pane on large window sizes and a left navigation pane on small window sizes. It can be adapted to left-only navigation by removing the *top* navigation settings in the VisualStateManager. -The example demonstrates a common way to set up navigation data that will work for many scenarios. In this example, you first store (in the tag of the [NavigationViewItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationviewitem)) the full type name of the page to which you want to navigate. In the event handler, you unbox that value, turn it into a [Type]()(C#) or [**Windows::UI::Xaml::Interop::TypeName**](/uwp/api/windows.ui.xaml.interop.typename)(C++/WinRT) object, and use that to navigate to the destination page. This lets you create unit tests to confirm that the values inside your tags are of a valid type. (Also see [Boxing and unboxing values to IInspectable with C++/WinRT](/windows/uwp/cpp-and-winrt-apis/boxing)). It also demonstrates how to implement backwards navigation with NavigationView's back button. +The example demonstrates a common way to set up navigation data that will work for many scenarios. In this example, you first store (in the tag of the [NavigationViewItem](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationviewitem)) the full type name of the page to which you want to navigate. In the event handler, you unbox that value, turn it into a [Type]()(C#) or [**Windows::UI::Xaml::Interop::TypeName**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.interop.typename)(C++/WinRT) object, and use that to navigate to the destination page. This lets you create unit tests to confirm that the values inside your tags are of a valid type. (Also see [Boxing and unboxing values to IInspectable with C++/WinRT](/windows/uwp/cpp-and-winrt-apis/boxing)). It also demonstrates how to implement backwards navigation with NavigationView's back button. This code assumes that your app contains pages with the following names to navigate to: *HomePage*, *AppsPage*, *GamesPage*, *MusicPage*, *MyContentPage*, and *SettingsPage*. Code for these pages is not shown. @@ -635,7 +635,7 @@ namespace winrt::NavigationViewDemo::implementation muxc::NavigationView const& /* sender */, muxc::NavigationViewSelectionChangedEventArgs const& args); void NavView_Navigate( - Windows::UI::Xaml::Interop::TypeName navPageType, + Microsoft::UI::Xaml::Interop::TypeName navPageType, Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo); void NavView_BackRequested( muxc::NavigationView const& /* sender */, @@ -722,9 +722,9 @@ namespace winrt::NavigationViewDemo::implementation } else if (args.InvokedItemContainer()) { - Windows::UI::Xaml::Interop::TypeName pageTypeName; + Microsoft::UI::Xaml::Interop::TypeName pageTypeName; pageTypeName.Name = unbox_value(args.InvokedItemContainer().Tag()); - pageTypeName.Kind = Windows::UI::Xaml::Interop::TypeKind::Primitive; + pageTypeName.Kind = Microsoft::UI::Xaml::Interop::TypeKind::Primitive; NavView_Navigate(pageTypeName, args.RecommendedNavigationTransitionInfo()); } } @@ -743,20 +743,20 @@ namespace winrt::NavigationViewDemo::implementation } else if (args.SelectedItemContainer()) { - Windows::UI::Xaml::Interop::TypeName pageTypeName; + Microsoft::UI::Xaml::Interop::TypeName pageTypeName; pageTypeName.Name = unbox_value(args.SelectedItemContainer().Tag()); - pageTypeName.Kind = Windows::UI::Xaml::Interop::TypeKind::Primitive; + pageTypeName.Kind = Microsoft::UI::Xaml::Interop::TypeKind::Primitive; NavView_Navigate(pageTypeName, args.RecommendedNavigationTransitionInfo()); } } void MainPage::NavView_Navigate( - Windows::UI::Xaml::Interop::TypeName navPageType, + Microsoft::UI::Xaml::Interop::TypeName navPageType, Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo) { // Get the page type before navigation so you can prevent duplicate // entries in the backstack. - Windows::UI::Xaml::Interop::TypeName preNavPageType = + Microsoft::UI::Xaml::Interop::TypeName preNavPageType = ContentFrame().CurrentSourcePageType(); // Navigate only if the selected page isn't currently loaded. diff --git a/hub/apps/develop/ui/controls/person-picture.md b/hub/apps/develop/ui/controls/person-picture.md index 0e8e67fac6..503c007cbf 100644 --- a/hub/apps/develop/ui/controls/person-picture.md +++ b/hub/apps/develop/ui/controls/person-picture.md @@ -1,160 +1,160 @@ ---- -description: Displays the avatar image for a person, if one is available; if not, it displays the person's initials or a generic glyph. -title: Person picture control -template: detail.hbs -label: Person picture -ms.date: 02/26/2025 -ms.topic: article -doc-status: Published -ms.localizationpriority: medium ---- -# Person picture control - -The person picture control displays the avatar image for a person, if one is available; if not, it displays the person's initials or a generic glyph. You can use the control to display a [Contact object](/uwp/api/Windows.ApplicationModel.Contacts.Contact), an object that manages a person's contact info, or you can manually provide contact information, such as a display name and profile picture. - - Here are two person picture controls accompanied by two [text block](../../../design/controls/text-block.md) elements that display the users' names. - -![Screenshot of the person picture control.](images/person-picture/person-picture_hero.png) - -## Is this the right control? - -Use the person picture when you want to represent a person and their contact information. Here are some examples of when you might use the control: - -* To display the current user -* To display contacts in an address book -* To display the sender of a message -* To display a social media contact - -The illustration shows the person picture control in a list of contacts: -![Screenshot that shows the Person Picture control in a list of contacts.](images/person-picture/person-picture-control.png) - -## Create a person picture - -> [!div class="checklist"] -> -> - **Important APIs:** [PersonPicture class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.personpicture) - -> [!div class="nextstepaction"] -> [Open the WinUI 3 Gallery app and see PersonPicture in action](winui3gallery://item/PersonPicture) - -[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] - -To create a person picture, you use the PersonPicture class. This example creates a PersonPicture control and manually provides the person's display name, profile picture, and initials: - -```xaml - -``` - -## Using the person picture control to display a Contact object - -You can use the person picture control to display a [Contact](/uwp/api/Windows.ApplicationModel.Contacts.Contact) object: - -```xaml - - - - - - - - - -``` - -```csharp -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Windows.Foundation; -using Windows.Foundation.Collections; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; -using Windows.UI.Xaml.Data; -using Windows.UI.Xaml.Input; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Navigation; -using Windows.ApplicationModel.Contacts; - -namespace SampleApp -{ - public sealed partial class PersonPictureContactExample : Page, System.ComponentModel.INotifyPropertyChanged - { - public PersonPictureContactExample() - { - this.InitializeComponent(); - } - - private Windows.ApplicationModel.Contacts.Contact _currentContact; - public Windows.ApplicationModel.Contacts.Contact CurrentContact - { - get => _currentContact; - set - { - _currentContact = value; - PropertyChanged?.Invoke(this, - new System.ComponentModel.PropertyChangedEventArgs(nameof(CurrentContact))); - } - - } - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - - public static async System.Threading.Tasks.Task CreateContact() - { - - var contact = new Windows.ApplicationModel.Contacts.Contact(); - contact.FirstName = "Betsy"; - contact.LastName = "Sherman"; - - // Get the app folder where the images are stored. - var appInstalledFolder = - Windows.ApplicationModel.Package.Current.InstalledLocation; - var assets = await appInstalledFolder.GetFolderAsync("Assets"); - var imageFile = await assets.GetFileAsync("betsy.png"); - contact.SourceDisplayPicture = imageFile; - - return contact; - } - - private async void LoadContactButton_Click(object sender, RoutedEventArgs e) - { - CurrentContact = await CreateContact(); - } - } -} -``` - -> [!NOTE] -> To keep the code simple, this example creates a new Contact object. In a real app, you'd let the user select a contact or you'd use a [ContactManager](/uwp/api/Windows.ApplicationModel.Contacts.ContactManager) to query for a list of contacts. For info on retrieving and managing contacts, see the [Contacts and calendar articles](/windows/uwp/contacts-and-calendar/index). - -## Determining which info to display - -When you provide a [Contact](/uwp/api/Windows.ApplicationModel.Contacts.Contact) object, the person picture control evaluates it to determine which info it can display. - -If an image is available, the control displays the first image it finds, in this order: - -1. LargeDisplayPicture -1. SmallDisplayPicture -1. Thumbnail - -You can change which image is chosen by setting the PreferSmallImage property to true; this gives the SmallDisplayPicture a higher priority than LargeDisplayPicture. - -If there isn't an image, the control displays the contact's name or initials; if there's isn't any name data, the control displays contact data, such as an email address or phone number. - -## Related articles - -* [Contacts and calendar](/windows/uwp/contacts-and-calendar/index) +--- +description: Displays the avatar image for a person, if one is available; if not, it displays the person's initials or a generic glyph. +title: Person picture control +template: detail.hbs +label: Person picture +ms.date: 02/26/2025 +ms.topic: article +doc-status: Published +ms.localizationpriority: medium +--- +# Person picture control + +The person picture control displays the avatar image for a person, if one is available; if not, it displays the person's initials or a generic glyph. You can use the control to display a [Contact object](/uwp/api/Windows.ApplicationModel.Contacts.Contact), an object that manages a person's contact info, or you can manually provide contact information, such as a display name and profile picture. + + Here are two person picture controls accompanied by two [text block](../../../design/controls/text-block.md) elements that display the users' names. + +![Screenshot of the person picture control.](images/person-picture/person-picture_hero.png) + +## Is this the right control? + +Use the person picture when you want to represent a person and their contact information. Here are some examples of when you might use the control: + +* To display the current user +* To display contacts in an address book +* To display the sender of a message +* To display a social media contact + +The illustration shows the person picture control in a list of contacts: +![Screenshot that shows the Person Picture control in a list of contacts.](images/person-picture/person-picture-control.png) + +## Create a person picture + +> [!div class="checklist"] +> +> - **Important APIs:** [PersonPicture class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.personpicture) + +> [!div class="nextstepaction"] +> [Open the WinUI 3 Gallery app and see PersonPicture in action](winui3gallery://item/PersonPicture) + +[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] + +To create a person picture, you use the PersonPicture class. This example creates a PersonPicture control and manually provides the person's display name, profile picture, and initials: + +```xaml + +``` + +## Using the person picture control to display a Contact object + +You can use the person picture control to display a [Contact](/uwp/api/Windows.ApplicationModel.Contacts.Contact) object: + +```xaml + + + + + + + + + +``` + +```csharp +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Windows.Foundation; +using Windows.Foundation.Collections; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Navigation; +using Windows.ApplicationModel.Contacts; + +namespace SampleApp +{ + public sealed partial class PersonPictureContactExample : Page, System.ComponentModel.INotifyPropertyChanged + { + public PersonPictureContactExample() + { + this.InitializeComponent(); + } + + private Windows.ApplicationModel.Contacts.Contact _currentContact; + public Windows.ApplicationModel.Contacts.Contact CurrentContact + { + get => _currentContact; + set + { + _currentContact = value; + PropertyChanged?.Invoke(this, + new System.ComponentModel.PropertyChangedEventArgs(nameof(CurrentContact))); + } + + } + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + public static async System.Threading.Tasks.Task CreateContact() + { + + var contact = new Windows.ApplicationModel.Contacts.Contact(); + contact.FirstName = "Betsy"; + contact.LastName = "Sherman"; + + // Get the app folder where the images are stored. + var appInstalledFolder = + Windows.ApplicationModel.Package.Current.InstalledLocation; + var assets = await appInstalledFolder.GetFolderAsync("Assets"); + var imageFile = await assets.GetFileAsync("betsy.png"); + contact.SourceDisplayPicture = imageFile; + + return contact; + } + + private async void LoadContactButton_Click(object sender, RoutedEventArgs e) + { + CurrentContact = await CreateContact(); + } + } +} +``` + +> [!NOTE] +> To keep the code simple, this example creates a new Contact object. In a real app, you'd let the user select a contact or you'd use a [ContactManager](/uwp/api/Windows.ApplicationModel.Contacts.ContactManager) to query for a list of contacts. For info on retrieving and managing contacts, see the [Contacts and calendar articles](/windows/uwp/contacts-and-calendar/index). + +## Determining which info to display + +When you provide a [Contact](/uwp/api/Windows.ApplicationModel.Contacts.Contact) object, the person picture control evaluates it to determine which info it can display. + +If an image is available, the control displays the first image it finds, in this order: + +1. LargeDisplayPicture +1. SmallDisplayPicture +1. Thumbnail + +You can change which image is chosen by setting the PreferSmallImage property to true; this gives the SmallDisplayPicture a higher priority than LargeDisplayPicture. + +If there isn't an image, the control displays the contact's name or initials; if there's isn't any name data, the control displays contact data, such as an email address or phone number. + +## Related articles + +* [Contacts and calendar](/windows/uwp/contacts-and-calendar/index) * [Contact cards sample](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/ContactCards) \ No newline at end of file diff --git a/hub/apps/develop/ui/controls/text-box.md b/hub/apps/develop/ui/controls/text-box.md index 390e0ba438..b44a79cba5 100644 --- a/hub/apps/develop/ui/controls/text-box.md +++ b/hub/apps/develop/ui/controls/text-box.md @@ -1,304 +1,304 @@ ---- -ms.assetid: CC1BF51D-3DAC-4198-ADCB-1770B901C2FC -description: The TextBox control lets a user enter text into an app. -title: Text box -label: Text box -template: detail.hbs -ms.date: 02/26/2025 -ms.topic: article -keywords: windows 10, uwp -pm-contact: miguelrb -design-contact: ksulliv -doc-status: Published -ms.localizationpriority: medium ---- -# Text box - -The TextBox control lets a user type text into an app. It's typically used to capture a single line of text, but can be configured to capture multiple lines of text. The text displays on the screen in a simple, uniform, plaintext format. - -![A text box](images/text-box.png) - -TextBox has a number of features that can simplify text entry. It comes with a familiar, built-in context menu with support for copying and pasting text. The "clear all" button lets a user quickly delete all text that has been entered. It also has spell checking capabilities built in and enabled by default. - -## Is this the right control? - -Use a **TextBox** control to let a user enter and edit unformatted text, such as in a form. You can use the [Text](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.text) property to get and set the text in a TextBox. - -You can make a TextBox read-only, but this should be a temporary, conditional state. If the text is never editable, consider using a [TextBlock](../../../design/controls/text-block.md) instead. - -Use a [PasswordBox](../../../design/controls/password-box.md) control to collect a password or other private data, such as a Social Security number. A password box looks like a text input box, except that it renders bullets in place of the text that has been entered. - -Use an [AutoSuggestBox](../../../design/controls/auto-suggest-box.md) control to let the user enter search terms or to show the user a list of suggestions to choose from as they type. - -Use a [RichEditBox](../../../design/controls/rich-edit-box.md) to display and edit rich text files. - -For more info about choosing the right text control, see the [Text controls](../../../design/controls/text-controls.md) article. - -## Recommendations - -- Use a label or placeholder text if the purpose of the text box isn't clear. A label is visible whether or not the text input box has a value. Placeholder text is displayed inside the text input box and disappears once a value has been entered. -- Give the text box an appropriate width for the range of values that can be entered. Word length varies between languages, so take localization into account if you want your app to be world-ready. -- A text input box is typically single-line (`TextWrap = "NoWrap"`). When users need to enter or edit a long string, set the text input box to multi-line (`TextWrap = "Wrap"`). -- Generally, a text input box is used for editable text. But you can make a text input box read-only so that its content can be read, selected, and copied, but not edited. -- If you need to reduce clutter in a view, consider making a set of text input boxes appear only when a controlling checkbox is checked. You can also bind the enabled state of a text input box to a control such as a checkbox. -- Consider how you want a text input box to behave when it contains a value and the user taps it. The default behavior is appropriate for editing the value rather than replacing it; the insertion point is placed between words and nothing is selected. If replacing is the most common use case for a given text input box, you can select all the text in the field whenever the control receives focus, and typing replaces the selection. - -### Single-line input boxes - -- Use several single-line text boxes to capture many small pieces of text information. If the text boxes are related in nature, group those together. - -- Make the size of single-line text boxes slightly wider than the longest anticipated input. If doing so makes the control too wide, separate it into two controls. For example, you could split a single address input into "Address line 1" and "Address line 2". -- Set a maximum length for characters that can be entered. If the backing data source doesn't allow a long input string, limit the input and use a validation popup to let users know when they reach the limit. -- Use single-line text input controls to gather small pieces of text from users. - - The following example shows a single-line text box to capture an answer to a security question. The answer is expected to be short, and so a single-line text box is appropriate here. - - ![Basic data input](images/single-line-text-input-type-text.png) - -- Use a set of short, fixed-sized, single-line text input controls to enter data with a specific format. - - ![Formatted data input](images/textinput-example-productkey.png) - -- Use a single-line, unconstrained text input control to enter or edit strings, combined with a command button that helps users select valid values. - - ![Assisted data input](images/textinput-example-assisted.png) - -### Multi-line text input controls - -- When you create a rich text box, provide styling buttons and implement their actions. -- Use a font that's consistent with the style of your app. -- Make the height of the text control tall enough to accommodate typical entries. -- When capturing long spans of text with a maximum character or word count, use a plain text box and provide a live-running counter to show the user how many characters or words they have left before they reach the limit. You'll need to create the counter yourself; place it below the text box and dynamically update it as the user enters each character or word. - - ![A long span of text](images/multi-line-text-input-text-limits.png) - -- Don't let your text input controls grow in height while users type. -- Don't use a multi-line text box when users only need a single line. -- Don't use a rich text control if a plain text control is adequate. - -## Create a text box - -> [!div class="checklist"] -> -> - **Important APIs:** [TextBox class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.TextBox), [Text property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.text) - -> [!div class="nextstepaction"] -> [Open the WinUI 3 Gallery app and see the TextBox in action](winui3gallery://item/TextBox) - -[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] - -Here's the XAML for a simple text box with a header and placeholder text. - -```xaml - -``` - -```csharp -TextBox textBox = new TextBox(); -textBox.Width = 300; -textBox.Header = "Notes"; -textBox.PlaceholderText = "Type your notes here"; -// Add the TextBox to the visual tree. -rootGrid.Children.Add(textBox); -``` - -Here's the text box that results from this XAML. - -![A simple text box](images/text-box-ex1.png) - -### Use a text box for data input in a form - -It's common to use a text box to accept data input on a form, and use the [Text](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.text) property to get the complete text string from the text box. You typically use an event like a submit button click to access the Text property, but you can handle the [TextChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textchanged) or [TextChanging](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textchanging) event if you need to do something when the text changes. - -This example shows how to get and set the current content of a text box. - -```xaml - -``` - -```csharp -string sampleText = SampleTextBox.Text; -... -SampleTextBox.Text = "Sample text retrieved"; -``` - -You can add a [Header](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.header) (or label) and [PlaceholderText](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.placeholdertext) (or watermark) to the text box to give the user an indication of what the text box is for. To customize the look of the header, you can set the [HeaderTemplate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.headertemplate) property instead of Header. *For design info, see Guidelines for labels*. - -You can restrict the number of characters the user can type by setting the [MaxLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.maxlength) property. However, MaxLength does not restrict the length of pasted text. Use the [Paste](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.paste) event to modify pasted text if this is important for your app. - -The text box includes a clear all button ("X") that appears when text is entered in the box. When a user clicks the "X", the text in the text box is cleared. It looks like this. - -![A text box with a clear all button](images/text-box-clear-all.png) - -The clear all button is shown only for editable, single-line text boxes that contain text and have focus. - -The clear all button is not shown in any of these cases: - -- **IsReadOnly** is **true** -- **AcceptsReturn** is **true** -- **TextWrap** has a value other than **NoWrap** - -This example shows how to get and set the current content of a text box. - -```xaml - -``` - -```csharp -string sampleText = SampleTextBox.Text; -... -SampleTextBox.Text = "Sample text retrieved"; -``` - - -### Make a text box read-only - -You can make a text box read-only by setting the [IsReadOnly](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.isreadonly) property to **true**. You typically toggle this property in your app code based on conditions in your app. If need text that is always read-only, consider using a TextBlock instead. - -You can make a TextBox read-only by setting the IsReadOnly property to true. For example, you might have a TextBox for a user to enter comments that is enabled only under certain conditions. You can make the TextBox read-only until the conditions are met. If you need only to display text, consider using a TextBlock or RichTextBlock instead. - -A read-only text box looks the same as a read/write text box, so it might be confusing to a user. -A user can select and copy text. -IsEnabled - -### Enable multi-line input - -There are two properties that you can use to control whether the text box displays text on more than one line. You typically set both properties to make a multi-line text box. - -- To let the text box allow and display the newline or return characters, set the [AcceptsReturn](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.acceptsreturn) property to **true**. -- To enable text wrapping, set the [TextWrapping](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textwrapping) property to **Wrap**. This causes the text to wrap when it reaches the edge of the text box, independent of line separator characters. - -> [!NOTE] -> TextBox and RichEditBox don't support the **WrapWholeWords** value for their TextWrapping properties. If you try to use WrapWholeWords as a value for TextBox.TextWrapping or RichEditBox.TextWrapping an invalid argument exception is thrown. - -A multi-line text box will continue to grow vertically as text is entered unless it's constrained by its [Height](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.height) or [MaxHeight](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.maxheight) property, or by a parent container. You should test that a multi-line text box doesn't grow beyond its visible area, and constrain its growth if it does. We recommend that you always specify an appropriate height for a multi-line text box, and not let it grow in height as the user types. - -Scrolling using a scroll-wheel or touch is automatically enabled when needed. However, the vertical scrollbars are not visible by default. You can show the vertical scrollbars by setting the [ScrollViewer.VerticalScrollBarVisibility](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollviewer.verticalscrollbarvisibility) to **Auto** on the embedded ScrollViewer, as shown here. - -```xaml - -``` - -```csharp -TextBox textBox = new TextBox(); -textBox.AcceptsReturn = true; -textBox.TextWrapping = TextWrapping.Wrap; -textBox.MaxHeight = 172; -textBox.Width = 300; -textBox.Header = "Description"; -ScrollViewer.SetVerticalScrollBarVisibility(textBox, ScrollBarVisibility.Auto); -``` - -Here's what the text box looks like after text is added. - -![A multi line text box](images/text-box-multi-line.png) - -### Format the text display - -Use the [TextAlignment](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textalignment) property to align text within a text box. To align the text box within the layout of the page, use the [HorizontalAlignment](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.horizontalalignment) and [VerticalAlignment](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.verticalalignment) properties. - -While the text box supports only unformatted text, you can customize how the text is displayed in the text box to match your branding. You can set standard [Control](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.Control) properties like [FontFamily](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.fontfamily), [FontSize](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.fontsize), [FontStyle](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.fontstyle), [Background](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.background), [Foreground](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.foreground), and [CharacterSpacing](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.characterspacing) to change the look of the text. These properties affect only how the text box displays the text locally, so if you were to copy and paste the text into a rich text control, for example, no formatting would be applied. - -This example shows a read-only text box with several properties set to customize the appearance of the text. - -```xaml - -``` - -```csharp -TextBox textBox = new TextBox(); -textBox.Text = "Sample Text"; -textBox.IsReadOnly = true; -textBox.FontFamily = new FontFamily("Verdana"); -textBox.FontSize = 24; -textBox.FontWeight = Windows.UI.Text.FontWeights.Bold; -textBox.FontStyle = Windows.UI.Text.FontStyle.Italic; -textBox.CharacterSpacing = 200; -textBox.Width = 300; -textBox.Background = new SolidColorBrush(Windows.UI.Colors.Beige); -textBox.Foreground = new SolidColorBrush(Windows.UI.Colors.Blue); -// Add the TextBox to the visual tree. -rootGrid.Children.Add(textBox); -``` - -The resulting text box looks like this. - -![A formatted text box](images/text-box-formatted.png) - -### Modify the context menu - -By default, the commands shown in the text box context menu depend on the state of the text box. For example, the following commands can be shown when the text box is editable. - -Command | Shown when... -------- | ------------- -Copy | text is selected. -Cut | text is selected. -Paste | the clipboard contains text. -Select all | the TextBox contains text. -Undo | text has been changed. - -To modify the commands shown in the context menu, handle the [ContextMenuOpening](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.contextmenuopening) event. For an example of this, see the **Customizing RichEditBox's CommandBarFlyout - adding 'Share'** example in the WinUI 3 Gallery. For design info, see Guidelines for [context menus](../../../design/controls/menus.md). - -### Select, copy, and paste - -You can get or set the selected text in a text box using the [SelectedText](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectedtext) property. Use the [SelectionStart](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionstart) and [SelectionLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionlength) properties, and the [Select](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.select) and [SelectAll](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectall) methods, to manipulate the text selection. Handle the [SelectionChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionchanged) event to do something when the user selects or de-selects text. You can change the color used to highlight the selected text by setting the [SelectionHighlightColor](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionhighlightcolor) property. - -TextBox supports copy and paste by default. You can provide custom handling of the [Paste](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.paste) event on editable text controls in your app. For example, you might remove the line breaks from a multi-line address when pasting it into a single-line search box. Or, you might check the length of the pasted text and warn the user if it exceeds the maximum length that can be saved to a database. For more info and examples, see the [Paste](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.paste) event. - -Here, we have an example of these properties and methods in use. When you select text in the first text box, the selected text is displayed in the second text box, which is read-only. The values of the [SelectionLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionlength) and [SelectionStart](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionstart) properties are shown in two text blocks. This is done using the [SelectionChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionchanged) event. - -```xaml - - - - - - -``` - -```csharp -private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e) -{ - textBox2.Text = textBox1.SelectedText; - label1.Text = "Selection length is " + textBox1.SelectionLength.ToString(); - label2.Text = "Selection starts at " + textBox1.SelectionStart.ToString(); -} -``` - -Here's the result of this code. - -![Selected text in a text box](images/text-box-selection.png) - -## Choose the right keyboard for your text control - -To help users to enter data using the touch keyboard, or Soft Input Panel (SIP), you can set the input scope of the text control to match the kind of data the user is expected to enter. - -The touch keyboard can be used for text entry when your app runs on a device with a touch screen. The touch keyboard is invoked when the user taps on an editable input field, such as a TextBox or RichEditBox. You can make it much faster and easier for users to enter data in your app by setting the input scope of the text control to match the kind of data you expect the user to enter. The input scope provides a hint to the system about the type of text input expected by the control so the system can provide a specialized touch keyboard layout for the input type. - -For example, if a text box is used only to enter a 4-digit PIN, set the [InputScope](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) property to **Number**. This tells the system to show the number keypad layout, which makes it easier for the user to enter the PIN. - -> **Important**  The input scope does not cause any input validation to be performed, and does not prevent the user from providing any input through a hardware keyboard or other input device. You are still responsible for validating the input in your code as needed. - -Other properties that affect the touch keyboard are [IsSpellCheckEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.isspellcheckenabled), [IsTextPredictionEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.istextpredictionenabled), and [PreventKeyboardDisplayOnProgrammaticFocus](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.preventkeyboarddisplayonprogrammaticfocus). (IsSpellCheckEnabled also affects the TextBox when a hardware keyboard is used.) - -For more info and examples, see [Use input scope to change the touch keyboard](../../../design/input/use-input-scope-to-change-the-touch-keyboard.md) and the property documentation. - -## Related articles - -- [Text controls](../../../design/controls/text-controls.md) -- [Guidelines for spell checking](../../../design/controls/text-controls.md) -- [Adding search](/previous-versions/windows/apps/hh465231(v=win.10)) -- [Guidelines for text input](../../../design/controls/text-controls.md) -- [TextBox class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.TextBox) -- [PasswordBox class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.PasswordBox) -- [String.Length property](/dotnet/api/system.string.length) +--- +ms.assetid: CC1BF51D-3DAC-4198-ADCB-1770B901C2FC +description: The TextBox control lets a user enter text into an app. +title: Text box +label: Text box +template: detail.hbs +ms.date: 02/26/2025 +ms.topic: article +keywords: windows 10, uwp +pm-contact: miguelrb +design-contact: ksulliv +doc-status: Published +ms.localizationpriority: medium +--- +# Text box + +The TextBox control lets a user type text into an app. It's typically used to capture a single line of text, but can be configured to capture multiple lines of text. The text displays on the screen in a simple, uniform, plaintext format. + +![A text box](images/text-box.png) + +TextBox has a number of features that can simplify text entry. It comes with a familiar, built-in context menu with support for copying and pasting text. The "clear all" button lets a user quickly delete all text that has been entered. It also has spell checking capabilities built in and enabled by default. + +## Is this the right control? + +Use a **TextBox** control to let a user enter and edit unformatted text, such as in a form. You can use the [Text](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.text) property to get and set the text in a TextBox. + +You can make a TextBox read-only, but this should be a temporary, conditional state. If the text is never editable, consider using a [TextBlock](../../../design/controls/text-block.md) instead. + +Use a [PasswordBox](../../../design/controls/password-box.md) control to collect a password or other private data, such as a Social Security number. A password box looks like a text input box, except that it renders bullets in place of the text that has been entered. + +Use an [AutoSuggestBox](../../../design/controls/auto-suggest-box.md) control to let the user enter search terms or to show the user a list of suggestions to choose from as they type. + +Use a [RichEditBox](../../../design/controls/rich-edit-box.md) to display and edit rich text files. + +For more info about choosing the right text control, see the [Text controls](../../../design/controls/text-controls.md) article. + +## Recommendations + +- Use a label or placeholder text if the purpose of the text box isn't clear. A label is visible whether or not the text input box has a value. Placeholder text is displayed inside the text input box and disappears once a value has been entered. +- Give the text box an appropriate width for the range of values that can be entered. Word length varies between languages, so take localization into account if you want your app to be world-ready. +- A text input box is typically single-line (`TextWrap = "NoWrap"`). When users need to enter or edit a long string, set the text input box to multi-line (`TextWrap = "Wrap"`). +- Generally, a text input box is used for editable text. But you can make a text input box read-only so that its content can be read, selected, and copied, but not edited. +- If you need to reduce clutter in a view, consider making a set of text input boxes appear only when a controlling checkbox is checked. You can also bind the enabled state of a text input box to a control such as a checkbox. +- Consider how you want a text input box to behave when it contains a value and the user taps it. The default behavior is appropriate for editing the value rather than replacing it; the insertion point is placed between words and nothing is selected. If replacing is the most common use case for a given text input box, you can select all the text in the field whenever the control receives focus, and typing replaces the selection. + +### Single-line input boxes + +- Use several single-line text boxes to capture many small pieces of text information. If the text boxes are related in nature, group those together. + +- Make the size of single-line text boxes slightly wider than the longest anticipated input. If doing so makes the control too wide, separate it into two controls. For example, you could split a single address input into "Address line 1" and "Address line 2". +- Set a maximum length for characters that can be entered. If the backing data source doesn't allow a long input string, limit the input and use a validation popup to let users know when they reach the limit. +- Use single-line text input controls to gather small pieces of text from users. + + The following example shows a single-line text box to capture an answer to a security question. The answer is expected to be short, and so a single-line text box is appropriate here. + + ![Basic data input](images/single-line-text-input-type-text.png) + +- Use a set of short, fixed-sized, single-line text input controls to enter data with a specific format. + + ![Formatted data input](images/textinput-example-productkey.png) + +- Use a single-line, unconstrained text input control to enter or edit strings, combined with a command button that helps users select valid values. + + ![Assisted data input](images/textinput-example-assisted.png) + +### Multi-line text input controls + +- When you create a rich text box, provide styling buttons and implement their actions. +- Use a font that's consistent with the style of your app. +- Make the height of the text control tall enough to accommodate typical entries. +- When capturing long spans of text with a maximum character or word count, use a plain text box and provide a live-running counter to show the user how many characters or words they have left before they reach the limit. You'll need to create the counter yourself; place it below the text box and dynamically update it as the user enters each character or word. + + ![A long span of text](images/multi-line-text-input-text-limits.png) + +- Don't let your text input controls grow in height while users type. +- Don't use a multi-line text box when users only need a single line. +- Don't use a rich text control if a plain text control is adequate. + +## Create a text box + +> [!div class="checklist"] +> +> - **Important APIs:** [TextBox class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.TextBox), [Text property](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.text) + +> [!div class="nextstepaction"] +> [Open the WinUI 3 Gallery app and see the TextBox in action](winui3gallery://item/TextBox) + +[!INCLUDE [winui-3-gallery](../../../../includes/winui-3-gallery.md)] + +Here's the XAML for a simple text box with a header and placeholder text. + +```xaml + +``` + +```csharp +TextBox textBox = new TextBox(); +textBox.Width = 300; +textBox.Header = "Notes"; +textBox.PlaceholderText = "Type your notes here"; +// Add the TextBox to the visual tree. +rootGrid.Children.Add(textBox); +``` + +Here's the text box that results from this XAML. + +![A simple text box](images/text-box-ex1.png) + +### Use a text box for data input in a form + +It's common to use a text box to accept data input on a form, and use the [Text](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.text) property to get the complete text string from the text box. You typically use an event like a submit button click to access the Text property, but you can handle the [TextChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textchanged) or [TextChanging](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textchanging) event if you need to do something when the text changes. + +This example shows how to get and set the current content of a text box. + +```xaml + +``` + +```csharp +string sampleText = SampleTextBox.Text; +... +SampleTextBox.Text = "Sample text retrieved"; +``` + +You can add a [Header](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.header) (or label) and [PlaceholderText](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.placeholdertext) (or watermark) to the text box to give the user an indication of what the text box is for. To customize the look of the header, you can set the [HeaderTemplate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.headertemplate) property instead of Header. *For design info, see Guidelines for labels*. + +You can restrict the number of characters the user can type by setting the [MaxLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.maxlength) property. However, MaxLength does not restrict the length of pasted text. Use the [Paste](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.paste) event to modify pasted text if this is important for your app. + +The text box includes a clear all button ("X") that appears when text is entered in the box. When a user clicks the "X", the text in the text box is cleared. It looks like this. + +![A text box with a clear all button](images/text-box-clear-all.png) + +The clear all button is shown only for editable, single-line text boxes that contain text and have focus. + +The clear all button is not shown in any of these cases: + +- **IsReadOnly** is **true** +- **AcceptsReturn** is **true** +- **TextWrap** has a value other than **NoWrap** + +This example shows how to get and set the current content of a text box. + +```xaml + +``` + +```csharp +string sampleText = SampleTextBox.Text; +... +SampleTextBox.Text = "Sample text retrieved"; +``` + + +### Make a text box read-only + +You can make a text box read-only by setting the [IsReadOnly](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.isreadonly) property to **true**. You typically toggle this property in your app code based on conditions in your app. If need text that is always read-only, consider using a TextBlock instead. + +You can make a TextBox read-only by setting the IsReadOnly property to true. For example, you might have a TextBox for a user to enter comments that is enabled only under certain conditions. You can make the TextBox read-only until the conditions are met. If you need only to display text, consider using a TextBlock or RichTextBlock instead. + +A read-only text box looks the same as a read/write text box, so it might be confusing to a user. +A user can select and copy text. +IsEnabled + +### Enable multi-line input + +There are two properties that you can use to control whether the text box displays text on more than one line. You typically set both properties to make a multi-line text box. + +- To let the text box allow and display the newline or return characters, set the [AcceptsReturn](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.acceptsreturn) property to **true**. +- To enable text wrapping, set the [TextWrapping](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textwrapping) property to **Wrap**. This causes the text to wrap when it reaches the edge of the text box, independent of line separator characters. + +> [!NOTE] +> TextBox and RichEditBox don't support the **WrapWholeWords** value for their TextWrapping properties. If you try to use WrapWholeWords as a value for TextBox.TextWrapping or RichEditBox.TextWrapping an invalid argument exception is thrown. + +A multi-line text box will continue to grow vertically as text is entered unless it's constrained by its [Height](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.height) or [MaxHeight](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.maxheight) property, or by a parent container. You should test that a multi-line text box doesn't grow beyond its visible area, and constrain its growth if it does. We recommend that you always specify an appropriate height for a multi-line text box, and not let it grow in height as the user types. + +Scrolling using a scroll-wheel or touch is automatically enabled when needed. However, the vertical scrollbars are not visible by default. You can show the vertical scrollbars by setting the [ScrollViewer.VerticalScrollBarVisibility](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollviewer.verticalscrollbarvisibility) to **Auto** on the embedded ScrollViewer, as shown here. + +```xaml + +``` + +```csharp +TextBox textBox = new TextBox(); +textBox.AcceptsReturn = true; +textBox.TextWrapping = TextWrapping.Wrap; +textBox.MaxHeight = 172; +textBox.Width = 300; +textBox.Header = "Description"; +ScrollViewer.SetVerticalScrollBarVisibility(textBox, ScrollBarVisibility.Auto); +``` + +Here's what the text box looks like after text is added. + +![A multi line text box](images/text-box-multi-line.png) + +### Format the text display + +Use the [TextAlignment](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.textalignment) property to align text within a text box. To align the text box within the layout of the page, use the [HorizontalAlignment](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.horizontalalignment) and [VerticalAlignment](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.verticalalignment) properties. + +While the text box supports only unformatted text, you can customize how the text is displayed in the text box to match your branding. You can set standard [Control](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.Control) properties like [FontFamily](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.fontfamily), [FontSize](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.fontsize), [FontStyle](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.fontstyle), [Background](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.background), [Foreground](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.foreground), and [CharacterSpacing](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control.characterspacing) to change the look of the text. These properties affect only how the text box displays the text locally, so if you were to copy and paste the text into a rich text control, for example, no formatting would be applied. + +This example shows a read-only text box with several properties set to customize the appearance of the text. + +```xaml + +``` + +```csharp +TextBox textBox = new TextBox(); +textBox.Text = "Sample Text"; +textBox.IsReadOnly = true; +textBox.FontFamily = new FontFamily("Verdana"); +textBox.FontSize = 24; +textBox.FontWeight = Windows.UI.Text.FontWeights.Bold; +textBox.FontStyle = Microsoft.UI.Text.FontStyle.Italic; +textBox.CharacterSpacing = 200; +textBox.Width = 300; +textBox.Background = new SolidColorBrush(Microsoft.UI.Colors.Beige); +textBox.Foreground = new SolidColorBrush(Microsoft.UI.Colors.Blue); +// Add the TextBox to the visual tree. +rootGrid.Children.Add(textBox); +``` + +The resulting text box looks like this. + +![A formatted text box](images/text-box-formatted.png) + +### Modify the context menu + +By default, the commands shown in the text box context menu depend on the state of the text box. For example, the following commands can be shown when the text box is editable. + +Command | Shown when... +------- | ------------- +Copy | text is selected. +Cut | text is selected. +Paste | the clipboard contains text. +Select all | the TextBox contains text. +Undo | text has been changed. + +To modify the commands shown in the context menu, handle the [ContextMenuOpening](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.contextmenuopening) event. For an example of this, see the **Customizing RichEditBox's CommandBarFlyout - adding 'Share'** example in the WinUI 3 Gallery. For design info, see Guidelines for [context menus](../../../design/controls/menus.md). + +### Select, copy, and paste + +You can get or set the selected text in a text box using the [SelectedText](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectedtext) property. Use the [SelectionStart](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionstart) and [SelectionLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionlength) properties, and the [Select](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.select) and [SelectAll](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectall) methods, to manipulate the text selection. Handle the [SelectionChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionchanged) event to do something when the user selects or de-selects text. You can change the color used to highlight the selected text by setting the [SelectionHighlightColor](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionhighlightcolor) property. + +TextBox supports copy and paste by default. You can provide custom handling of the [Paste](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.paste) event on editable text controls in your app. For example, you might remove the line breaks from a multi-line address when pasting it into a single-line search box. Or, you might check the length of the pasted text and warn the user if it exceeds the maximum length that can be saved to a database. For more info and examples, see the [Paste](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.paste) event. + +Here, we have an example of these properties and methods in use. When you select text in the first text box, the selected text is displayed in the second text box, which is read-only. The values of the [SelectionLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionlength) and [SelectionStart](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionstart) properties are shown in two text blocks. This is done using the [SelectionChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.selectionchanged) event. + +```xaml + + + + + + +``` + +```csharp +private void TextBox1_SelectionChanged(object sender, RoutedEventArgs e) +{ + textBox2.Text = textBox1.SelectedText; + label1.Text = "Selection length is " + textBox1.SelectionLength.ToString(); + label2.Text = "Selection starts at " + textBox1.SelectionStart.ToString(); +} +``` + +Here's the result of this code. + +![Selected text in a text box](images/text-box-selection.png) + +## Choose the right keyboard for your text control + +To help users to enter data using the touch keyboard, or Soft Input Panel (SIP), you can set the input scope of the text control to match the kind of data the user is expected to enter. + +The touch keyboard can be used for text entry when your app runs on a device with a touch screen. The touch keyboard is invoked when the user taps on an editable input field, such as a TextBox or RichEditBox. You can make it much faster and easier for users to enter data in your app by setting the input scope of the text control to match the kind of data you expect the user to enter. The input scope provides a hint to the system about the type of text input expected by the control so the system can provide a specialized touch keyboard layout for the input type. + +For example, if a text box is used only to enter a 4-digit PIN, set the [InputScope](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.inputscope) property to **Number**. This tells the system to show the number keypad layout, which makes it easier for the user to enter the PIN. + +> **Important**  The input scope does not cause any input validation to be performed, and does not prevent the user from providing any input through a hardware keyboard or other input device. You are still responsible for validating the input in your code as needed. + +Other properties that affect the touch keyboard are [IsSpellCheckEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.isspellcheckenabled), [IsTextPredictionEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.istextpredictionenabled), and [PreventKeyboardDisplayOnProgrammaticFocus](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textbox.preventkeyboarddisplayonprogrammaticfocus). (IsSpellCheckEnabled also affects the TextBox when a hardware keyboard is used.) + +For more info and examples, see [Use input scope to change the touch keyboard](../../../design/input/use-input-scope-to-change-the-touch-keyboard.md) and the property documentation. + +## Related articles + +- [Text controls](../../../design/controls/text-controls.md) +- [Guidelines for spell checking](../../../design/controls/text-controls.md) +- [Adding search](/previous-versions/windows/apps/hh465231(v=win.10)) +- [Guidelines for text input](../../../design/controls/text-controls.md) +- [TextBox class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.TextBox) +- [PasswordBox class](/windows/windows-app-sdk/api/winrt/microsoft.UI.Xaml.Controls.PasswordBox) +- [String.Length property](/dotnet/api/system.string.length) diff --git a/hub/apps/develop/ui/controls/two-pane-view.md b/hub/apps/develop/ui/controls/two-pane-view.md index eb81926cb0..b97fd50e12 100644 --- a/hub/apps/develop/ui/controls/two-pane-view.md +++ b/hub/apps/develop/ui/controls/two-pane-view.md @@ -1,313 +1,313 @@ ---- -description: TwoPaneView is a layout control that helps you manage the display of apps that have 2 distinct areas of content. -title: Two-pane view -template: detail.hbs -ms.date: 04/29/2025 -ms.topic: article -keywords: windows 10, uwp -ms.localizationpriority: medium ---- -# Two-pane view - -Two-pane view is a layout control that helps you manage the display of apps that have 2 distinct areas of content, like a list/detail view. - -## Is this the right control? - -Use the two-pane view when you have two distinct but related areas of content and: - -- The content should automatically rearrange and resize to best fit the window. -- The secondary area of content should show/hide based on available space. - -If you need to display two areas of content but don't need the resizing and rearranging provided by the two-pane view, consider using a [Split view](../../../design/controls/split-view.md) instead. - -For navigation options, use a [Navigation view](../../../design/controls/navigationview.md). - - -## How it works - -The two-pane view has two panes where you place your content. It adjusts the size and arrangement of the panes depending on the space available to the window. The possible pane layouts are defined by the [TwoPaneViewMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneviewmode) enumeration: - -| Enum value | Description | -| - | - | -| `SinglePane` | Only one pane is shown, as specified by the [PanePriority](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.panepriority) property. | -| `Wide` | Panes are shown side-by-side, or a single pane is shown, as specified by the [WideModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.widemodeconfiguration) property. | -| `Tall` | Panes are shown top-bottom, or a single pane is shown, as specified by the [TallModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.tallmodeconfiguration) property. | - -:::image type="content" source="images/two-pane-view/tpv-dual-wide.png" alt-text="Two-pane view app in wide mode, with a photo of a mountain on the left and information about the photo on the right."::: - -> _App in wide mode._ - -:::image type="content" source="images/two-pane-view/tpv-dual-tall.png" alt-text="Two-pane view app in tall mode, with a photo of a mountain on the top and information about the photo on the bottom."::: - -> _App in tall mode._ - -You configure the two-pane view by setting the [PanePriority](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.panepriority) to specify which pane is shown when there is space for only one pane. Then, you specify whether `Pane1` is shown on the top or bottom for tall windows, or on the left or right for wide windows. - -The two-pane view handles the size and arrangement of the panes, but you still need to make the content inside the pane adapt to the changes in size and orientation. See [Responsive layouts with XAML](../../../design/layout/layouts-with-xaml.md) and [Layout panels](../../../design/layout/layout-panels.md) for more info about creating an adaptive UI. - -## Create a two-pane view - -> [!div class="checklist"] -> -> - **Important APIs:** [TwoPaneView class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview) - -This XAML shows how to create a basic `TwoPaneView`. - -```xaml - - - - - - - - - - - - - -``` - -![Two-pane view with panes set to default sizes](images/two-pane-view/tpv-size-default.png) - -The [TwoPaneView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview) doesn't have to be the root element of your page layout. In fact, you'll often use it inside a [NavigationView](/uwp/api/microsoft.ui.xaml.controls.navigationview) control that provides the overall navigation for your app. The `TwoPaneView` adapts appropriately regardless of where it is in the XAML tree. - -### Add content to the panes - -Each pane of a two-pane view can hold a single XAML `UIElement`. To add content, you typically place a XAML layout panel in each pane, and then add other controls and content to the panel. The panes can change size and switch between wide and tall modes, so you need to make sure the content in each pane can adapt to these changes. See [Responsive layouts with XAML](../../../design/layout/layouts-with-xaml.md) and [Layout panels](../../../design/layout/layout-panels.md) for more info about creating an adaptive UI. - -This example creates the simple picture/info app UI shown previously. The content can be shown in two panes, or combined into a single pane, depending on how much space is available. (When there's only space for one pane, you move the content of Pane2 into Pane1, and let the user scroll to see any hidden content. You'll see the code for this later in the _Responding to mode changes_ section.) - -![Small image of example app spanned on dual-screens](images/two-pane-view/tpv-left-right.png) - -```xaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -``` - -### Specify which pane to display - -When the two-pane view can only display a single pane, it uses the [PanePriority](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.panepriority) property to determine which pane to display. By default, PanePriority is set to **Pane1**. Here's how you can set this property in XAML or in code. - -```xaml - -``` - -```csharp -MyTwoPaneView.PanePriority = TwoPaneViewPriority.Pane2; -``` - -### Pane sizing - -The size of the panes is determined by the [Pane1Length](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.pane1length) and [Pane2Length](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.pane2length) properties. These use [GridLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.gridlength) values that support _auto_ and _star_(\*) sizing. See the _Layout properties_ section of [Responsive layouts with XAML](../../../design/layout/layouts-with-xaml.md#layout-properties) for an explanation of auto and star sizing. - -By default, `Pane1Length` is set to `Auto` and it sizes itself to fit its content. `Pane2Length` is set to `*` and it uses all the remaining space. - -![Two-pane view with panes set to default sizes](images/two-pane-view/tpv-size-default.png) - -> _Panes with default sizing_ - -The default values are useful for a typical list/detail layout, where you have a list of items in `Pane1`, and a lot of details in `Pane2`. However, depending on your content, you might prefer to divide the space differently. Here, `Pane1Length` is set to `2*` so it gets twice as much space as `Pane2`. - -```xaml - -``` - -![Two-pane view with pane 1 using two-thirds of screen, and pane 2 using one-third](images/two-pane-view/tpv-size-2.png) - -> _Panes sized 2* and *_ - -If you set a pane to use auto sizing, you can control the size by setting the height and width of the `Panel` that holds the pane's content. In this case, you might need to handle the `ModeChanged` event and set the height and width constraints of the content as appropriate for the current mode. - -### Display in wide or tall mode - -On a single screen, the two-pane view's display [Mode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.mode) is determined by the [MinWideModeWidth](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.minwidemodewidth) and [MinTallModeHeight](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.mintallmodeheight) properties. Both properties have a default value of 641px, the same as [NavigationView.CompactThresholdWidth](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationview.compactmodethresholdwidth). - -This table shows how the `Height` and `Width` of the `TwoPaneView` determine which display mode is used. - -| TwoPaneView condition | Mode | -|---------|---------| -| `Width` > `MinWideModeWidth` | `Wide` mode is used | -| `Width` <= `MinWideModeWidth`, and `Height` > `MinTallModeHeight` | `Tall` mode is used | -| `Width` <= `MinWideModeWidth`, and `Height` <= `MinTallModeHeight` | `SinglePane` mode is used | - -#### Wide configuration options - -`MinWideModeWidth` controls when the two-pane view enters wide mode. The two-pane view enters `Wide` mode when the available space is wider than the `MinWideModeWidth` property. The default value is 641px, but you can change it to whatever you want. In general, you should set this property to whatever you want the minimum width of your pane to be. - -When the two-pane view is in wide mode, the [WideModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.widemodeconfiguration) property determines what to show: - -| [Enum value](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneviewwidemodeconfiguration) | Description | -|---------|---------| -| `SinglePane` | A single pane (as determined by `PanePriority`). The pane takes up the full size of the `TwoPaneView` (ie, it's star sized in both directions). | -| `LeftRight` | `Pane1` on the left/`Pane2` on the right. Both panes are star sized vertically, `Pane1`'s width is autosized, and `Pane2`'s width is star sized. | -| `RightLeft` | `Pane1` on the right/`Pane2` on the left. Both panes are star sized vertically, `Pane2`'s width is autosized, and `Pane1`'s width is star sized. | - -The default setting is `LeftRight`. - -| LeftRight | RightLeft | -| - | - | -| ![Two-pane view configured left-right](images/two-pane-view/tpv-left-right.png) | ![Two-pane view configured right-left](images/two-pane-view/tpv-right-left.png) | - -> [!NOTE] -> When the device uses a right-to-left (RTL) language, the two-pane view automatically swaps the order: `RightLeft` renders as `LeftRight`, and `LeftRight` renders as `RightLeft`. - -#### Tall configuration options - -The two-pane view enters `Tall` mode when the available space is narrower than `MinWideModeWidth`, and taller than `MinTallModeHeight`. The default value is 641px, but you can change it to whatever you want. In general, you should set this property to whatever you want the minimum height of your pane to be. - -When the two-pane view is in tall mode, the [TallModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.tallmodeconfiguration) property determines what to show: - -| [Enum value](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneviewtallmodeconfiguration) | Description | -|---------|---------| -| `SinglePane` | A single pane (as determined by `PanePriority`). The pane takes up the full size of the `TwoPaneView` (ie, it's star sized in both directions). | -| `TopBottom` | `Pane1` on the top/`Pane2` on the bottom. Both panes are star sized horizontally, `Pane1`'s height is autosized, and `Pane2`'s height is star sized. | -| `BottomTop` | `Pane1` on the bottom/`Pane2` on the top. Both panes are star sized horizontally, `Pane2`'s height is autosized, and `Pane1`'s height is star sized. | - -The default is `TopBottom`. - -| TopBottom | BottomTop | -| - | - | -| ![Two-pane view configured top-bottom](images/two-pane-view/tpv-top-bottom.png) | ![Two-pane view configured bottom-top](images/two-pane-view/tpv-bottom-top.png) | - -#### Special values for MinWideModeWidth and MinTallModeHeight - -You can use the `MinWideModeWidth` property to prevent the two-pane view from entering `Wide` mode - just set `MinWideModeWidth` to [Double.PositiveInfinity](/dotnet/api/system.double.positiveinfinity?view=dotnet-uwp-10.0&preserve-view=true). - -If you set `MinTallModeHeight` to [Double.PositiveInfinity](/dotnet/api/system.double.positiveinfinity?view=dotnet-uwp-10.0&preserve-view=true), it prevents the two-pane view from entering `Tall` mode. - -If you set `MinTallModeHeight` to 0, it prevents the two-pane view from entering `SinglePane` mode. - -#### Responding to mode changes - -You can use the read-only [Mode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.mode) property to get the current display mode. Whenever the two-pane view changes which pane or panes it's displaying, the [ModeChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.modechanged) event occurs before it renders the updated content. You can handle the event to respond to changes in the display mode. - -> [!IMPORTANT] -> The `ModeChanged` event does not occur when the page is initially loaded, so your default XAML should represent the UI as it should appear when first loaded. - -One way you can use this event is to update your app's UI so users can view all the content in `SinglePane` mode. For example, the example app has a primary pane (the image) and an info pane. - -![Small image of example app spanned in tall mode](images/two-pane-view/tpv-top-bottom.png) - -> _Tall mode_ - -When there's only enough space to display one pane, you can move the content of `Pane2` into `Pane1` so the user can scroll to see all the content. It looks like this. - -![Image of sample app on one screen with all content scrolling in a single pane](images/two-pane-view/tpv-single-pane.png) - -> _SinglePane mode_ - -Remember that the `MinWideModeWidth` and `MinTallModeHeight` properties determine when the display mode changes, so you can change when the content is moved between panes by adjusting the values of these properties. - -Here's the `ModeChanged` event handler code that moves the content between `Pane1` and `Pane2`. It also sets a [VisualState](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.visualstate) to constrain the width of the image in `Wide` mode. - -```csharp -private void TwoPaneView_ModeChanged(TwoPaneView sender, object args) -{ - // Remove details content from it's parent panel. - ((Panel)DetailsContent.Parent).Children.Remove(DetailsContent); - // Set Normal visual state. - VisualStateManager.GoToState(this, "Normal", true); - - // Single pane - if (sender.Mode == TwoPaneViewMode.SinglePane) - { - // Add the details content to Pane1. - Pane1StackPanel.Children.Add(DetailsContent); - } - // Dual pane. - else - { - // Put details content in Pane2. - Pane2Root.Children.Add(DetailsContent); - - // If also in Wide mode, set Wide visual state - // to constrain the width of the image to 2*. - if (sender.Mode == TwoPaneViewMode.Wide) - { - VisualStateManager.GoToState(this, "Wide", true); - } - } -} -``` - -## Related articles - -- [Layout overview](../../../design/layout/index.md) -- [Split view](../../../design/controls/split-view.md) +--- +description: TwoPaneView is a layout control that helps you manage the display of apps that have 2 distinct areas of content. +title: Two-pane view +template: detail.hbs +ms.date: 04/29/2025 +ms.topic: article +keywords: windows 10, uwp +ms.localizationpriority: medium +--- +# Two-pane view + +Two-pane view is a layout control that helps you manage the display of apps that have 2 distinct areas of content, like a list/detail view. + +## Is this the right control? + +Use the two-pane view when you have two distinct but related areas of content and: + +- The content should automatically rearrange and resize to best fit the window. +- The secondary area of content should show/hide based on available space. + +If you need to display two areas of content but don't need the resizing and rearranging provided by the two-pane view, consider using a [Split view](../../../design/controls/split-view.md) instead. + +For navigation options, use a [Navigation view](../../../design/controls/navigationview.md). + + +## How it works + +The two-pane view has two panes where you place your content. It adjusts the size and arrangement of the panes depending on the space available to the window. The possible pane layouts are defined by the [TwoPaneViewMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneviewmode) enumeration: + +| Enum value | Description | +| - | - | +| `SinglePane` | Only one pane is shown, as specified by the [PanePriority](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.panepriority) property. | +| `Wide` | Panes are shown side-by-side, or a single pane is shown, as specified by the [WideModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.widemodeconfiguration) property. | +| `Tall` | Panes are shown top-bottom, or a single pane is shown, as specified by the [TallModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.tallmodeconfiguration) property. | + +:::image type="content" source="images/two-pane-view/tpv-dual-wide.png" alt-text="Two-pane view app in wide mode, with a photo of a mountain on the left and information about the photo on the right."::: + +> _App in wide mode._ + +:::image type="content" source="images/two-pane-view/tpv-dual-tall.png" alt-text="Two-pane view app in tall mode, with a photo of a mountain on the top and information about the photo on the bottom."::: + +> _App in tall mode._ + +You configure the two-pane view by setting the [PanePriority](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.panepriority) to specify which pane is shown when there is space for only one pane. Then, you specify whether `Pane1` is shown on the top or bottom for tall windows, or on the left or right for wide windows. + +The two-pane view handles the size and arrangement of the panes, but you still need to make the content inside the pane adapt to the changes in size and orientation. See [Responsive layouts with XAML](../../../design/layout/layouts-with-xaml.md) and [Layout panels](../../../design/layout/layout-panels.md) for more info about creating an adaptive UI. + +## Create a two-pane view + +> [!div class="checklist"] +> +> - **Important APIs:** [TwoPaneView class](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview) + +This XAML shows how to create a basic `TwoPaneView`. + +```xaml + + + + + + + + + + + + + +``` + +![Two-pane view with panes set to default sizes](images/two-pane-view/tpv-size-default.png) + +The [TwoPaneView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview) doesn't have to be the root element of your page layout. In fact, you'll often use it inside a [NavigationView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationview) control that provides the overall navigation for your app. The `TwoPaneView` adapts appropriately regardless of where it is in the XAML tree. + +### Add content to the panes + +Each pane of a two-pane view can hold a single XAML `UIElement`. To add content, you typically place a XAML layout panel in each pane, and then add other controls and content to the panel. The panes can change size and switch between wide and tall modes, so you need to make sure the content in each pane can adapt to these changes. See [Responsive layouts with XAML](../../../design/layout/layouts-with-xaml.md) and [Layout panels](../../../design/layout/layout-panels.md) for more info about creating an adaptive UI. + +This example creates the simple picture/info app UI shown previously. The content can be shown in two panes, or combined into a single pane, depending on how much space is available. (When there's only space for one pane, you move the content of Pane2 into Pane1, and let the user scroll to see any hidden content. You'll see the code for this later in the _Responding to mode changes_ section.) + +![Small image of example app spanned on dual-screens](images/two-pane-view/tpv-left-right.png) + +```xaml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### Specify which pane to display + +When the two-pane view can only display a single pane, it uses the [PanePriority](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.panepriority) property to determine which pane to display. By default, PanePriority is set to **Pane1**. Here's how you can set this property in XAML or in code. + +```xaml + +``` + +```csharp +MyTwoPaneView.PanePriority = TwoPaneViewPriority.Pane2; +``` + +### Pane sizing + +The size of the panes is determined by the [Pane1Length](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.pane1length) and [Pane2Length](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.pane2length) properties. These use [GridLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.gridlength) values that support _auto_ and _star_(\*) sizing. See the _Layout properties_ section of [Responsive layouts with XAML](../../../design/layout/layouts-with-xaml.md#layout-properties) for an explanation of auto and star sizing. + +By default, `Pane1Length` is set to `Auto` and it sizes itself to fit its content. `Pane2Length` is set to `*` and it uses all the remaining space. + +![Two-pane view with panes set to default sizes](images/two-pane-view/tpv-size-default.png) + +> _Panes with default sizing_ + +The default values are useful for a typical list/detail layout, where you have a list of items in `Pane1`, and a lot of details in `Pane2`. However, depending on your content, you might prefer to divide the space differently. Here, `Pane1Length` is set to `2*` so it gets twice as much space as `Pane2`. + +```xaml + +``` + +![Two-pane view with pane 1 using two-thirds of screen, and pane 2 using one-third](images/two-pane-view/tpv-size-2.png) + +> _Panes sized 2* and *_ + +If you set a pane to use auto sizing, you can control the size by setting the height and width of the `Panel` that holds the pane's content. In this case, you might need to handle the `ModeChanged` event and set the height and width constraints of the content as appropriate for the current mode. + +### Display in wide or tall mode + +On a single screen, the two-pane view's display [Mode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.mode) is determined by the [MinWideModeWidth](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.minwidemodewidth) and [MinTallModeHeight](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.mintallmodeheight) properties. Both properties have a default value of 641px, the same as [NavigationView.CompactThresholdWidth](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationview.compactmodethresholdwidth). + +This table shows how the `Height` and `Width` of the `TwoPaneView` determine which display mode is used. + +| TwoPaneView condition | Mode | +|---------|---------| +| `Width` > `MinWideModeWidth` | `Wide` mode is used | +| `Width` <= `MinWideModeWidth`, and `Height` > `MinTallModeHeight` | `Tall` mode is used | +| `Width` <= `MinWideModeWidth`, and `Height` <= `MinTallModeHeight` | `SinglePane` mode is used | + +#### Wide configuration options + +`MinWideModeWidth` controls when the two-pane view enters wide mode. The two-pane view enters `Wide` mode when the available space is wider than the `MinWideModeWidth` property. The default value is 641px, but you can change it to whatever you want. In general, you should set this property to whatever you want the minimum width of your pane to be. + +When the two-pane view is in wide mode, the [WideModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.widemodeconfiguration) property determines what to show: + +| [Enum value](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneviewwidemodeconfiguration) | Description | +|---------|---------| +| `SinglePane` | A single pane (as determined by `PanePriority`). The pane takes up the full size of the `TwoPaneView` (ie, it's star sized in both directions). | +| `LeftRight` | `Pane1` on the left/`Pane2` on the right. Both panes are star sized vertically, `Pane1`'s width is autosized, and `Pane2`'s width is star sized. | +| `RightLeft` | `Pane1` on the right/`Pane2` on the left. Both panes are star sized vertically, `Pane2`'s width is autosized, and `Pane1`'s width is star sized. | + +The default setting is `LeftRight`. + +| LeftRight | RightLeft | +| - | - | +| ![Two-pane view configured left-right](images/two-pane-view/tpv-left-right.png) | ![Two-pane view configured right-left](images/two-pane-view/tpv-right-left.png) | + +> [!NOTE] +> When the device uses a right-to-left (RTL) language, the two-pane view automatically swaps the order: `RightLeft` renders as `LeftRight`, and `LeftRight` renders as `RightLeft`. + +#### Tall configuration options + +The two-pane view enters `Tall` mode when the available space is narrower than `MinWideModeWidth`, and taller than `MinTallModeHeight`. The default value is 641px, but you can change it to whatever you want. In general, you should set this property to whatever you want the minimum height of your pane to be. + +When the two-pane view is in tall mode, the [TallModeConfiguration](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.tallmodeconfiguration) property determines what to show: + +| [Enum value](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneviewtallmodeconfiguration) | Description | +|---------|---------| +| `SinglePane` | A single pane (as determined by `PanePriority`). The pane takes up the full size of the `TwoPaneView` (ie, it's star sized in both directions). | +| `TopBottom` | `Pane1` on the top/`Pane2` on the bottom. Both panes are star sized horizontally, `Pane1`'s height is autosized, and `Pane2`'s height is star sized. | +| `BottomTop` | `Pane1` on the bottom/`Pane2` on the top. Both panes are star sized horizontally, `Pane2`'s height is autosized, and `Pane1`'s height is star sized. | + +The default is `TopBottom`. + +| TopBottom | BottomTop | +| - | - | +| ![Two-pane view configured top-bottom](images/two-pane-view/tpv-top-bottom.png) | ![Two-pane view configured bottom-top](images/two-pane-view/tpv-bottom-top.png) | + +#### Special values for MinWideModeWidth and MinTallModeHeight + +You can use the `MinWideModeWidth` property to prevent the two-pane view from entering `Wide` mode - just set `MinWideModeWidth` to [Double.PositiveInfinity](/dotnet/api/system.double.positiveinfinity?view=dotnet-uwp-10.0&preserve-view=true). + +If you set `MinTallModeHeight` to [Double.PositiveInfinity](/dotnet/api/system.double.positiveinfinity?view=dotnet-uwp-10.0&preserve-view=true), it prevents the two-pane view from entering `Tall` mode. + +If you set `MinTallModeHeight` to 0, it prevents the two-pane view from entering `SinglePane` mode. + +#### Responding to mode changes + +You can use the read-only [Mode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.mode) property to get the current display mode. Whenever the two-pane view changes which pane or panes it's displaying, the [ModeChanged](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.twopaneview.modechanged) event occurs before it renders the updated content. You can handle the event to respond to changes in the display mode. + +> [!IMPORTANT] +> The `ModeChanged` event does not occur when the page is initially loaded, so your default XAML should represent the UI as it should appear when first loaded. + +One way you can use this event is to update your app's UI so users can view all the content in `SinglePane` mode. For example, the example app has a primary pane (the image) and an info pane. + +![Small image of example app spanned in tall mode](images/two-pane-view/tpv-top-bottom.png) + +> _Tall mode_ + +When there's only enough space to display one pane, you can move the content of `Pane2` into `Pane1` so the user can scroll to see all the content. It looks like this. + +![Image of sample app on one screen with all content scrolling in a single pane](images/two-pane-view/tpv-single-pane.png) + +> _SinglePane mode_ + +Remember that the `MinWideModeWidth` and `MinTallModeHeight` properties determine when the display mode changes, so you can change when the content is moved between panes by adjusting the values of these properties. + +Here's the `ModeChanged` event handler code that moves the content between `Pane1` and `Pane2`. It also sets a [VisualState](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.visualstate) to constrain the width of the image in `Wide` mode. + +```csharp +private void TwoPaneView_ModeChanged(TwoPaneView sender, object args) +{ + // Remove details content from it's parent panel. + ((Panel)DetailsContent.Parent).Children.Remove(DetailsContent); + // Set Normal visual state. + VisualStateManager.GoToState(this, "Normal", true); + + // Single pane + if (sender.Mode == TwoPaneViewMode.SinglePane) + { + // Add the details content to Pane1. + Pane1StackPanel.Children.Add(DetailsContent); + } + // Dual pane. + else + { + // Put details content in Pane2. + Pane2Root.Children.Add(DetailsContent); + + // If also in Wide mode, set Wide visual state + // to constrain the width of the image to 2*. + if (sender.Mode == TwoPaneViewMode.Wide) + { + VisualStateManager.GoToState(this, "Wide", true); + } + } +} +``` + +## Related articles + +- [Layout overview](../../../design/layout/index.md) +- [Split view](../../../design/controls/split-view.md) diff --git a/hub/apps/develop/ui/display-ui-objects.md b/hub/apps/develop/ui/display-ui-objects.md index 4835e0d0ae..4febf05639 100644 --- a/hub/apps/develop/ui/display-ui-objects.md +++ b/hub/apps/develop/ui/display-ui-objects.md @@ -1,235 +1,235 @@ ---- -title: Display WinRT UI objects that depend on CoreWindow -description: You can use certain pickers, popups, dialogs, and other Windows Runtime (WinRT) objects in your desktop app by adding a little bit of interoperation code. -ms.topic: how-to -ms.date: 02/28/2023 -keywords: Windows, App, SDK, desktop, C#, C++, cpp, window, handle, HWND, WinUI, interop, IInitializeWithWindow, IInitializeWithWindow::Initialize, WinRT.Interop.InitializeWithWindow, IDataTransferManagerInterop, IUserConsentVerifierInterop -ms.localizationpriority: medium ---- - -# Display WinRT UI objects that depend on CoreWindow - -Certain pickers, popups, dialogs, and other Windows Runtime (WinRT) objects depend on a [CoreWindow](/uwp/api/windows.ui.core.corewindow); typically to display a user-interface (UI). Even though **CoreWindow** isn't supported in desktop apps (see [Core unsupported classes](../../desktop/modernize/desktop-to-uwp-supported-api.md#core-unsupported-classes)), you can still use many of those WinRT classes in your desktop app by adding a little bit of interoperation code. - -Your desktop app can be [WinUI 3](../../winui/winui3/index.md), [Windows Presentation Foundation (WPF)](/dotnet/desktop/wpf/), or [Windows Forms (WinForms)](/dotnet/desktop/winforms/) apps. Code examples are presented in C# and [C++/WinRT](/windows/uwp/cpp-and-winrt-apis/). - -## Set the owner window handle (HWND) for a WinRT UI object - -For classes that implement the [**IInitializeWithWindow**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-iinitializewithwindow) interface (or the equivalent [**IDataTransferManagerInterop**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-idatatransfermanagerinterop) interface), you can use that interface to set an owner window on the object before you display it. It's a two-step process. - -1. Decide which window will be the owner of the UI object that you want to display, and retrieve that window's HWND. For more details and code examples for this step, see [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md). -2. Then call the appropriate interoperability API (for C# or C++/WinRT) to set an owner window handle (HWND) for the WinRT UI object. - -## For classes that implement IInitializeWithWindow - -These classes implement [**IInitializeWithWindow**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-iinitializewithwindow): - -* [**Windows.ApplicationModel.Contacts.PinnedContactManager**](/uwp/api/windows.applicationmodel.contacts.pinnedcontactmanager) -* [**Windows.ApplicationModel.Payments.PaymentMediator**](/uwp/api/windows.applicationmodel.payments.paymentmediator) -* [**Windows.Devices.Enumeration.DevicePicker**](/uwp/api/windows.devices.enumeration.devicepicker) -* [**Windows.Graphics.Capture.GraphicsCapturePicker**](/uwp/api/windows.graphics.capture.graphicscapturepicker) -* [**Windows.Media.Casting.CastingDevicePicker**](/uwp/api/windows.media.casting.castingdevicepicker) -* [**Windows.Media.DialProtocol.DialDevicePicker**](/uwp/api/windows.media.dialprotocol.dialdevicepicker) -* [**Windows.Networking.NetworkOperators.ProvisioningAgent**](/uwp/api/windows.networking.networkoperators.provisioningagent) -* [**Windows.Security.Authentication.OnlineId.OnlineIdAuthenticator**](/uwp/api/windows.security.authentication.onlineid.onlineidauthenticator) -* [**Windows.Services.Store.StoreContext**](/uwp/api/windows.services.store.storecontext) -* [**Windows.Storage.Pickers.FileOpenPicker**](/uwp/api/windows.storage.pickers.fileopenpicker) -* [**Windows.Storage.Pickers.FileSavePicker**](/uwp/api/windows.storage.pickers.filesavepicker) -* [**Windows.Storage.Pickers.FolderPicker**](/uwp/api/windows.storage.pickers.folderpicker) -* [**Windows.System.FolderLauncherOptions**](/uwp/api/windows.system.folderlauncheroptions)—Windows 10, version 1903 (10.0; Build 18362) and later -* [**Windows.System.LauncherOptions**](/uwp/api/windows.system.launcheroptions)—Windows 10, version 1903 (10.0; Build 18362) and later -* [**Windows.UI.Core.CoreWindowDialog**](/uwp/api/windows.ui.core.corewindowdialog) -* [**Windows.UI.Core.CoreWindowFlyout**](/uwp/api/windows.ui.core.corewindowflyout) -* [**Windows.UI.Popups.MessageDialog**](/uwp/api/windows.ui.popups.messagedialog). But for new apps we recommend using the [**ContentDialog**](/uwp/api/windows.ui.xaml.controls.contentdialog) control instead. -* [**Windows.UI.Popups.PopupMenu**](/uwp/api/windows.ui.popups.popupmenu) -* [**Windows.UI.StartScreen.SecondaryTile**](/uwp/api/windows.ui.startscreen.secondarytile) -* [**Windows.Web.Http.Filters.HttpBaseProtocolFilter**](/uwp/api/windows.web.http.filters.httpbaseprotocolfilter) - -> [!NOTE] -> The list above is necessarily incomplete—refer to a type's documentation to see whether it implements **IInitializeWithWindow** (or an equivalent interop interface). - -The next sections contain code examples to display a [**FolderPicker**](/uwp/api/windows.storage.pickers.fileopenpicker). But it's the same technique to display any of the APIs listed above. - -### WinUI with C# (also WPF/WinForms with .NET 6 or later) - -> [!NOTE] -> The code examples in this section use the **WinRT.Interop.WindowNative** C# interop class. If you target .NET 6 or later, then you can use that class in a WPF or WinForms project. For info about setting up your project to do that, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). - -The C# code below expects that you've already used the pattern documented in [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md). Then, to set the owner window for the UI object that you want to display, the code calls the **Initialize** method on the **WinRT.Interop.InitializeWithWindow** C# interop class. For more info about the C# interop classes, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). - -```csharp -// MainWindow.xaml.cs -private async void ShowFolderPickerAsync(IntPtr hWnd) -{ - // Create a folder picker. - var folderPicker = new Windows.Storage.Pickers.FolderPicker(); - - // Initialize the folder picker with the window handle (HWND). - WinRT.Interop.InitializeWithWindow.Initialize(folderPicker, hWnd); - - // Use the folder picker as usual. - folderPicker.FileTypeFilter.Add("*"); - var folder = await folderPicker.PickSingleFolderAsync(); -} -``` - -### WinUI with C++ - -The C++/WinRT code below expects that you've already used the pattern documented in [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md). Then, to set the owner window for the UI object that you want to display, the code calls the interoperability method [**IInitializeWithWindow::Initialize**](/windows/win32/api/shobjidl_core/nf-shobjidl_core-iinitializewithwindow-initialize). - -```cppwinrt -// pch.h -... -#include -#include -#include - -// MainWindow.xaml.cpp -winrt::fire_and_forget ShowFolderPickerAsync(HWND hWnd) -{ - // Create a folder picker. - Windows::Storage::Pickers::FolderPicker folderPicker; - - // Initialize the folder picker with the window handle (HWND). - auto initializeWithWindow{ folderPicker.as<::IInitializeWithWindow>() }; - initializeWithWindow->Initialize(hWnd); - - // Use the folder picker as usual. - folderPicker.FileTypeFilter().Append(L"*"); - auto folder{ co_await folderPicker.PickSingleFolderAsync() }; -} -``` - -## For classes that implement IDataTransferManagerInterop - -The [**Windows.ApplicationModel.DataTransfer.DataTransferManager**](/uwp/api/windows.applicationmodel.datatransfer.datatransfermanager) class implements the [**IDataTransferManagerInterop**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-idatatransfermanagerinterop) interface (which, like **IInitializeWithWindow**, lets you set an owner window). - -In a desktop app, instead of calling the [**DataTransferManager.ShowShareUI**](/uwp/api/windows.applicationmodel.datatransfer.datatransfermanager.showshareui) method, you call [**IDataTransferManagerInterop::ShowShareUIForWindow**](/windows/win32/api/shobjidl_core/nf-shobjidl_core-idatatransfermanagerinterop-showshareuiforwindow), as shown in the code examples below. - -### WinUI with C# (also WPF/WinForms with .NET 6 or later) - -```csharp -// MainWindow.xaml.cs -... -public sealed partial class MainWindow : Window -{ - ... - - [System.Runtime.InteropServices.ComImport] - [System.Runtime.InteropServices.Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")] - [System.Runtime.InteropServices.InterfaceType( - System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)] - interface IDataTransferManagerInterop - { - IntPtr GetForWindow([System.Runtime.InteropServices.In] IntPtr appWindow, - [System.Runtime.InteropServices.In] ref Guid riid); - void ShowShareUIForWindow(IntPtr appWindow); - } - - static readonly Guid _dtm_iid = - new Guid(0xa5caee9b, 0x8708, 0x49d1, 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c); - - private void myButton_Click(object sender, RoutedEventArgs e) - { - // Retrieve the window handle (HWND) of the current WinUI window. - var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); - - IDataTransferManagerInterop interop = - Windows.ApplicationModel.DataTransfer.DataTransferManager.As - (); - - IntPtr result = interop.GetForWindow(hWnd, _dtm_iid); - var dataTransferManager = WinRT.MarshalInterface - .FromAbi(result); - - dataTransferManager.DataRequested += (sender, args) => - { - args.Request.Data.Properties.Title = "In a desktop app..."; - args.Request.Data.SetText("...display WinRT UI objects that depend on CoreWindow."); - args.Request.Data.RequestedOperation = - Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy; - }; - - // Show the Share UI - interop.ShowShareUIForWindow(hWnd); - } -} -... -``` - -### WinUI with C++ - -```cppwinrt -// pch.h in a Windows App SDK app -... -#include -#include -#include -... - -// MainWindow.xaml.cpp -... -void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&) -{ - // Retrieve the window handle (HWND) of the current WinUI window. - auto windowNative{ this->m_inner.as<::IWindowNative>() }; - HWND hWnd{ 0 }; - windowNative->get_WindowHandle(&hWnd); - - winrt::com_ptr interop = - winrt::get_activation_factory(); - - winrt::guid _dtm_iid{ 0xa5caee9b, 0x8708, 0x49d1, { 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c } }; - Windows::ApplicationModel::DataTransfer::DataTransferManager dataTransferManager{ nullptr }; - interop->GetForWindow(hWnd, _dtm_iid, winrt::put_abi(dataTransferManager)); - - dataTransferManager.DataRequested([](Windows::ApplicationModel::DataTransfer::DataTransferManager const& /* sender */, - Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs const& args) - { - args.Request().Data().Properties().Title(L"In a desktop app..."); - args.Request().Data().SetText(L"...display WinRT UI objects that depend on CoreWindow."); - args.Request().Data().RequestedOperation(Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy); - }); - - interop->ShowShareUIForWindow(hWnd); -} -... -``` - -## For classes that implement IUserConsentVerifierInterop - -The [**Windows.Security.Credentials.UI.UserConsentVerifier**](/uwp/api/windows.security.credentials.ui.userconsentverifier) class implements the [**IUserConsentVerifierInterop**](/windows/win32/api/userconsentverifierinterop/nn-userconsentverifierinterop-iuserconsentverifierinterop) interface (which, like **IInitializeWithWindow**, lets you set an owner window). - -In a desktop app, instead of calling the [**UserConsentVerifier.RequestVerificationAsync**](/uwp/api/windows.security.credentials.ui.userconsentverifier.requestverificationasync) method: - -* **C#**. Call the **RequestVerificationForWindowAsync** method of the **Windows.Security.Credentials.UI.UserConsentVerifierInterop** C# interop class. For more info about the C# interop classes, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). -* **C++/WinRT**. Call [**IUserConsentVerifierInterop::RequestVerificationForWindowAsync**](/windows/win32/api/userconsentverifierinterop/nf-userconsentverifierinterop-iuserconsentverifierinterop-requestverificationforwindowasync). - -For more info, and code examples, see [**UserConsentVerifier**](/uwp/api/windows.security.credentials.ui.userconsentverifier). - -## For classes that implement other interop interfaces - -These interfaces have **XxxForWindow** methods, which let you set an owner window handle (HWND). You can use these interfaces directly from C++/WinRT. Versions of the interfaces also exist in the form of C# classes—for more details, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). - -* [**IAccountsSettingsPaneInterop**](/windows/win32/api/accountssettingspaneinterop/nn-accountssettingspaneinterop-iaccountssettingspaneinterop) -* [**IDragDropManagerInterop**](/windows/win32/api/dragdropinterop/nn-dragdropinterop-idragdropmanagerinterop) -* [**IInputPaneInterop**](/windows/win32/api/inputpaneinterop/nn-inputpaneinterop-iinputpaneinterop) -* [**IPlayToManagerInterop**](/windows/win32/api/playtomanagerinterop/nn-playtomanagerinterop-iplaytomanagerinterop) -* [**IPrintManagerInterop**](/windows/win32/api/printmanagerinterop/nn-printmanagerinterop-iprintmanagerinterop) -* [**IRadialControllerConfigurationInterop**](/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerconfigurationinterop) -* **IRadialControllerIndependentInputSourceInterop** -* [**IRadialControllerInterop**](/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerinterop) -* [**ISpatialInteractionManagerInterop**](/windows/win32/api/spatialinteractionmanagerinterop/nn-spatialinteractionmanagerinterop-ispatialinteractionmanagerinterop) -* [**ISystemMediaTransportControlsInterop**](/windows/win32/api/systemmediatransportcontrolsinterop/nn-systemmediatransportcontrolsinterop-isystemmediatransportcontrolsinterop) -* [**IUIViewSettingsInterop**](/windows/win32/api/uiviewsettingsinterop/nn-uiviewsettingsinterop-iuiviewsettingsinterop) -* [**IWebAuthenticationCoreManagerInterop**](/windows/win32/api/webauthenticationcoremanagerinterop/nn-webauthenticationcoremanagerinterop-iwebauthenticationcoremanagerinterop) - -## Related topics - -* [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md) -* [WinUI](../../winui/winui3/index.md) -* [Windows Presentation Foundation (WPF)](/dotnet/desktop/wpf/) -* [Windows Forms (WinForms)](/dotnet/desktop/winforms/) -* [C++/WinRT](/windows/uwp/cpp-and-winrt-apis/) -* [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md) +--- +title: Display WinRT UI objects that depend on CoreWindow +description: You can use certain pickers, popups, dialogs, and other Windows Runtime (WinRT) objects in your desktop app by adding a little bit of interoperation code. +ms.topic: how-to +ms.date: 02/28/2023 +keywords: Windows, App, SDK, desktop, C#, C++, cpp, window, handle, HWND, WinUI, interop, IInitializeWithWindow, IInitializeWithWindow::Initialize, WinRT.Interop.InitializeWithWindow, IDataTransferManagerInterop, IUserConsentVerifierInterop +ms.localizationpriority: medium +--- + +# Display WinRT UI objects that depend on CoreWindow + +Certain pickers, popups, dialogs, and other Windows Runtime (WinRT) objects depend on a [CoreWindow](/uwp/api/windows.ui.core.corewindow); typically to display a user-interface (UI). Even though **CoreWindow** isn't supported in desktop apps (see [Core unsupported classes](../../desktop/modernize/desktop-to-uwp-supported-api.md#core-unsupported-classes)), you can still use many of those WinRT classes in your desktop app by adding a little bit of interoperation code. + +Your desktop app can be [WinUI 3](../../winui/winui3/index.md), [Windows Presentation Foundation (WPF)](/dotnet/desktop/wpf/), or [Windows Forms (WinForms)](/dotnet/desktop/winforms/) apps. Code examples are presented in C# and [C++/WinRT](/windows/uwp/cpp-and-winrt-apis/). + +## Set the owner window handle (HWND) for a WinRT UI object + +For classes that implement the [**IInitializeWithWindow**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-iinitializewithwindow) interface (or the equivalent [**IDataTransferManagerInterop**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-idatatransfermanagerinterop) interface), you can use that interface to set an owner window on the object before you display it. It's a two-step process. + +1. Decide which window will be the owner of the UI object that you want to display, and retrieve that window's HWND. For more details and code examples for this step, see [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md). +2. Then call the appropriate interoperability API (for C# or C++/WinRT) to set an owner window handle (HWND) for the WinRT UI object. + +## For classes that implement IInitializeWithWindow + +These classes implement [**IInitializeWithWindow**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-iinitializewithwindow): + +* [**Windows.ApplicationModel.Contacts.PinnedContactManager**](/uwp/api/windows.applicationmodel.contacts.pinnedcontactmanager) +* [**Windows.ApplicationModel.Payments.PaymentMediator**](/uwp/api/windows.applicationmodel.payments.paymentmediator) +* [**Windows.Devices.Enumeration.DevicePicker**](/uwp/api/windows.devices.enumeration.devicepicker) +* [**Windows.Graphics.Capture.GraphicsCapturePicker**](/uwp/api/windows.graphics.capture.graphicscapturepicker) +* [**Windows.Media.Casting.CastingDevicePicker**](/uwp/api/windows.media.casting.castingdevicepicker) +* [**Windows.Media.DialProtocol.DialDevicePicker**](/uwp/api/windows.media.dialprotocol.dialdevicepicker) +* [**Windows.Networking.NetworkOperators.ProvisioningAgent**](/uwp/api/windows.networking.networkoperators.provisioningagent) +* [**Windows.Security.Authentication.OnlineId.OnlineIdAuthenticator**](/uwp/api/windows.security.authentication.onlineid.onlineidauthenticator) +* [**Windows.Services.Store.StoreContext**](/uwp/api/windows.services.store.storecontext) +* [**Windows.Storage.Pickers.FileOpenPicker**](/uwp/api/windows.storage.pickers.fileopenpicker) +* [**Windows.Storage.Pickers.FileSavePicker**](/uwp/api/windows.storage.pickers.filesavepicker) +* [**Windows.Storage.Pickers.FolderPicker**](/uwp/api/windows.storage.pickers.folderpicker) +* [**Windows.System.FolderLauncherOptions**](/uwp/api/windows.system.folderlauncheroptions)—Windows 10, version 1903 (10.0; Build 18362) and later +* [**Windows.System.LauncherOptions**](/uwp/api/windows.system.launcheroptions)—Windows 10, version 1903 (10.0; Build 18362) and later +* [**Windows.UI.Core.CoreWindowDialog**](/uwp/api/windows.ui.core.corewindowdialog) +* [**Windows.UI.Core.CoreWindowFlyout**](/uwp/api/windows.ui.core.corewindowflyout) +* [**Windows.UI.Popups.MessageDialog**](/uwp/api/windows.ui.popups.messagedialog). But for new apps we recommend using the [**ContentDialog**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.contentdialog) control instead. +* [**Windows.UI.Popups.PopupMenu**](/uwp/api/windows.ui.popups.popupmenu) +* [**Windows.UI.StartScreen.SecondaryTile**](/uwp/api/windows.ui.startscreen.secondarytile) +* [**Windows.Web.Http.Filters.HttpBaseProtocolFilter**](/uwp/api/windows.web.http.filters.httpbaseprotocolfilter) + +> [!NOTE] +> The list above is necessarily incomplete—refer to a type's documentation to see whether it implements **IInitializeWithWindow** (or an equivalent interop interface). + +The next sections contain code examples to display a [**FolderPicker**](/uwp/api/windows.storage.pickers.fileopenpicker). But it's the same technique to display any of the APIs listed above. + +### WinUI with C# (also WPF/WinForms with .NET 6 or later) + +> [!NOTE] +> The code examples in this section use the **WinRT.Interop.WindowNative** C# interop class. If you target .NET 6 or later, then you can use that class in a WPF or WinForms project. For info about setting up your project to do that, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). + +The C# code below expects that you've already used the pattern documented in [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md). Then, to set the owner window for the UI object that you want to display, the code calls the **Initialize** method on the **WinRT.Interop.InitializeWithWindow** C# interop class. For more info about the C# interop classes, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). + +```csharp +// MainWindow.xaml.cs +private async void ShowFolderPickerAsync(IntPtr hWnd) +{ + // Create a folder picker. + var folderPicker = new Windows.Storage.Pickers.FolderPicker(); + + // Initialize the folder picker with the window handle (HWND). + WinRT.Interop.InitializeWithWindow.Initialize(folderPicker, hWnd); + + // Use the folder picker as usual. + folderPicker.FileTypeFilter.Add("*"); + var folder = await folderPicker.PickSingleFolderAsync(); +} +``` + +### WinUI with C++ + +The C++/WinRT code below expects that you've already used the pattern documented in [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md). Then, to set the owner window for the UI object that you want to display, the code calls the interoperability method [**IInitializeWithWindow::Initialize**](/windows/win32/api/shobjidl_core/nf-shobjidl_core-iinitializewithwindow-initialize). + +```cppwinrt +// pch.h +... +#include +#include +#include + +// MainWindow.xaml.cpp +winrt::fire_and_forget ShowFolderPickerAsync(HWND hWnd) +{ + // Create a folder picker. + Windows::Storage::Pickers::FolderPicker folderPicker; + + // Initialize the folder picker with the window handle (HWND). + auto initializeWithWindow{ folderPicker.as<::IInitializeWithWindow>() }; + initializeWithWindow->Initialize(hWnd); + + // Use the folder picker as usual. + folderPicker.FileTypeFilter().Append(L"*"); + auto folder{ co_await folderPicker.PickSingleFolderAsync() }; +} +``` + +## For classes that implement IDataTransferManagerInterop + +The [**Windows.ApplicationModel.DataTransfer.DataTransferManager**](/uwp/api/windows.applicationmodel.datatransfer.datatransfermanager) class implements the [**IDataTransferManagerInterop**](/windows/win32/api/shobjidl_core/nn-shobjidl_core-idatatransfermanagerinterop) interface (which, like **IInitializeWithWindow**, lets you set an owner window). + +In a desktop app, instead of calling the [**DataTransferManager.ShowShareUI**](/uwp/api/windows.applicationmodel.datatransfer.datatransfermanager.showshareui) method, you call [**IDataTransferManagerInterop::ShowShareUIForWindow**](/windows/win32/api/shobjidl_core/nf-shobjidl_core-idatatransfermanagerinterop-showshareuiforwindow), as shown in the code examples below. + +### WinUI with C# (also WPF/WinForms with .NET 6 or later) + +```csharp +// MainWindow.xaml.cs +... +public sealed partial class MainWindow : Window +{ + ... + + [System.Runtime.InteropServices.ComImport] + [System.Runtime.InteropServices.Guid("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")] + [System.Runtime.InteropServices.InterfaceType( + System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)] + interface IDataTransferManagerInterop + { + IntPtr GetForWindow([System.Runtime.InteropServices.In] IntPtr appWindow, + [System.Runtime.InteropServices.In] ref Guid riid); + void ShowShareUIForWindow(IntPtr appWindow); + } + + static readonly Guid _dtm_iid = + new Guid(0xa5caee9b, 0x8708, 0x49d1, 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c); + + private void myButton_Click(object sender, RoutedEventArgs e) + { + // Retrieve the window handle (HWND) of the current WinUI window. + var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this); + + IDataTransferManagerInterop interop = + Windows.ApplicationModel.DataTransfer.DataTransferManager.As + (); + + IntPtr result = interop.GetForWindow(hWnd, _dtm_iid); + var dataTransferManager = WinRT.MarshalInterface + .FromAbi(result); + + dataTransferManager.DataRequested += (sender, args) => + { + args.Request.Data.Properties.Title = "In a desktop app..."; + args.Request.Data.SetText("...display WinRT UI objects that depend on CoreWindow."); + args.Request.Data.RequestedOperation = + Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy; + }; + + // Show the Share UI + interop.ShowShareUIForWindow(hWnd); + } +} +... +``` + +### WinUI with C++ + +```cppwinrt +// pch.h in a Windows App SDK app +... +#include +#include +#include +... + +// MainWindow.xaml.cpp +... +void MainWindow::myButton_Click(IInspectable const&, RoutedEventArgs const&) +{ + // Retrieve the window handle (HWND) of the current WinUI window. + auto windowNative{ this->m_inner.as<::IWindowNative>() }; + HWND hWnd{ 0 }; + windowNative->get_WindowHandle(&hWnd); + + winrt::com_ptr interop = + winrt::get_activation_factory(); + + winrt::guid _dtm_iid{ 0xa5caee9b, 0x8708, 0x49d1, { 0x8d, 0x36, 0x67, 0xd2, 0x5a, 0x8d, 0xa0, 0x0c } }; + Windows::ApplicationModel::DataTransfer::DataTransferManager dataTransferManager{ nullptr }; + interop->GetForWindow(hWnd, _dtm_iid, winrt::put_abi(dataTransferManager)); + + dataTransferManager.DataRequested([](Windows::ApplicationModel::DataTransfer::DataTransferManager const& /* sender */, + Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs const& args) + { + args.Request().Data().Properties().Title(L"In a desktop app..."); + args.Request().Data().SetText(L"...display WinRT UI objects that depend on CoreWindow."); + args.Request().Data().RequestedOperation(Windows::ApplicationModel::DataTransfer::DataPackageOperation::Copy); + }); + + interop->ShowShareUIForWindow(hWnd); +} +... +``` + +## For classes that implement IUserConsentVerifierInterop + +The [**Windows.Security.Credentials.UI.UserConsentVerifier**](/uwp/api/windows.security.credentials.ui.userconsentverifier) class implements the [**IUserConsentVerifierInterop**](/windows/win32/api/userconsentverifierinterop/nn-userconsentverifierinterop-iuserconsentverifierinterop) interface (which, like **IInitializeWithWindow**, lets you set an owner window). + +In a desktop app, instead of calling the [**UserConsentVerifier.RequestVerificationAsync**](/uwp/api/windows.security.credentials.ui.userconsentverifier.requestverificationasync) method: + +* **C#**. Call the **RequestVerificationForWindowAsync** method of the **Windows.Security.Credentials.UI.UserConsentVerifierInterop** C# interop class. For more info about the C# interop classes, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). +* **C++/WinRT**. Call [**IUserConsentVerifierInterop::RequestVerificationForWindowAsync**](/windows/win32/api/userconsentverifierinterop/nf-userconsentverifierinterop-iuserconsentverifierinterop-requestverificationforwindowasync). + +For more info, and code examples, see [**UserConsentVerifier**](/uwp/api/windows.security.credentials.ui.userconsentverifier). + +## For classes that implement other interop interfaces + +These interfaces have **XxxForWindow** methods, which let you set an owner window handle (HWND). You can use these interfaces directly from C++/WinRT. Versions of the interfaces also exist in the form of C# classes—for more details, see [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md). + +* [**IAccountsSettingsPaneInterop**](/windows/win32/api/accountssettingspaneinterop/nn-accountssettingspaneinterop-iaccountssettingspaneinterop) +* [**IDragDropManagerInterop**](/windows/win32/api/dragdropinterop/nn-dragdropinterop-idragdropmanagerinterop) +* [**IInputPaneInterop**](/windows/win32/api/inputpaneinterop/nn-inputpaneinterop-iinputpaneinterop) +* [**IPlayToManagerInterop**](/windows/win32/api/playtomanagerinterop/nn-playtomanagerinterop-iplaytomanagerinterop) +* [**IPrintManagerInterop**](/windows/win32/api/printmanagerinterop/nn-printmanagerinterop-iprintmanagerinterop) +* [**IRadialControllerConfigurationInterop**](/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerconfigurationinterop) +* **IRadialControllerIndependentInputSourceInterop** +* [**IRadialControllerInterop**](/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerinterop) +* [**ISpatialInteractionManagerInterop**](/windows/win32/api/spatialinteractionmanagerinterop/nn-spatialinteractionmanagerinterop-ispatialinteractionmanagerinterop) +* [**ISystemMediaTransportControlsInterop**](/windows/win32/api/systemmediatransportcontrolsinterop/nn-systemmediatransportcontrolsinterop-isystemmediatransportcontrolsinterop) +* [**IUIViewSettingsInterop**](/windows/win32/api/uiviewsettingsinterop/nn-uiviewsettingsinterop-iuiviewsettingsinterop) +* [**IWebAuthenticationCoreManagerInterop**](/windows/win32/api/webauthenticationcoremanagerinterop/nn-webauthenticationcoremanagerinterop-iwebauthenticationcoremanagerinterop) + +## Related topics + +* [Retrieve a window handle (HWND)](../ui-input/retrieve-hwnd.md) +* [WinUI](../../winui/winui3/index.md) +* [Windows Presentation Foundation (WPF)](/dotnet/desktop/wpf/) +* [Windows Forms (WinForms)](/dotnet/desktop/winforms/) +* [C++/WinRT](/windows/uwp/cpp-and-winrt-apis/) +* [Call interop APIs from a .NET app](../../desktop/modernize/winrt-com-interop-csharp.md) diff --git a/hub/apps/develop/ui/navigation/navigate-between-two-pages.md b/hub/apps/develop/ui/navigation/navigate-between-two-pages.md index a88087fa85..cf3b010c49 100644 --- a/hub/apps/develop/ui/navigation/navigate-between-two-pages.md +++ b/hub/apps/develop/ui/navigation/navigate-between-two-pages.md @@ -1,461 +1,461 @@ ---- -description: Learn how to enable peer-to-peer navigation between two basic pages in an Windows app. -title: "Tutorial: Implement navigation between two pages" -ms.assetid: 0A364C8B-715F-4407-9426-92267E8FB525 -label: Peer-to-peer navigation between two pages -template: detail.hbs -op-migration-status: ready -ms.date: 04/03/2025 -ms.topic: how-to -ms.localizationpriority: medium -dev_langs: -- csharp -- cppwinrt ---- - -# Tutorial: Implement navigation between two pages - -Learn how to use a frame and pages to enable basic peer-to-peer navigation in your app. - -![peer to peer navigation](../../../design/basics/images/peertopeer.png) - -Almost every app requires navigation between pages. Even a simple app with a single content page will typically have a settings page that requires navigation. In this article, we walk through the basics of adding a XAML `Page` to your app, and using a `Frame` to navigate between pages. - -> [!div class="checklist"] -> -> - **Applies to**: Windows App SDK/WinUI3 -> - **Important APIs**: [Microsoft.UI.Xaml.Controls.Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) class, [Microsoft.UI.Xaml.Controls.Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) class, [Microsoft.UI.Xaml.Navigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.navigation) namespace - -## 1. Create a blank app -To create a blank app in Visual Studio: - -1. To set up your development computer, see [Start developing Windows apps](../../../get-started/start-here.md). -1. From the Microsoft Visual Studio start window, select **Create a new project**, OR, on the Visual Studio menu, choose **File** > **New** > **Project**. -1. In the **Create a new project** dialog's drop-down filters, select **C#** or **C++**, **Windows**, and **WinUI**, respectively. -1. Select the **WinUI Blank App (Packaged)** project template, and click **Next**. That template creates a desktop app with a WinUI-based user interface. -1. In the **Project name** box, enter `BasicNavigation`, and click **Create**. -1. To run the program, choose **Debug** > **Start Debugging** from the menu, or press F5. Build and run your solution on your development computer to confirm that the app runs without errors. A blank page is displayed. -1. To stop debugging and return to Visual Studio, exit the app, or click **Stop Debugging** from the menu. -1. Remove any example code that's included in the template from the `MainWindow.xaml` and `MainWindow` code-behind files. - -## 2. Use a Frame to navigate between pages - -When your app has multiple pages, you use a [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) to navigate between them. The `Frame` class supports various navigation methods such as [Navigate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.navigate), [GoBack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.goback), and [GoForward](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.goforward), and properties such as [BackStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstack), [ForwardStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.forwardstack), and [BackStackDepth](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstackdepth). - -When you create a new Windows App SDK project in Visual Studio, the project template creates a `MainWindow` class (of type [Microsoft.UI.Xaml.Window](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window)). However, it doesn't create a [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) or [Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) and doesn't provide any navigation code. - -To enable navigation between pages, add a `Frame` as the root element of `MainWindow`. You can do that in the [Application.OnLaunched](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.onlaunched) method override in the `App.xaml` code-behind file. Open the `App` code-behind file, update the `OnLaunched` override, and handle the [NavigationFailed](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.navigationfailed) event as shown here. - -```csharp -// App.xaml.cs - -protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) -{ - m_window = new MainWindow(); - - // Create a Frame to act as the navigation context and navigate to the first page - Frame rootFrame = new Frame(); - rootFrame.NavigationFailed += OnNavigationFailed; - // Navigate to the first page, configuring the new page - // by passing required information as a navigation parameter - rootFrame.Navigate(typeof(MainPage), args.Arguments); - - // Place the frame in the current Window - m_window.Content = rootFrame; - // Ensure the MainWindow is active - m_window.Activate(); -} - -void OnNavigationFailed(object sender, NavigationFailedEventArgs e) -{ - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); -} -``` - -```cppwinrt -// App.xaml.h - -// Add after OnLaunched declaration. -void OnNavigationFailed(IInspectable const&, Microsoft::UI::Xaml::Navigation::NavigationFailedEventArgs const&); - -/////////////// -// App.xaml.cpp - -void App::OnLaunched(LaunchActivatedEventArgs const& e) -{ - window = make(); - Frame rootFrame = Frame(); - rootFrame.NavigationFailed({ this, &App::OnNavigationFailed }); - rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); - window.Content(rootFrame); - window.Activate(); -} - -void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e) -{ - throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name); -} -``` - -> [!NOTE] -> For apps with more complex navigation, you will typically use a [NavigationView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationview) as the root of MainWindow, and place a `Frame` as the content of the navigation view. For more info, see [Navigation view](../controls/navigationview.md). - -The [Navigate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.navigate) method is used to display content in this `Frame`. Here, `MainPage.xaml` is passed to the `Navigate` method, so the method loads `MainPage` in the `Frame`. - -If the navigation to the app's initial window fails, a `NavigationFailed` event occurs, and this code throws an exception in the event handler. - -## 3. Add basic pages - -The **Blank App** template doesn't create multiple app pages for you. Before you can navigate between pages, you need to add some pages to your app. - -To add a new item to your app: - -1. In **Solution Explorer**, right-click the `BasicNavigation` project node to open the context menu. -1. Choose **Add** > **New Item** from the context menu. -1. In the **Add New Item** dialog box, select the **WinUI** node in the left pane, then choose **Blank Page** in the middle pane. -1. In the **Name** box, enter `MainPage` and press the **Add** button. -1. Repeat steps 1-4 to add the second page, but in the **Name** box, enter `Page2`. - -Now, these files should be listed as part of your `BasicNavigation` project. - - - - - - - - - - - - - - -
C#C++
    -
  • MainPage.xaml
  • -
  • MainPage.xaml.cs
  • -
  • Page2.xaml
  • -
  • Page2.xaml.cs
  • -
    -
  • MainPage.xaml
  • -
  • MainPage.xaml.cpp
  • -
  • MainPage.xaml.h
  • -
  • Page2.xaml
  • -
  • Page2.xaml.cpp
  • -
  • Page2.xaml.h -
  • -
- -> [!IMPORTANT] -> **For C++ projects**, you must add a `#include` directive in the header file of each page that references another page. For the inter-page navigation example presented here, **MainPage.xaml.h** file contains `#include "Page2.xaml.h"`, in turn, **Page2.xaml.h** contains `#include "MainPage.xaml.h"`. -> -> C++ page templates also include an example `Button` and click handler code that you will need to remove from the XAML and code-behind files for the page. - -### Add content to the pages - -In `MainPage.xaml`, replace the existing page content with the following content: - -```xaml - - - - -``` - -This XAML adds: - -- A [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock) element named `pageTitle` with its [Text](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock.text) property set to `Main Page` as a child element of the root [Grid](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.Grid). -- A [HyperlinkButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton) element that is used to navigate to the next page as a child element of the root [Grid](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid). - -In the `MainPage` code-behind file, add the following code to handle the `Click` event of the [HyperlinkButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton) you added to enable navigation to `Page2.xaml`. - -```csharp -// MainPage.xaml.cs - -private void HyperlinkButton_Click(object sender, RoutedEventArgs e) -{ - Frame.Navigate(typeof(Page2)); -} -``` - -```cppwinrt -// pch.h -// Add this include in pch.h to support winrt::xaml_typename - -#include - -//////////////////// -// MainPage.xaml.h - -void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); - -//////////////////// -// MainPage.xaml.cpp - -void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) -{ - Frame().Navigate(winrt::xaml_typename()); -} -``` - -`MainPage` is a subclass of the [Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) class. The `Page` class has a read-only [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.frame) property that gets the `Frame` containing the `Page`. When the `Click` event handler of the `HyperlinkButton` in `MainPage` calls `Frame.Navigate(typeof(Page2))`, the `Frame` displays the content of `Page2.xaml`. - -Whenever a page is loaded into the frame, that page is added as a [PageStackEntry](/uwp/api/Windows.UI.Xaml.Navigation.PageStackEntry) to the [BackStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstack) or [ForwardStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.forwardstack) of the [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.frame), allowing for [history and backwards navigation](navigation-history-and-backwards-navigation.md). - -Now, do the same in `Page2.xaml`. Replace the existing page content with the following content: - -```xaml - - - - -``` - -In the `Page2` code-behind file, add the following code to handle the `Click` event of the [HyperlinkButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton) to navigate to `MainPage.xaml`. - -```csharp -// Page2.xaml.cs - -private void HyperlinkButton_Click(object sender, RoutedEventArgs e) -{ - Frame.Navigate(typeof(MainPage)); -} -``` - -```cppwinrt -// Page2.xaml.h - -void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); - -///////////////// -// Page2.xaml.cpp - -void winrt::BasicNavigation::implementation::Page2::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) -{ - Frame().Navigate(winrt::xaml_typename()); -} -``` - -Build and run the app. Click the link that says "Click to go to page 2". The second page that says "Page 2" at the top should be loaded and displayed in the frame. Now click the link on Page 2 to go back to Main Page. - -## 4. Pass information between pages - -Your app now navigates between two pages, but it really doesn't do anything interesting yet. Often, when an app has multiple pages, the pages need to share information. Now you'll pass some information from the first page to the second page. - -In `MainPage.xaml`, replace the `HyperlinkButton` you added earlier with the following [StackPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.StackPanel). This adds a [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.TextBlock) label and a [TextBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.TextBox) `name` for entering a text string. - -```xaml - - - - - -``` - -Now you'll use the second overload of the `Navigate` method and pass the text from the text box as the second parameter. Here's the signature of this `Navigate` overload: - -```csharp -public bool Navigate(System.Type sourcePageType, object parameter); -``` - -```cppwinrt -bool Navigate(TypeName const& sourcePageType, IInspectable const& parameter); -``` - -In the `HyperlinkButton_Click` event handler of the `MainPage` code-behind file, add a second parameter to the `Navigate` method that references the `Text` property of the `name` text box. - -```csharp -// MainPage.xaml.cs - -private void HyperlinkButton_Click(object sender, RoutedEventArgs e) -{ - Frame.Navigate(typeof(Page2), name.Text); -} -``` - -```cppwinrt -// MainPage.xaml.cpp - -void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) -{ - Frame().Navigate(xaml_typename(), winrt::box_value(name().Text())); -} -``` - -In `Page2.xaml`, replace the `HyperlinkButton` you added earlier with the following `StackPanel`. This adds a [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.TextBlock) for displaying the text string passed from `MainPage`. - -```xaml - - - - -``` - -In the `Page2` code-behind file, add the following code to override the `OnNavigatedTo` method: - -```csharp -// Page2.xaml.cs - -protected override void OnNavigatedTo(NavigationEventArgs e) -{ - if (e.Parameter is string && !string.IsNullOrWhiteSpace((string)e.Parameter)) - { - greeting.Text = $"Hello, {e.Parameter.ToString()}"; - } - else - { - greeting.Text = "Hello!"; - } - base.OnNavigatedTo(e); -} -``` - -```cppwinrt -// Page2.xaml.h - -void Page2::OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e) -{ - auto propertyValue{ e.Parameter().as() }; - if (propertyValue.Type() == Windows::Foundation::PropertyType::String) - { - auto name{ winrt::unbox_value(e.Parameter()) }; - if (!name.empty()) - { - greeting().Text(L"Hello, " + name); - __super::OnNavigatedTo(e); - return; - } - } - greeting().Text(L"Hello!"); - __super::OnNavigatedTo(e); -} -``` - -Run the app, type your name in the text box, and then click the link that says `Click to go to page 2`. - -When the `Click` event of the `HyperlinkButton` in `MainPage` calls `Frame.Navigate(typeof(Page2), name.Text)`, the `name.Text` property is passed to `Page2`, and the value from the event data is used for the message displayed on the page. - -## 5. Cache a page - -Page content and state is not cached by default, so if you'd like to cache information, you must enable it in each page of your app. - -In our basic peer-to-peer example, when you click the `Click to go to page 1` link on `Page2`, the `TextBox` (and any other field) on `MainPage` is set to its default state. One way to work around this is to use the [NavigationCacheMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.navigationcachemode) property to specify that a page be added to the frame's page cache. - -By default, a new page instance is created with its default values every time navigation occurs. In `MainPage.xaml`, set `NavigationCacheMode` to `Enabled` (in the opening `Page` tag) to cache the page and retain all content and state values for the page until the page cache for the frame is exceeded. Set [NavigationCacheMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.navigationcachemode) to [Required](/uwp/api/Windows.UI.Xaml.Navigation.NavigationCacheMode) if you want to ignore [CacheSize](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.cachesize) limits, which specify the number of pages in the navigation history that can be cached for the frame. However, keep in mind that cache size limits might be crucial, depending on the memory limits of a device. - -```xaml - -``` - -Now, when you click back to main page, the name you entered in the text box is still there. - -## 6. Customize page transition animations - -By default, each page is animated into the frame when navigation occurs. The default animation is an "entrance" animation that causes the page to slide up from the bottom of the window. However, you can choose different animation options that better suit the navigation of your app. For example, you can use a "drill in" animation to give the feeling that the user is going deeper into your app, or a horizontal slide animation to give the feeling that two pages are peers. For more info, see [Page transitions](../../motion/page-transitions.md). - -These animations are represented by sub-classes of [NavigationTransitionInfo](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.navigationtransitioninfo). To specify the animation to use for a page transition, you'll use the third overload of the `Navigate` method and pass a `NavigationTransitionInfo` sub-class as the third parameter (`infoOverride`). Here's the signature of this `Navigate` overload: - -```csharp -public bool Navigate(System.Type sourcePageType, - object parameter, - NavigationTransitionInfo infoOverride); -``` - -```cppwinrt -bool Navigate(TypeName const& sourcePageType, - IInspectable const& parameter, - NavigationTransitionInfo const& infoOverride); -``` - -In the `HyperlinkButton_Click` event handler of the `MainPage` code-behind file, add a third parameter to the `Navigate` method that sets the `infoOverride` parameter to a [SlideNavigationTransitionInfo](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo) with its [Effect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo.effect) property set to [FromRight](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioneffect). - -```csharp -// MainPage.xaml.cs - -private void HyperlinkButton_Click(object sender, RoutedEventArgs e) -{ - Frame.Navigate(typeof(Page2), - name.Text, - new SlideNavigationTransitionInfo() - { Effect = SlideNavigationTransitionEffect.FromRight}); -} -``` - -```cppwinrt -// pch.h - -#include - -//////////////////// -// MainPage.xaml.cpp - -using namespace winrt::Microsoft::UI::Xaml::Media::Animation; - -// ... - -void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) -{ - // Create the slide transition and set the transition effect to FromRight. - SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo(); - slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromRight)); - Frame().Navigate(winrt::xaml_typename(), - winrt::box_value(name().Text()), - slideEffect); -} -``` - -In the `HyperlinkButton_Click` event handler of the `Page2` code-behind file, set the `infoOverride` parameter to a [SlideNavigationTransitionInfo](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo) with its [Effect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo.effect) property set to [FromLeft](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioneffect). - - - -```csharp -// Page2.xaml.cs - -private void HyperlinkButton_Click(object sender, RoutedEventArgs e) -{ - Frame.Navigate(typeof(MainPage), - null, - new SlideNavigationTransitionInfo() - { Effect = SlideNavigationTransitionEffect.FromLeft}); -} -``` - -```cppwinrt -// Page2.xaml.cpp - -using namespace winrt::Microsoft::UI::Xaml::Media::Animation; - -// ... - -void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) -{ - // Create the slide transition and set the transition effect to FromLeft. - SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo(); - slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromLeft)); - Frame().Navigate(winrt::xaml_typename(), - nullptr, - slideEffect); -} -``` - -Now, when you navigate between pages, the pages slide left and right, which provides a more natural feeling for this transition and reinforces the connection between the pages. - -## Related articles - -- [Navigation design basics for Windows apps](../../../design/basics/navigation-basics.md) -- [Navigation view](../controls/navigationview.md) -- [Navigation history and backwards navigation](navigation-history-and-backwards-navigation.md) +--- +description: Learn how to enable peer-to-peer navigation between two basic pages in an Windows app. +title: "Tutorial: Implement navigation between two pages" +ms.assetid: 0A364C8B-715F-4407-9426-92267E8FB525 +label: Peer-to-peer navigation between two pages +template: detail.hbs +op-migration-status: ready +ms.date: 04/03/2025 +ms.topic: how-to +ms.localizationpriority: medium +dev_langs: +- csharp +- cppwinrt +--- + +# Tutorial: Implement navigation between two pages + +Learn how to use a frame and pages to enable basic peer-to-peer navigation in your app. + +![peer to peer navigation](../../../design/basics/images/peertopeer.png) + +Almost every app requires navigation between pages. Even a simple app with a single content page will typically have a settings page that requires navigation. In this article, we walk through the basics of adding a XAML `Page` to your app, and using a `Frame` to navigate between pages. + +> [!div class="checklist"] +> +> - **Applies to**: Windows App SDK/WinUI3 +> - **Important APIs**: [Microsoft.UI.Xaml.Controls.Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) class, [Microsoft.UI.Xaml.Controls.Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) class, [Microsoft.UI.Xaml.Navigation](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.navigation) namespace + +## 1. Create a blank app +To create a blank app in Visual Studio: + +1. To set up your development computer, see [Start developing Windows apps](../../../get-started/start-here.md). +1. From the Microsoft Visual Studio start window, select **Create a new project**, OR, on the Visual Studio menu, choose **File** > **New** > **Project**. +1. In the **Create a new project** dialog's drop-down filters, select **C#** or **C++**, **Windows**, and **WinUI**, respectively. +1. Select the **WinUI Blank App (Packaged)** project template, and click **Next**. That template creates a desktop app with a WinUI-based user interface. +1. In the **Project name** box, enter `BasicNavigation`, and click **Create**. +1. To run the program, choose **Debug** > **Start Debugging** from the menu, or press F5. Build and run your solution on your development computer to confirm that the app runs without errors. A blank page is displayed. +1. To stop debugging and return to Visual Studio, exit the app, or click **Stop Debugging** from the menu. +1. Remove any example code that's included in the template from the `MainWindow.xaml` and `MainWindow` code-behind files. + +## 2. Use a Frame to navigate between pages + +When your app has multiple pages, you use a [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) to navigate between them. The `Frame` class supports various navigation methods such as [Navigate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.navigate), [GoBack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.goback), and [GoForward](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.goforward), and properties such as [BackStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstack), [ForwardStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.forwardstack), and [BackStackDepth](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstackdepth). + +When you create a new Windows App SDK project in Visual Studio, the project template creates a `MainWindow` class (of type [Microsoft.UI.Xaml.Window](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window)). However, it doesn't create a [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) or [Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) and doesn't provide any navigation code. + +To enable navigation between pages, add a `Frame` as the root element of `MainWindow`. You can do that in the [Application.OnLaunched](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.onlaunched) method override in the `App.xaml` code-behind file. Open the `App` code-behind file, update the `OnLaunched` override, and handle the [NavigationFailed](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.navigationfailed) event as shown here. + +```csharp +// App.xaml.cs + +protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) +{ + m_window = new MainWindow(); + + // Create a Frame to act as the navigation context and navigate to the first page + Frame rootFrame = new Frame(); + rootFrame.NavigationFailed += OnNavigationFailed; + // Navigate to the first page, configuring the new page + // by passing required information as a navigation parameter + rootFrame.Navigate(typeof(MainPage), args.Arguments); + + // Place the frame in the current Window + m_window.Content = rootFrame; + // Ensure the MainWindow is active + m_window.Activate(); +} + +void OnNavigationFailed(object sender, NavigationFailedEventArgs e) +{ + throw new Exception("Failed to load Page " + e.SourcePageType.FullName); +} +``` + +```cppwinrt +// App.xaml.h + +// Add after OnLaunched declaration. +void OnNavigationFailed(IInspectable const&, Microsoft::UI::Xaml::Navigation::NavigationFailedEventArgs const&); + +/////////////// +// App.xaml.cpp + +void App::OnLaunched(LaunchActivatedEventArgs const& e) +{ + window = make(); + Frame rootFrame = Frame(); + rootFrame.NavigationFailed({ this, &App::OnNavigationFailed }); + rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); + window.Content(rootFrame); + window.Activate(); +} + +void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e) +{ + throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name); +} +``` + +> [!NOTE] +> For apps with more complex navigation, you will typically use a [NavigationView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.navigationview) as the root of MainWindow, and place a `Frame` as the content of the navigation view. For more info, see [Navigation view](../controls/navigationview.md). + +The [Navigate](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.navigate) method is used to display content in this `Frame`. Here, `MainPage.xaml` is passed to the `Navigate` method, so the method loads `MainPage` in the `Frame`. + +If the navigation to the app's initial window fails, a `NavigationFailed` event occurs, and this code throws an exception in the event handler. + +## 3. Add basic pages + +The **Blank App** template doesn't create multiple app pages for you. Before you can navigate between pages, you need to add some pages to your app. + +To add a new item to your app: + +1. In **Solution Explorer**, right-click the `BasicNavigation` project node to open the context menu. +1. Choose **Add** > **New Item** from the context menu. +1. In the **Add New Item** dialog box, select the **WinUI** node in the left pane, then choose **Blank Page** in the middle pane. +1. In the **Name** box, enter `MainPage` and press the **Add** button. +1. Repeat steps 1-4 to add the second page, but in the **Name** box, enter `Page2`. + +Now, these files should be listed as part of your `BasicNavigation` project. + + + + + + + + + + + + + + +
C#C++
    +
  • MainPage.xaml
  • +
  • MainPage.xaml.cs
  • +
  • Page2.xaml
  • +
  • Page2.xaml.cs
  • +
    +
  • MainPage.xaml
  • +
  • MainPage.xaml.cpp
  • +
  • MainPage.xaml.h
  • +
  • Page2.xaml
  • +
  • Page2.xaml.cpp
  • +
  • Page2.xaml.h +
  • +
+ +> [!IMPORTANT] +> **For C++ projects**, you must add a `#include` directive in the header file of each page that references another page. For the inter-page navigation example presented here, **MainPage.xaml.h** file contains `#include "Page2.xaml.h"`, in turn, **Page2.xaml.h** contains `#include "MainPage.xaml.h"`. +> +> C++ page templates also include an example `Button` and click handler code that you will need to remove from the XAML and code-behind files for the page. + +### Add content to the pages + +In `MainPage.xaml`, replace the existing page content with the following content: + +```xaml + + + + +``` + +This XAML adds: + +- A [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock) element named `pageTitle` with its [Text](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock.text) property set to `Main Page` as a child element of the root [Grid](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.Grid). +- A [HyperlinkButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton) element that is used to navigate to the next page as a child element of the root [Grid](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid). + +In the `MainPage` code-behind file, add the following code to handle the `Click` event of the [HyperlinkButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton) you added to enable navigation to `Page2.xaml`. + +```csharp +// MainPage.xaml.cs + +private void HyperlinkButton_Click(object sender, RoutedEventArgs e) +{ + Frame.Navigate(typeof(Page2)); +} +``` + +```cppwinrt +// pch.h +// Add this include in pch.h to support winrt::xaml_typename + +#include + +//////////////////// +// MainPage.xaml.h + +void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + +//////////////////// +// MainPage.xaml.cpp + +void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + Frame().Navigate(winrt::xaml_typename()); +} +``` + +`MainPage` is a subclass of the [Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) class. The `Page` class has a read-only [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.frame) property that gets the `Frame` containing the `Page`. When the `Click` event handler of the `HyperlinkButton` in `MainPage` calls `Frame.Navigate(typeof(Page2))`, the `Frame` displays the content of `Page2.xaml`. + +Whenever a page is loaded into the frame, that page is added as a [PageStackEntry](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.navigation.pagestackentry) to the [BackStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstack) or [ForwardStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.forwardstack) of the [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.frame), allowing for [history and backwards navigation](navigation-history-and-backwards-navigation.md). + +Now, do the same in `Page2.xaml`. Replace the existing page content with the following content: + +```xaml + + + + +``` + +In the `Page2` code-behind file, add the following code to handle the `Click` event of the [HyperlinkButton](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.hyperlinkbutton) to navigate to `MainPage.xaml`. + +```csharp +// Page2.xaml.cs + +private void HyperlinkButton_Click(object sender, RoutedEventArgs e) +{ + Frame.Navigate(typeof(MainPage)); +} +``` + +```cppwinrt +// Page2.xaml.h + +void HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e); + +///////////////// +// Page2.xaml.cpp + +void winrt::BasicNavigation::implementation::Page2::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + Frame().Navigate(winrt::xaml_typename()); +} +``` + +Build and run the app. Click the link that says "Click to go to page 2". The second page that says "Page 2" at the top should be loaded and displayed in the frame. Now click the link on Page 2 to go back to Main Page. + +## 4. Pass information between pages + +Your app now navigates between two pages, but it really doesn't do anything interesting yet. Often, when an app has multiple pages, the pages need to share information. Now you'll pass some information from the first page to the second page. + +In `MainPage.xaml`, replace the `HyperlinkButton` you added earlier with the following [StackPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.StackPanel). This adds a [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.TextBlock) label and a [TextBox](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.TextBox) `name` for entering a text string. + +```xaml + + + + + +``` + +Now you'll use the second overload of the `Navigate` method and pass the text from the text box as the second parameter. Here's the signature of this `Navigate` overload: + +```csharp +public bool Navigate(System.Type sourcePageType, object parameter); +``` + +```cppwinrt +bool Navigate(TypeName const& sourcePageType, IInspectable const& parameter); +``` + +In the `HyperlinkButton_Click` event handler of the `MainPage` code-behind file, add a second parameter to the `Navigate` method that references the `Text` property of the `name` text box. + +```csharp +// MainPage.xaml.cs + +private void HyperlinkButton_Click(object sender, RoutedEventArgs e) +{ + Frame.Navigate(typeof(Page2), name.Text); +} +``` + +```cppwinrt +// MainPage.xaml.cpp + +void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + Frame().Navigate(xaml_typename(), winrt::box_value(name().Text())); +} +``` + +In `Page2.xaml`, replace the `HyperlinkButton` you added earlier with the following `StackPanel`. This adds a [TextBlock](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.TextBlock) for displaying the text string passed from `MainPage`. + +```xaml + + + + +``` + +In the `Page2` code-behind file, add the following code to override the `OnNavigatedTo` method: + +```csharp +// Page2.xaml.cs + +protected override void OnNavigatedTo(NavigationEventArgs e) +{ + if (e.Parameter is string && !string.IsNullOrWhiteSpace((string)e.Parameter)) + { + greeting.Text = $"Hello, {e.Parameter.ToString()}"; + } + else + { + greeting.Text = "Hello!"; + } + base.OnNavigatedTo(e); +} +``` + +```cppwinrt +// Page2.xaml.h + +void Page2::OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e) +{ + auto propertyValue{ e.Parameter().as() }; + if (propertyValue.Type() == Windows::Foundation::PropertyType::String) + { + auto name{ winrt::unbox_value(e.Parameter()) }; + if (!name.empty()) + { + greeting().Text(L"Hello, " + name); + __super::OnNavigatedTo(e); + return; + } + } + greeting().Text(L"Hello!"); + __super::OnNavigatedTo(e); +} +``` + +Run the app, type your name in the text box, and then click the link that says `Click to go to page 2`. + +When the `Click` event of the `HyperlinkButton` in `MainPage` calls `Frame.Navigate(typeof(Page2), name.Text)`, the `name.Text` property is passed to `Page2`, and the value from the event data is used for the message displayed on the page. + +## 5. Cache a page + +Page content and state is not cached by default, so if you'd like to cache information, you must enable it in each page of your app. + +In our basic peer-to-peer example, when you click the `Click to go to page 1` link on `Page2`, the `TextBox` (and any other field) on `MainPage` is set to its default state. One way to work around this is to use the [NavigationCacheMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.navigationcachemode) property to specify that a page be added to the frame's page cache. + +By default, a new page instance is created with its default values every time navigation occurs. In `MainPage.xaml`, set `NavigationCacheMode` to `Enabled` (in the opening `Page` tag) to cache the page and retain all content and state values for the page until the page cache for the frame is exceeded. Set [NavigationCacheMode](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page.navigationcachemode) to [Required](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.navigation.navigationcachemode) if you want to ignore [CacheSize](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.cachesize) limits, which specify the number of pages in the navigation history that can be cached for the frame. However, keep in mind that cache size limits might be crucial, depending on the memory limits of a device. + +```xaml + +``` + +Now, when you click back to main page, the name you entered in the text box is still there. + +## 6. Customize page transition animations + +By default, each page is animated into the frame when navigation occurs. The default animation is an "entrance" animation that causes the page to slide up from the bottom of the window. However, you can choose different animation options that better suit the navigation of your app. For example, you can use a "drill in" animation to give the feeling that the user is going deeper into your app, or a horizontal slide animation to give the feeling that two pages are peers. For more info, see [Page transitions](../../motion/page-transitions.md). + +These animations are represented by sub-classes of [NavigationTransitionInfo](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.navigationtransitioninfo). To specify the animation to use for a page transition, you'll use the third overload of the `Navigate` method and pass a `NavigationTransitionInfo` sub-class as the third parameter (`infoOverride`). Here's the signature of this `Navigate` overload: + +```csharp +public bool Navigate(System.Type sourcePageType, + object parameter, + NavigationTransitionInfo infoOverride); +``` + +```cppwinrt +bool Navigate(TypeName const& sourcePageType, + IInspectable const& parameter, + NavigationTransitionInfo const& infoOverride); +``` + +In the `HyperlinkButton_Click` event handler of the `MainPage` code-behind file, add a third parameter to the `Navigate` method that sets the `infoOverride` parameter to a [SlideNavigationTransitionInfo](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo) with its [Effect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo.effect) property set to [FromRight](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioneffect). + +```csharp +// MainPage.xaml.cs + +private void HyperlinkButton_Click(object sender, RoutedEventArgs e) +{ + Frame.Navigate(typeof(Page2), + name.Text, + new SlideNavigationTransitionInfo() + { Effect = SlideNavigationTransitionEffect.FromRight}); +} +``` + +```cppwinrt +// pch.h + +#include + +//////////////////// +// MainPage.xaml.cpp + +using namespace winrt::Microsoft::UI::Xaml::Media::Animation; + +// ... + +void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + // Create the slide transition and set the transition effect to FromRight. + SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo(); + slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromRight)); + Frame().Navigate(winrt::xaml_typename(), + winrt::box_value(name().Text()), + slideEffect); +} +``` + +In the `HyperlinkButton_Click` event handler of the `Page2` code-behind file, set the `infoOverride` parameter to a [SlideNavigationTransitionInfo](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo) with its [Effect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioninfo.effect) property set to [FromLeft](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.animation.slidenavigationtransitioneffect). + + + +```csharp +// Page2.xaml.cs + +private void HyperlinkButton_Click(object sender, RoutedEventArgs e) +{ + Frame.Navigate(typeof(MainPage), + null, + new SlideNavigationTransitionInfo() + { Effect = SlideNavigationTransitionEffect.FromLeft}); +} +``` + +```cppwinrt +// Page2.xaml.cpp + +using namespace winrt::Microsoft::UI::Xaml::Media::Animation; + +// ... + +void winrt::BasicNavigation::implementation::MainPage::HyperlinkButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e) +{ + // Create the slide transition and set the transition effect to FromLeft. + SlideNavigationTransitionInfo slideEffect = SlideNavigationTransitionInfo(); + slideEffect.Effect(SlideNavigationTransitionEffect(SlideNavigationTransitionEffect::FromLeft)); + Frame().Navigate(winrt::xaml_typename(), + nullptr, + slideEffect); +} +``` + +Now, when you navigate between pages, the pages slide left and right, which provides a more natural feeling for this transition and reinforces the connection between the pages. + +## Related articles + +- [Navigation design basics for Windows apps](../../../design/basics/navigation-basics.md) +- [Navigation view](../controls/navigationview.md) +- [Navigation history and backwards navigation](navigation-history-and-backwards-navigation.md) diff --git a/hub/apps/develop/ui/navigation/navigation-history-and-backwards-navigation.md b/hub/apps/develop/ui/navigation/navigation-history-and-backwards-navigation.md index 04e31bb417..e4b7758aff 100644 --- a/hub/apps/develop/ui/navigation/navigation-history-and-backwards-navigation.md +++ b/hub/apps/develop/ui/navigation/navigation-history-and-backwards-navigation.md @@ -1,178 +1,178 @@ ---- -description: Learn how to implement backwards navigation for traversing the user's navigation history within a Windows app. -title: Navigation history and backwards navigation -template: detail.hbs -op-migration-status: ready -ms.date: 04/10/2025 -ms.topic: article -ms.localizationpriority: medium -dev_langs: -- csharp -- cppwinrt ---- -# Navigation history and backwards navigation for Windows apps - -> [!div class="checklist"] -> -> - **Applies to**: Windows App SDK/WinUI3 -> - **Important APIs**: [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) class, [Page](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page) class, [Frame.GoBack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.goback) method - -To implement backwards navigation in your app, place a back button at the top left corner of your app's UI. The user expects the back button to navigate to the previous location in the app's navigation history. By default, the [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) control records navigation actions in its [BackStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.backstack) and [ForwardStack](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame.forwardstack). However, you can modify which navigation actions are added to the navigation history. - -> [!NOTE] ->For most apps that have multiple pages, we recommend that you use the [NavigationView](../controls/navigationview.md) control to provide the navigation framework for your app. It adapts to a variety of screen sizes and supports both _top_ and _left_ navigation styles. If your app uses the `NavigationView` control, then you can use [NavigationView's built-in back button](../controls/navigationview.md#backwards-navigation). -> -> The guidelines and examples in this article should be used when you implement navigation without using the `NavigationView` control. If you use `NavigationView`, this information provides useful background knowledge, but you should use the specific guidance and examples in the [NavigationView](../controls/navigationview.md) article - -## Back button - -We recommend that you place the back button in the upper left corner of your app. If you [customize the title bar](../../title-bar.md), place the back button in the title bar. See [Title bar design > Back button](/windows/apps/design/basics/titlebar-design#back-button) for more info. - -If you use the [TitleBar](../controls/title-bar.md) control to create a custom title bar, use the built-in back button. Set [IsBackButtonVisible](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.titlebar.isbackbuttonvisible) to `true`, set [IsBackButtonEnabled](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.titlebar.isbackbuttonenabled) as needed, and handle the [BackRequested](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.titlebar.backrequested) event to navigate. - -To create a stand-alone back button, use the [Button](../controls/buttons.md) control with the `TitleBarBackButtonStyle` resource, and place the button at the top left hand corner of your app's UI (for details, see the XAML code examples below). - -![Back button in the top left of the app's UI](../../../design/basics/images/back-nav/back-enabled.png) - -```xaml - - - - - - - -