diff --git a/hub/apps/design/accessibility/custom-automation-peers.md b/hub/apps/design/accessibility/custom-automation-peers.md index 6cf6d02295..f2d4a0e61f 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..1cf401b247 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 @@ -42,14 +42,14 @@ If your app has images that must be mirrored (that is, the same image can be fli If your app requires a different image to flip the image correctly, then you can use the resource management system with the `LayoutDirection` qualifier (see the LayoutDirection section of [Tailor your resources for language, scale, and other qualifiers](/windows/apps/windows-app-sdk/mrtcore/tailor-resources-lang-scale-contrast#layoutdirection)). The system chooses an image named `file.layoutdir-rtl.png` when the app runtime language (see [Understand user profile languages and app manifest languages](manage-language-and-region.md)) is set to an RTL language. This approach may be necessary when some part of the image is flipped, but another part isn't. ## Handling right-to-left (RTL) languages -When your app is localized for right-to-left (RTL) languages, use the [**FrameworkElement.FlowDirection**](/uwp/api/Windows.UI.Xaml.FrameworkElement.FlowDirection) property, and set symmetrical padding and margins. Layout panels such as [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid?branch=live) scale and flip automatically with the value of **FlowDirection** that you set. +When your app is localized for right-to-left (RTL) languages, use the [**FrameworkElement.FlowDirection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.flowdirection) property, and set symmetrical padding and margins. Layout panels such as [**Grid**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid?branch=live) scale and flip automatically with the value of **FlowDirection** that you set. Set **FlowDirection** on the root layout panel (or frame) of your Page, or on the Page itself. This causes all of the controls contained within to inherit that property. > [!IMPORTANT] > However, **FlowDirection** is *not* set automatically based on the user's selected display language in Windows settings; nor does it change dynamically in response to the user switching display language. If the user switches Windows settings from English to Arabic, for example, then the **FlowDirection** property will *not* automatically change from left-to-right to right-to-left. As the app developer, you have to set **FlowDirection** appropriately for the language that you are currently displaying. -The programmatic technique is to use the `LayoutDirection` property of the preferred user display language to set the [**FlowDirection**](/uwp/api/Windows.UI.Xaml.FrameworkElement.FlowDirection) property (see the code example below). Most controls included in Windows use **FlowDirection** already. If you're implementing a custom control, it should use **FlowDirection** to make appropriate layout changes for RTL and LTR languages. +The programmatic technique is to use the `LayoutDirection` property of the preferred user display language to set the [**FlowDirection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.flowdirection) property (see the code example below). Most controls included in Windows use **FlowDirection** already. If you're implementing a custom control, it should use **FlowDirection** to make appropriate layout changes for RTL and LTR languages. ```csharp this.languageTag = Windows.Globalization.ApplicationLanguages.Languages[0]; @@ -114,7 +114,7 @@ First, in your app's Resources File (.resw), add a property identifier with the Instead of a single line of code for all languages, this depends on the translator "translating" this property resource correctly for each translated language; so be aware that there's that extra opportunity for human error when you use this technique. ## Important APIs -* [FrameworkElement.FlowDirection](/uwp/api/Windows.UI.Xaml.FrameworkElement.FlowDirection) +* [FrameworkElement.FlowDirection](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.flowdirection) * [LanguageFont](/uwp/api/Windows.Globalization.Fonts.LanguageFont?branch=live) ## Related topics diff --git a/hub/apps/design/layout/attached-layouts.md b/hub/apps/design/layout/attached-layouts.md index ec27d0d391..35b914e14e 100644 --- a/hub/apps/design/layout/attached-layouts.md +++ b/hub/apps/design/layout/attached-layouts.md @@ -20,15 +20,15 @@ In this topic, we cover what's involved in creating an attached layout (virtuali > **Important APIs**: -> * [ScrollViewer](/uwp/api/windows.ui.xaml.controls.scrollviewer) +> * [ScrollViewer](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollviewer) > * [ItemsRepeater](../controls/items-repeater.md) -> * [Layout](/uwp/api/microsoft.ui.xaml.controls.layout) -> * [NonVirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayout) -> * [VirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout) -> * [LayoutContext](/uwp/api/microsoft.ui.xaml.controls.layoutcontext) -> * [NonVirtualizingLayoutContext](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayoutcontext) -> * [VirtualizingLayoutContext](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext) -> * [LayoutPanel](/uwp/api/microsoft.ui.xaml.controls.layoutpanel) (Preview) +> * [Layout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layout) +> * [NonVirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayout) +> * [VirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout) +> * [LayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutcontext) +> * [NonVirtualizingLayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayoutcontext) +> * [VirtualizingLayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext) +> * [LayoutPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutpanel) (Preview) ## Key Concepts @@ -42,7 +42,7 @@ XAML's layout system, which answers these questions, is briefly covered as part ### Containers and Context -Conceptually, XAML's [Panel](/uwp/api/windows.ui.xaml.controls.panel) fills two important roles in the framework: +Conceptually, XAML's [Panel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) fills two important roles in the framework: 1. It can contain child elements and introduces branching in the tree of elements. 2. It applies a specific layout strategy to those children. @@ -52,13 +52,13 @@ For this reason, a Panel in XAML has often been synonymous with layout, but tech The [ItemsRepeater](../controls/items-repeater.md) also behaves like Panel, but, unlike Panel, it does not expose a Children property that would allow programmatically adding or removing UIElement children. Instead, the lifetime of its children are automatically managed by the framework to correspond to a collection of data items. Although it is not derived from Panel, it behaves and is treated by the framework like a Panel. > [!NOTE] -> The [LayoutPanel](/uwp/api/microsoft.ui.xaml.controls.layoutpanel) is a container, derived from Panel, that delegates its logic to the attached [Layout](/uwp/api/microsoft.ui.xaml.controls.layoutpanel.layout) object. LayoutPanel is in *Preview* and is currently available only in the *Prerelease* drops of the WinUI 3 package. +> The [LayoutPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutpanel) is a container, derived from Panel, that delegates its logic to the attached [Layout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutpanel.layout) object. LayoutPanel is in *Preview* and is currently available only in the *Prerelease* drops of the WinUI 3 package. #### Containers -Conceptually, [Panel](/uwp/api/windows.ui.xaml.controls.panel) is a container of elements that also has the ability to render pixels for a [Background](/uwp/api/windows.ui.xaml.controls.panel.background). Panels provide a way to encapsulate common layout logic in an easy to use package. +Conceptually, [Panel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) is a container of elements that also has the ability to render pixels for a [Background](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.background). Panels provide a way to encapsulate common layout logic in an easy to use package. -The concept of **attached layout** makes the distinction between the two roles of container and layout more clear. If the container delegates its layout logic to another object we would call that object the attached layout as seen in the snippet below. Containers that inherit from [FrameworkElement](/uwp/api/windows.ui.xaml.frameworkelement), such as the LayoutPanel, automatically expose the common properties that provide input to XAML's layout process (for example, Height and Width). +The concept of **attached layout** makes the distinction between the two roles of container and layout more clear. If the container delegates its layout logic to another object we would call that object the attached layout as seen in the snippet below. Containers that inherit from [FrameworkElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement), such as the LayoutPanel, automatically expose the common properties that provide input to XAML's layout process (for example, Height and Width). ```xaml @@ -92,7 +92,7 @@ For this situation *ExampleLayout* must carefully consider the state that it use #### LayoutContext -The purpose of the [LayoutContext](/uwp/api/microsoft.ui.xaml.controls.layoutcontext) is to deal with those challenges. It provides the attached layout the ability to interact with the host container, such as retrieving child elements, without introducing a direct dependency between the two. The context also enables the layout to store any state it requires that might be related to the container's child elements. +The purpose of the [LayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutcontext) is to deal with those challenges. It provides the attached layout the ability to interact with the host container, such as retrieving child elements, without introducing a direct dependency between the two. The context also enables the layout to store any state it requires that might be related to the container's child elements. Simple, non-virtualizing layouts often do not need to maintain any state, making it a non-issue. A more complex layout, such as Grid, however, may choose to maintain state between the measure and arrange call to avoid re-computing a value. @@ -100,11 +100,11 @@ Virtualizing layouts *often* need to maintain some state between both the measur #### Initializing and Uninitializing Per-Container State -When a layout is attached to a container, its [InitializeForContextCore](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.initializeforcontextcore) method is called and provides an opportunity to initialize an object to store state. +When a layout is attached to a container, its [InitializeForContextCore](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.initializeforcontextcore) method is called and provides an opportunity to initialize an object to store state. -Similarly, when the layout is being removed from a container, the [UninitializeForContextCore](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.uninitializeforcontextcore) method will be called. This gives the layout an opportunity to clean up any state it had associated with that container. +Similarly, when the layout is being removed from a container, the [UninitializeForContextCore](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.uninitializeforcontextcore) method will be called. This gives the layout an opportunity to clean up any state it had associated with that container. -The layout's state object can be stored with and retrieved from the container with the [LayoutState](/uwp/api/microsoft.ui.xaml.controls.layoutcontext.layoutstate) property on the context. +The layout's state object can be stored with and retrieved from the container with the [LayoutState](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutcontext.layoutstate) property on the context. ### UI Virtualization @@ -122,31 +122,31 @@ First, decide whether the layout you need to create should support UI virtualiza **A few things to keep in mind…** 1. Non-virtualizing layouts are easier to author. If the number of items will always be small then authoring a non-virtualizing layout is recommended. -2. The platform provides a set of attached layouts that work with the [ItemsRepeater](../controls/items-repeater.md#change-the-layout-of-items) and [LayoutPanel](/uwp/api/microsoft.ui.xaml.controls.layoutpanel) to cover common needs. Familiarize yourself with those before deciding you need to define a custom layout. +2. The platform provides a set of attached layouts that work with the [ItemsRepeater](../controls/items-repeater.md#change-the-layout-of-items) and [LayoutPanel](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutpanel) to cover common needs. Familiarize yourself with those before deciding you need to define a custom layout. 3. Virtualizing layouts always have some additional CPU and memory cost/complexity/overhead compared to a non-virtualizing layout. As a general rule of thumb if the children the layout will need to manage will likely fit in an area that is 3x the size of the viewport, then there may not be much gain from a virtualizing layout. The 3x size is discussed in greater detail later in this doc, but is due to the asynchronous nature of scrolling on Windows and its impact on virtualization. > [!TIP] -> As a point of reference, the default settings for the [ListView](/uwp/api/windows.ui.xaml.controls.listview) (and [ItemsRepeater](/uwp/api/microsoft.ui.xaml.controls.itemsrepeater)) are that recycling doesn't begin until the number of items are enough to fill up 3x the size of the current viewport. +> As a point of reference, the default settings for the [ListView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.listview) (and [ItemsRepeater](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater)) are that recycling doesn't begin until the number of items are enough to fill up 3x the size of the current viewport. **Choose your base type** ![attached layout hierarchy](images/xaml-attached-layout-hierarchy.png) -The base [Layout](/uwp/api/microsoft.ui.xaml.controls.layout) type has two derived types that serve as the start point for authoring an attached layout: +The base [Layout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layout) type has two derived types that serve as the start point for authoring an attached layout: -1. [NonVirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayout) -2. [VirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout) +1. [NonVirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayout) +2. [VirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout) ## Non-Virtualizing Layout -The approach for creating a non-virtualizing layout should feel familiar to anyone that has created a [Custom Panel](./custom-panels-overview.md). The same concepts apply. The primary difference is that a [NonVirtualizingLayoutContext](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayoutcontext) is used to access the [Children](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayoutcontext.children) collection, and layout may choose to store state. +The approach for creating a non-virtualizing layout should feel familiar to anyone that has created a [Custom Panel](./custom-panels-overview.md). The same concepts apply. The primary difference is that a [NonVirtualizingLayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayoutcontext) is used to access the [Children](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayoutcontext.children) collection, and layout may choose to store state. -1. Derive from the base type [NonVirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayout) (instead of Panel). +1. Derive from the base type [NonVirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayout) (instead of Panel). 2. *(Optional)* Define dependency properties that when changed will invalidate the layout. -3. _(**New**/Optional)_ Initialize any state object required by the layout as part of the [InitializeForContextCore](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.initializeforcontextcore). Stash it with the host container by using the [LayoutState](/uwp/api/microsoft.ui.xaml.controls.layoutcontext.layoutstate) provided with the context. -4. Override the [MeasureOverride](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayout.measureoverride) and call the [Measure](/uwp/api/windows.ui.xaml.uielement.measure) method on all the children. -5. Override the [ArrangeOverride](/uwp/api/microsoft.ui.xaml.controls.nonvirtualizinglayout.arrangeoverride) and call the [Arrange](/uwp/api/windows.ui.xaml.uielement.arrange) method on all the children. -6. *(**New**/Optional)* Clean up any saved state as part of the [UninitializeForContextCore](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.uninitializeforcontextcore). +3. _(**New**/Optional)_ Initialize any state object required by the layout as part of the [InitializeForContextCore](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.initializeforcontextcore). Stash it with the host container by using the [LayoutState](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutcontext.layoutstate) provided with the context. +4. Override the [MeasureOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayout.measureoverride) and call the [Measure](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) method on all the children. +5. Override the [ArrangeOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.nonvirtualizinglayout.arrangeoverride) and call the [Arrange](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) method on all the children. +6. *(**New**/Optional)* Clean up any saved state as part of the [UninitializeForContextCore](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.uninitializeforcontextcore). ### Example: A Simple Stack Layout (Varying-Sized Items) @@ -205,16 +205,16 @@ public class MyStackLayout : NonVirtualizingLayout Similar to a non-virtualizing layout, the high-level steps for a virtualizing layout are the same. The complexity is largely in determining what elements will fall within the viewport and should be realized. -1. Derive from the base type [VirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout). +1. Derive from the base type [VirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout). 2. (Optional) Define your dependency properties that when changed will invalidate the layout. -3. Initialize any state object that will be required by the layout as part of the [InitializeForContextCore](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.initializeforcontextcore). Stash it with the host container by using the [LayoutState](/uwp/api/microsoft.ui.xaml.controls.layoutcontext.layoutstate) provided with the context. -4. Override the [MeasureOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride) and call the [Measure](/uwp/api/windows.ui.xaml.uielement.measure) method for each child that should be realized. - 1. The [GetOrCreateElementAt](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method is used to retrieve a UIElement that has been prepared by the framework (for example, data bindings applied). -5. Override the [ArrangeOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.arrangeoverride) and call the [Arrange](/uwp/api/windows.ui.xaml.uielement.arrange) method for each realized child. -6. (Optional) Clean up any saved state as part of the [UninitializeForContextCore](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.uninitializeforcontextcore). +3. Initialize any state object that will be required by the layout as part of the [InitializeForContextCore](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.initializeforcontextcore). Stash it with the host container by using the [LayoutState](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.layoutcontext.layoutstate) provided with the context. +4. Override the [MeasureOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride) and call the [Measure](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) method for each child that should be realized. + 1. The [GetOrCreateElementAt](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method is used to retrieve a UIElement that has been prepared by the framework (for example, data bindings applied). +5. Override the [ArrangeOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.arrangeoverride) and call the [Arrange](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) method for each realized child. +6. (Optional) Clean up any saved state as part of the [UninitializeForContextCore](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.uninitializeforcontextcore). > [!TIP] -> The value returned by the [MeasureOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout) is used as the size of the virtualized content. +> The value returned by the [MeasureOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout) is used as the size of the virtualized content. There are two general approaches to consider when authoring a virtualizing layout. Whether to choose one or the other largely depends on "how will you determine the size of an element". If its enough to know the index of an item in the data set or the data itself dictates its eventual size, then we'd consider it **data-dependent**. These are more straightforward to create. If, however, the only way to determine the size for an item is to create and measure the UI then we'd say it is **content-dependent**. These are more complex. @@ -232,7 +232,7 @@ An (over)simplified view of the steps performed by the framework from start-up t 4. Performs a render pass. -With UI virtualization, creating the elements that would normally be done in step 2 is delayed or ended early once its been determined that sufficient content has been created to fill the viewport. A virtualizing container (for example, ItemsRepeater) defers to its attached layout to drive this process. It provides the attached layout with a [VirtualizingLayoutContext](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext) that surfaces the additional information that a virtualizing layout needs. +With UI virtualization, creating the elements that would normally be done in step 2 is delayed or ended early once its been determined that sufficient content has been created to fill the viewport. A virtualizing container (for example, ItemsRepeater) defers to its attached layout to drive this process. It provides the attached layout with a [VirtualizingLayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext) that surfaces the additional information that a virtualizing layout needs. **The RealizationRect (i.e. Viewport)** @@ -240,29 +240,29 @@ Scrolling on Windows happens asynchronous to the UI thread. It is not controlled ![Realization rect](images/xaml-attached-layout-realizationrect.png) -Since element creation is costly, virtualizing containers (for example, [ItemsRepeater](../controls/items-repeater.md)) will initially provide the attached layout with a [RealizationRect](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) that matches the viewport. On idle time the container may grow the buffer of prepared content by making repeated calls to the layout using an increasingly larger realization rect. This behavior is a performance optimization that attempts to strike a balance between fast startup time and a good panning experience. The maximum buffer size that the ItemsRepeater will generate is controlled by its [VerticalCacheLength](/uwp/api/microsoft.ui.xaml.controls.itemsrepeater.verticalcachelength) and [HorizontalCacheLength](/uwp/api/microsoft.ui.xaml.controls.itemsrepeater.verticalcachelength) properties. +Since element creation is costly, virtualizing containers (for example, [ItemsRepeater](../controls/items-repeater.md)) will initially provide the attached layout with a [RealizationRect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) that matches the viewport. On idle time the container may grow the buffer of prepared content by making repeated calls to the layout using an increasingly larger realization rect. This behavior is a performance optimization that attempts to strike a balance between fast startup time and a good panning experience. The maximum buffer size that the ItemsRepeater will generate is controlled by its [VerticalCacheLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater.verticalcachelength) and [HorizontalCacheLength](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater.verticalcachelength) properties. **Re-using Elements (Recycling)** -The layout is expected to size and position the elements to fill the [RealizationRect](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) each time it is run. By default the [VirtualizingLayout](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout) will recycle any unused elements at the end of each layout pass. +The layout is expected to size and position the elements to fill the [RealizationRect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) each time it is run. By default the [VirtualizingLayout](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout) will recycle any unused elements at the end of each layout pass. -The [VirtualizingLayoutContext](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext) that is passed to the layout as part of the [MeasureOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride) and [ArrangeOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.arrangeoverride) provides the additional information a virtualizing layout needs. Some of the most commonly used things it provides are the ability to: +The [VirtualizingLayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext) that is passed to the layout as part of the [MeasureOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride) and [ArrangeOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.arrangeoverride) provides the additional information a virtualizing layout needs. Some of the most commonly used things it provides are the ability to: -1. Query the number of items in the data ([ItemCount](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.itemcount)). -2. Retrieve a specific item using the [GetItemAt](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getitemat) method. -3. Retrieve a [RealizationRect](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) that represents the viewport and buffer that the layout should fill with realized elements. -4. Request the UIElement for a specific item with the [GetOrCreateElement](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method. +1. Query the number of items in the data ([ItemCount](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.itemcount)). +2. Retrieve a specific item using the [GetItemAt](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getitemat) method. +3. Retrieve a [RealizationRect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) that represents the viewport and buffer that the layout should fill with realized elements. +4. Request the UIElement for a specific item with the [GetOrCreateElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method. Requesting an element for a given index will cause that element to be marked as "in use" for that pass of the layout. If the element does not already exist, then it will be realized and automatically prepared for use (for example, inflating the UI tree defined in a DataTemplate, processing any data binding, etc.). Otherwise, it will be retrieved from a pool of existing instances. -At the end of each measure pass, any existing, realized element that was not marked "in use" is automatically considered available for re-use unless the option to [SuppressAutoRecycle](/uwp/api/microsoft.ui.xaml.controls.elementrealizationoptions) was used when the element was retrieved via the [GetOrCreateElementAt](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method. The framework automatically moves it to a recycle pool and makes it available. It may subsequently be pulled for use by a different container. The framework tries to avoid this when possible as there is some cost associated with re-parenting an element. +At the end of each measure pass, any existing, realized element that was not marked "in use" is automatically considered available for re-use unless the option to [SuppressAutoRecycle](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.elementrealizationoptions) was used when the element was retrieved via the [GetOrCreateElementAt](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method. The framework automatically moves it to a recycle pool and makes it available. It may subsequently be pulled for use by a different container. The framework tries to avoid this when possible as there is some cost associated with re-parenting an element. -If a virtualizing layout knows at the beginning of each measure which elements will no longer fall within the realization rect then it can optimize its re-use. Rather than relying on the framework's default behavior. The layout can preemptively move elements to the recycle pool by using the [RecycleElement](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recycleelement) method. Calling this method before requesting new elements causes those existing elements to be available when the layout later issues a [GetOrCreateElementAt](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) request for an index that isn't already associated with an element. +If a virtualizing layout knows at the beginning of each measure which elements will no longer fall within the realization rect then it can optimize its re-use. Rather than relying on the framework's default behavior. The layout can preemptively move elements to the recycle pool by using the [RecycleElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recycleelement) method. Calling this method before requesting new elements causes those existing elements to be available when the layout later issues a [GetOrCreateElementAt](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) request for an index that isn't already associated with an element. The VirtualizingLayoutContext provides two additional properties designed for layout authors creating a content-dependent layout. They are discussed in more detail later. -1. A [RecommendedAnchorIndex](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) that provides an optional _input_ to layout. -2. A [LayoutOrigin](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.layoutorigin) that is an optional _output_ of the layout. +1. A [RecommendedAnchorIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) that provides an optional _input_ to layout. +2. A [LayoutOrigin](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.layoutorigin) that is an optional _output_ of the layout. ## Data-dependent Virtualizing Layouts @@ -271,11 +271,11 @@ A virtualizing layout is easier if you know what the size of every item should b The general approach is for the layout to: 1. Calculate a size and position of every item. -2. As part of the [MeasureOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride): - 1. Use the [RealizationRect](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) to determine which items should appear within the viewport. - 2. Retrieve the UIElement that should represent the item with the [GetOrCreateElementAt](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method. - 3. [Measure](/uwp/api/windows.ui.xaml.uielement.measure) the UIElement with the pre-calculated size. -3. As part of the [ArrangeOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.arrangeoverride), [Arrange](/uwp/api/windows.ui.xaml.uielement.arrange) each realized UIElement with the precalculated position. +2. As part of the [MeasureOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride): + 1. Use the [RealizationRect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect) to determine which items should appear within the viewport. + 2. Retrieve the UIElement that should represent the item with the [GetOrCreateElementAt](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method. + 3. [Measure](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) the UIElement with the pre-calculated size. +3. As part of the [ArrangeOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.arrangeoverride), [Arrange](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) each realized UIElement with the precalculated position. > [!NOTE] > A data layout approach is often incompatible with _data virtualization_. Specifically, where the only data loaded into memory is that data required to fill what's visible to the user. Data virtualization isn't referring to lazy or incremental loading of data as a user scrolls down where that data remains resident. Rather, it's referring to when items are released from memory as they're scrolled out of view. Having a data layout that inspects every data item as part of a data layout would prevent data virtualization from working as expected. An exception is a layout like the UniformGridLayout which assumes that everything has the same size. @@ -570,7 +570,7 @@ internal class ActivityFeedLayoutState ### (Optional) Managing the Item to UIElement Mapping -By default, the [VirtualizingLayoutContext](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext) maintains a mapping between the realized elements and the index in the data source they represent. A layout can choose to manage this mapping itself by always requesting the option to [SuppressAutoRecycle](/uwp/api/microsoft.ui.xaml.controls.elementrealizationoptions) when retrieving an element via the [GetOrCreateElementAt](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method which prevents the default auto-recycling behavior. A layout may choose to do this, for example, if it will only be used when scrolling is restricted to one direction and the items it considers will always be contiguous (i.e. knowing the index of the first and last element is enough to know all the elements that should be realized). +By default, the [VirtualizingLayoutContext](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext) maintains a mapping between the realized elements and the index in the data source they represent. A layout can choose to manage this mapping itself by always requesting the option to [SuppressAutoRecycle](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.elementrealizationoptions) when retrieving an element via the [GetOrCreateElementAt](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.getorcreateelementat) method which prevents the default auto-recycling behavior. A layout may choose to do this, for example, if it will only be used when scrolling is restricted to one direction and the items it considers will always be contiguous (i.e. knowing the index of the first and last element is enough to know all the elements that should be realized). #### Example: Xbox Activity Feed measure @@ -662,11 +662,11 @@ Content-dependent layouts rely on estimation to guess both the size of unrealize **Scroll Anchoring** -XAML provides a mechanism to mitigate sudden viewport shifts by having scrolling controls support [scroll anchoring](/uwp/api/windows.ui.xaml.controls.iscrollanchorprovider) by implementing the [IScrollAnchorPovider](/uwp/api/windows.ui.xaml.controls.iscrollanchorprovider) interface. As the user manipulates the content, the scrolling control continually selects an element from the set of candidates that were opted-in to be tracked. If the position of the anchor element shifts during the layout then the scroll control automatically shifts its viewport to maintain the viewport. +XAML provides a mechanism to mitigate sudden viewport shifts by having scrolling controls support [scroll anchoring](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.iscrollanchorprovider) by implementing the [IScrollAnchorPovider](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.iscrollanchorprovider) interface. As the user manipulates the content, the scrolling control continually selects an element from the set of candidates that were opted-in to be tracked. If the position of the anchor element shifts during the layout then the scroll control automatically shifts its viewport to maintain the viewport. -The value of the [RecommendedAnchorIndex](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) provided to the layout may reflect that currently selected anchor element chosen by the scrolling control. Alternatively, if a developer explicitly requests that an element be realized for an index with the [GetOrCreateElement](/uwp/api/microsoft.ui.xaml.controls.itemsrepeater.getorcreateelement) method on the [ItemsRepeater](/uwp/api/microsoft.ui.xaml.controls.itemsrepeater), then that index is given as the [RecommendedAnchorIndex](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) on the next layout pass. This enables the layout to be prepared for the likely scenario that a developer realizes an element and subsequently requests that it be brought into view via the [StartBringIntoView](/uwp/api/windows.ui.xaml.uielement.startbringintoview) method. +The value of the [RecommendedAnchorIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) provided to the layout may reflect that currently selected anchor element chosen by the scrolling control. Alternatively, if a developer explicitly requests that an element be realized for an index with the [GetOrCreateElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater.getorcreateelement) method on the [ItemsRepeater](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater), then that index is given as the [RecommendedAnchorIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) on the next layout pass. This enables the layout to be prepared for the likely scenario that a developer realizes an element and subsequently requests that it be brought into view via the [StartBringIntoView](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.startbringintoview) method. -The [RecommendedAnchorIndex](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) is the index for the item in the data source that a content-dependent layout should position first when estimating the position of its items. It should serve as the starting point for positioning other realized items. +The [RecommendedAnchorIndex](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.recommendedanchorindex) is the index for the item in the data source that a content-dependent layout should position first when estimating the position of its items. It should serve as the starting point for positioning other realized items. **Impact on ScrollBars** @@ -676,13 +676,13 @@ The more accurate the layout can be in its estimations then the less likely a us ### Layout Corrections -A content-dependent layout should be prepared to rationalize its estimate with reality. For example, as the user scrolls to the top of the content and the layout realizes the very first element, it may find that the element's anticipated position relative to the element from which it started would cause it to appear somewhere other than the origin of (x:0, y:0). When this occurs, the layout can use the [LayoutOrigin](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.layoutorigin) property to set the position it calculated as the new layout origin. The net result is similar to scroll anchoring in which the scrolling control's viewport is automatically adjusted to account for the content's position as reported by the layout. +A content-dependent layout should be prepared to rationalize its estimate with reality. For example, as the user scrolls to the top of the content and the layout realizes the very first element, it may find that the element's anticipated position relative to the element from which it started would cause it to appear somewhere other than the origin of (x:0, y:0). When this occurs, the layout can use the [LayoutOrigin](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.layoutorigin) property to set the position it calculated as the new layout origin. The net result is similar to scroll anchoring in which the scrolling control's viewport is automatically adjusted to account for the content's position as reported by the layout. ![Correcting the LayoutOrigin](images/xaml-attached-layout-origincorrection.png) ### Disconnected Viewports -The size returned from the layout's [MeasureOverride](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride) method represents the best guess at the size of the content which may change with each successive layout. As a user scrolls the layout will be continually re-evaluated with an updated [RealizationRect](/uwp/api/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect). +The size returned from the layout's [MeasureOverride](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayout.measureoverride) method represents the best guess at the size of the content which may change with each successive layout. As a user scrolls the layout will be continually re-evaluated with an updated [RealizationRect](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.virtualizinglayoutcontext.realizationrect). If a user drags the thumb very quickly then its possible for the viewport, from the perspective of the layout, to appear to make large jumps where the prior position doesn't overlap the now current position. This is due to the asynchronous nature of scrolling. It's also possible for an app that is consuming the layout to request that an element be brought into view for an item that is not currently realized and is estimated to lay outside the current range tracked by the layout. @@ -1186,5 +1186,5 @@ public class VirtualizingStackLayout : VirtualizingLayout ## Related articles -- [ItemsRepeater](/uwp/api/microsoft.ui.xaml.controls.itemsrepeater) -- [ScrollViewer](/uwp/api/windows.ui.xaml.controls.scrollviewer) +- [ItemsRepeater](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.itemsrepeater) +- [ScrollViewer](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.scrollviewer) diff --git a/hub/apps/design/layout/boxpanel-example-custom-panel.md b/hub/apps/design/layout/boxpanel-example-custom-panel.md index 9283395139..2d7d28a5c6 100644 --- a/hub/apps/design/layout/boxpanel-example-custom-panel.md +++ b/hub/apps/design/layout/boxpanel-example-custom-panel.md @@ -15,13 +15,13 @@ 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. +Learn to write code for a custom [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) class, implementing [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) methods, and using the [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.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) +> **Important APIs**: [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel), [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride),[**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.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. +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**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) class. You provide behavior for your panel by overriding the [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.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 @@ -37,7 +37,7 @@ With that in mind, the `BoxPanel` shown here is for a particular scenario. In th ## 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`. +Start by deriving a custom class from [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.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: @@ -50,7 +50,7 @@ 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: +Now that you can resolve [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel), make it the base class of `BoxPanel`. Also, make `BoxPanel` public: ```CSharp public class BoxPanel : Panel @@ -115,18 +115,18 @@ protected override Size MeasureOverride(Size 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. +The necessary pattern of a [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) implementation is the loop through each element in [**Panel.Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children). Always call the [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.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. +So what does the measure pass do? It sets a value for the read-only [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) property on each element where [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.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). +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**](/windows/windows-app-sdk/api/winrt/microsoft.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**](/windows/windows-app-sdk/api/winrt/microsoft.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**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.height) and [**Width**](/windows/windows-app-sdk/api/winrt/microsoft.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. +> The internal logic of [**StackPanel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stackpanel) also has this behavior: **StackPanel** passes an infinite dimension value to [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.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: +However, the panel itself can't return a [**Size**](/uwp/api/Windows.Foundation.Size) with an infinite value from [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.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. @@ -163,17 +163,17 @@ protected override Size ArrangeOverride(Size 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. +The necessary pattern of an [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) implementation is the loop through each element in [**Panel.Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children). Always call the [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.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). +Note how there aren't as many calculations as in [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.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**](/windows/windows-app-sdk/api/winrt/microsoft.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). +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**](/windows/windows-app-sdk/api/winrt/microsoft.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. +Panels sometimes need to clip their content. If they do, the clipped size is the size that's present in [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize), because the [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.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**](/windows/windows-app-sdk/api/winrt/microsoft.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. +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**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.canvas) layout logic, the position in the [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.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). +It's typical that the input *finalSize* and the [**Size**](/uwp/api/Windows.Foundation.Size) you return from a [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.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 @@ -213,13 +213,13 @@ 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. +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**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid) does for its cells. In **Grid**'s case, the size of the cells is set by [**ColumnDefinition**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.columndefinition) and [**RowDefinition**](/windows/windows-app-sdk/api/winrt/microsoft.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. +An advanced scenario for extending `BoxPanel` further (not shown here) could both accommodate dynamic children and use a child's [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.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. @@ -227,9 +227,9 @@ You might wonder why the panel wouldn't instead choose 5x2 for 10 items, because **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) +* [**FrameworkElement.ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) +* [**FrameworkElement.MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) +* [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) **Concepts** diff --git a/hub/apps/design/layout/custom-panels-overview.md b/hub/apps/design/layout/custom-panels-overview.md index aff0176808..e8bf07b65e 100644 --- a/hub/apps/design/layout/custom-panels-overview.md +++ b/hub/apps/design/layout/custom-panels-overview.md @@ -20,28 +20,28 @@ ms.localizationpriority: medium A *panel* is an object that provides a layout behavior for child elements it contains, when the Extensible Application Markup Language (XAML) layout system runs and your app UI is rendered. -> **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) +> **Important APIs**: [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel), [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride), [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) -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 [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride), supplying logic that measures and arranges the child elements. +You can define custom panels for XAML layout by deriving a custom class from the [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) class. You provide behavior for your panel by overriding the [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride), supplying logic that measures and arranges the child elements. ## The **Panel** base class -To define a custom panel class, you can either derive from the [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class directly, or derive from one of the practical panel classes that aren't sealed, such as [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid) or [**StackPanel**](/uwp/api/Windows.UI.Xaml.Controls.StackPanel). It's easier to derive from **Panel**, because it can be difficult to work around the existing layout logic of a panel that already has layout behavior. Also, a panel with behavior might have existing properties that aren't relevant for your panel's layout features. +To define a custom panel class, you can either derive from the [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) class directly, or derive from one of the practical panel classes that aren't sealed, such as [**Grid**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid) or [**StackPanel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stackpanel). It's easier to derive from **Panel**, because it can be difficult to work around the existing layout logic of a panel that already has layout behavior. Also, a panel with behavior might have existing properties that aren't relevant for your panel's layout features. -From [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel), your custom panel inherits these APIs: +From [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel), your custom panel inherits these APIs: -- The [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property. -- The [**Background**](/uwp/api/windows.ui.xaml.controls.panel.background), [**ChildrenTransitions**](/uwp/api/windows.ui.xaml.controls.panel.childrentransitions) and [**IsItemsHost**](/uwp/api/windows.ui.xaml.controls.panel.isitemshost) properties, and the dependency property identifiers. None of these properties are virtual, so you don't typically override or replace them. You don't typically need these properties for custom panel scenarios, not even for reading values. -- The layout override methods [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride). These were originally defined by [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement). The base [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class doesn't override these, but practical panels like [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid) do have override implementations that are implemented as native code and are run by the system. Providing new (or additive) implementations for **ArrangeOverride** and **MeasureOverride** is the bulk of the effort you need to define a custom panel. -- All the other APIs of [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement), [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) and [**DependencyObject**](/uwp/api/Windows.UI.Xaml.DependencyObject), such as [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height), [**Visibility**](/uwp/api/windows.ui.xaml.uielement.visibility) and so on. You sometimes reference values of these properties in your layout overrides, but they aren't virtual so you don't typically override or replace them. +- The [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) property. +- The [**Background**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.background), [**ChildrenTransitions**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.childrentransitions) and [**IsItemsHost**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.isitemshost) properties, and the dependency property identifiers. None of these properties are virtual, so you don't typically override or replace them. You don't typically need these properties for custom panel scenarios, not even for reading values. +- The layout override methods [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride). These were originally defined by [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement). The base [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) class doesn't override these, but practical panels like [**Grid**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid) do have override implementations that are implemented as native code and are run by the system. Providing new (or additive) implementations for **ArrangeOverride** and **MeasureOverride** is the bulk of the effort you need to define a custom panel. +- All the other APIs of [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement), [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement) and [**DependencyObject**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.dependencyobject), such as [**Height**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.height), [**Visibility**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.visibility) and so on. You sometimes reference values of these properties in your layout overrides, but they aren't virtual so you don't typically override or replace them. This focus here is to describe XAML layout concepts, so you can consider all the possibilities for how a custom panel can and should behave in layout. If you'd rather jump right in and see an example custom panel implementation, see [BoxPanel, an example custom panel](boxpanel-example-custom-panel.md). ## The **Children** property -The [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property is relevant to a custom panel because all classes derived from [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) use the **Children** property as the place to store their contained child elements in a collection. **Children** is designated as the XAML content property for the **Panel** class, and all classes derived from **Panel** can inherit the XAML content property behavior. If a property is designated the XAML content property, that means that XAML markup can omit a property element when specifying that property in markup, and the values are set as immediate markup children (the "content"). For example, if you derive a class named **CustomPanel** from **Panel** that defines no new behavior, you can still use this markup: +The [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) property is relevant to a custom panel because all classes derived from [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) use the **Children** property as the place to store their contained child elements in a collection. **Children** is designated as the XAML content property for the **Panel** class, and all classes derived from **Panel** can inherit the XAML content property behavior. If a property is designated the XAML content property, that means that XAML markup can omit a property element when specifying that property in markup, and the values are set as immediate markup children (the "content"). For example, if you derive a class named **CustomPanel** from **Panel** that defines no new behavior, you can still use this markup: ```XAML @@ -50,50 +50,50 @@ The [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property is ``` -When a XAML parser reads this markup, [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) is known to be the XAML content property for all [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) derived types, so the parser will add the two [**Button**](/uwp/api/Windows.UI.Xaml.Controls.Button) elements to the [**UIElementCollection**](/uwp/api/Windows.UI.Xaml.Controls.UIElementCollection) value of the **Children** property. The XAML content property facilitates a streamlined parent-child relationship in the XAML markup for a UI definition. For more info about XAML content properties, and how collection properties are populated when XAML is parsed, see the [XAML syntax guide](/windows/apps/develop/platform/xaml/xaml-syntax-guide). +When a XAML parser reads this markup, [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) is known to be the XAML content property for all [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) derived types, so the parser will add the two [**Button**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.button) elements to the [**UIElementCollection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uielementcollection) value of the **Children** property. The XAML content property facilitates a streamlined parent-child relationship in the XAML markup for a UI definition. For more info about XAML content properties, and how collection properties are populated when XAML is parsed, see the [XAML syntax guide](/windows/apps/develop/platform/xaml/xaml-syntax-guide). -The collection type that's maintaining the value of the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property is the [**UIElementCollection**](/uwp/api/Windows.UI.Xaml.Controls.UIElementCollection) class. **UIElementCollection** is a strongly typed collection that uses [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) as its enforced item type. **UIElement** is a base type that's inherited by hundreds of practical UI element types, so the type enforcement here is deliberately loose. But it does enforce that you couldn't have a [**Brush**](/uwp/api/Windows.UI.Xaml.Media.Brush) as a direct child of a [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel), and it generally means that only elements that are expected to be visible in UI and participate in layout will be found as child elements in a **Panel**. +The collection type that's maintaining the value of the [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) property is the [**UIElementCollection**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.uielementcollection) class. **UIElementCollection** is a strongly typed collection that uses [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement) as its enforced item type. **UIElement** is a base type that's inherited by hundreds of practical UI element types, so the type enforcement here is deliberately loose. But it does enforce that you couldn't have a [**Brush**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.brush) as a direct child of a [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel), and it generally means that only elements that are expected to be visible in UI and participate in layout will be found as child elements in a **Panel**. -Typically, a custom panel accepts any [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) child element by a XAML definition, by simply using the characteristics of the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) property as-is. As an advanced scenario, you could support further type checking of child elements, when you iterate over the collection in your layout overrides. +Typically, a custom panel accepts any [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement) child element by a XAML definition, by simply using the characteristics of the [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) property as-is. As an advanced scenario, you could support further type checking of child elements, when you iterate over the collection in your layout overrides. -Besides looping through the [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) collection in the overrides, your panel logic might also be influenced by `Children.Count`. You might have logic that is allocating space at least partly based on the number of items, rather than desired sizes and the other characteristics of individual items. +Besides looping through the [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) collection in the overrides, your panel logic might also be influenced by `Children.Count`. You might have logic that is allocating space at least partly based on the number of items, rather than desired sizes and the other characteristics of individual items. ## Overriding the layout methods -The basic model for the layout override methods ([**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride)) is that they should iterate through all the children and call each child element's specific layout method. The first layout cycle starts when the XAML layout system sets the visual for the root window. Because each parent invokes layout on its children, this propagates a call to layout methods to every possible UI element that is supposed to be part of a layout. In XAML layout, there are two stages: measure, then arrange. +The basic model for the layout override methods ([**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride)) is that they should iterate through all the children and call each child element's specific layout method. The first layout cycle starts when the XAML layout system sets the visual for the root window. Because each parent invokes layout on its children, this propagates a call to layout methods to every possible UI element that is supposed to be part of a layout. In XAML layout, there are two stages: measure, then arrange. -You don't get any built-in layout method behavior for [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) from the base [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel) class. Items in [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) won't automatically render as part of the XAML visual tree. It is up to you to make the items known to the layout process, by invoking layout methods on each of the items you find in **Children** through a layout pass within your **MeasureOverride** and **ArrangeOverride** implementations. +You don't get any built-in layout method behavior for [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) and [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) from the base [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel) class. Items in [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) won't automatically render as part of the XAML visual tree. It is up to you to make the items known to the layout process, by invoking layout methods on each of the items you find in **Children** through a layout pass within your **MeasureOverride** and **ArrangeOverride** implementations. There's no reason to call base implementations in layout overrides unless you have your own inheritance. The native methods for layout behavior (if they exist) run regardless, and not calling base implementation from overrides won't prevent the native behavior from happening. -During the measure pass, your layout logic queries each child element for its desired size, by calling the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) method on that child element. Calling the **Measure** method establishes the value for the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) property. The [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) return value is the desired size for the panel itself. +During the measure pass, your layout logic queries each child element for its desired size, by calling the [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) method on that child element. Calling the **Measure** method establishes the value for the [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) property. The [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) return value is the desired size for the panel itself. -During the arrange pass, the positions and sizes of child elements are determined in x-y space and the layout composition is prepared for rendering. Your code must call [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) on each child element in [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) so that the layout system detects that the element belongs in the layout. The **Arrange** call is a precursor to composition and rendering; it informs the layout system where that element goes, when the composition is submitted for rendering. +During the arrange pass, the positions and sizes of child elements are determined in x-y space and the layout composition is prepared for rendering. Your code must call [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) on each child element in [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) so that the layout system detects that the element belongs in the layout. The **Arrange** call is a precursor to composition and rendering; it informs the layout system where that element goes, when the composition is submitted for rendering. Many properties and values contribute to how the layout logic will work at runtime. A way to think about the layout process is that the elements with no children (generally the most deeply nested element in the UI) are the ones that can finalize measurements first. They don't have any dependencies on child elements that influence their desired size. They might have their own desired sizes, and these are size suggestions until the layout actually takes place. Then, the measure pass continues walking up the visual tree until the root element has its measurements and all the measurements can be finalized. -The candidate layout must fit within the current app window or else parts of the UI will be clipped. Panels often are the place where the clipping logic is determined. Panel logic can determine what size is available from within the [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) implementation, and may have to push the size restrictions onto the children and divide space amongst children so that everything fits as best it can. The result of layout is ideally something that uses various properties of all parts of the layout but still fits within the app window. That requires both a good implementation for layout logic of the panels, and also a judicious UI design on the part of any app code that builds a UI using that panel. No panel design is going to look good if the overall UI design includes more child elements than can possibly fit in the app. +The candidate layout must fit within the current app window or else parts of the UI will be clipped. Panels often are the place where the clipping logic is determined. Panel logic can determine what size is available from within the [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) implementation, and may have to push the size restrictions onto the children and divide space amongst children so that everything fits as best it can. The result of layout is ideally something that uses various properties of all parts of the layout but still fits within the app window. That requires both a good implementation for layout logic of the panels, and also a judicious UI design on the part of any app code that builds a UI using that panel. No panel design is going to look good if the overall UI design includes more child elements than can possibly fit in the app. -A large part of what makes the layout system work is that any element that's based on [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement) already has some of its own inherent behavior when acting as a child in a container. For example, there are several APIs of **FrameworkElement** that either inform layout behavior or are needed to make layout work at all. These include: +A large part of what makes the layout system work is that any element that's based on [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement) already has some of its own inherent behavior when acting as a child in a container. For example, there are several APIs of **FrameworkElement** that either inform layout behavior or are needed to make layout work at all. These include: -- [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) (actually a [**UIElement**](/uwp/api/Windows.UI.Xaml.UIElement) property) -- [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight) and [**ActualWidth**](/uwp/api/windows.ui.xaml.frameworkelement.actualwidth) -- [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) and [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width) -- [**Margin**](/uwp/api/windows.ui.xaml.frameworkelement.margin) -- [**LayoutUpdated**](/uwp/api/windows.ui.xaml.frameworkelement.layoutupdated) event -- [**HorizontalAlignment**](/uwp/api/windows.ui.xaml.frameworkelement.horizontalalignment) and [**VerticalAlignment**](/uwp/api/windows.ui.xaml.frameworkelement.verticalalignment) -- [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) methods -- [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) and [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) methods: these have native implementations defined at the [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement) level, which handle the element-level layout action +- [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) (actually a [**UIElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement) property) +- [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight) and [**ActualWidth**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualwidth) +- [**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) +- [**Margin**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.margin) +- [**LayoutUpdated**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.layoutupdated) event +- [**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) +- [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) and [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) methods +- [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) and [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) methods: these have native implementations defined at the [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement) level, which handle the element-level layout action ## **MeasureOverride** -The [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) method has a return value that's used by the layout system as the starting [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) for the panel itself, when the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) method is called on the panel by its parent in layout. The logic choices within the method are just as important as what it returns, and the logic often influences what value is returned. +The [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) method has a return value that's used by the layout system as the starting [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) for the panel itself, when the [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) method is called on the panel by its parent in layout. The logic choices within the method are just as important as what it returns, and the logic often influences what value is returned. -All [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) implementations should loop through [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children), and call the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) method on each child element. Calling the **Measure** method establishes the value for the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) property. This might inform how much space the panel itself needs, as well as how that space is divided among elements or sized for a particular child element. +All [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) implementations should loop through [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children), and call the [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) method on each child element. Calling the **Measure** method establishes the value for the [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) property. This might inform how much space the panel itself needs, as well as how that space is divided among elements or sized for a particular child element. -Here's a very basic skeleton of a [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) method: +Here's a very basic skeleton of a [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) method: ```CSharp protected override Size MeasureOverride(Size availableSize) @@ -111,37 +111,37 @@ protected override Size MeasureOverride(Size availableSize) } ``` -Elements often have a natural size by the time they're ready for layout. After the measure pass, the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) might indicate that natural size, if the *availableSize* you passed for [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) was smaller. If the natural size is larger than *availableSize* you passed for **Measure**, the **DesiredSize** is constrained to *availableSize*. That's how **Measure**'s internal implementation behaves, and your layout overrides should take that behavior into account. +Elements often have a natural size by the time they're ready for layout. After the measure pass, the [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) might indicate that natural size, if the *availableSize* you passed for [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) was smaller. If the natural size is larger than *availableSize* you passed for **Measure**, the **DesiredSize** is constrained to *availableSize*. That's how **Measure**'s internal implementation behaves, and your layout overrides should take that behavior into account. -Some elements don't have a natural size because they have **Auto** values for [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) and [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width). These elements use the full *availableSize*, because that's what an **Auto** value represents: size the element to the maximum available size, which the immediate layout parent communicates by calling [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) with *availableSize*. In practice, there's always some measurement that a UI is sized to (even if that's the top level window.) Eventually, the measure pass resolves all the **Auto** values to parent constraints and all **Auto** value elements get real measurements (which you can get by checking [**ActualWidth**](/uwp/api/windows.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight), after layout completes). +Some elements don't have a natural size because they have **Auto** values for [**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). These elements use the full *availableSize*, because that's what an **Auto** value represents: size the element to the maximum available size, which the immediate layout parent communicates by calling [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) with *availableSize*. In practice, there's always some measurement that a UI is sized to (even if that's the top level window.) Eventually, the measure pass resolves all the **Auto** values to parent constraints and all **Auto** value elements get real measurements (which you can get by checking [**ActualWidth**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight), after layout completes). -It's legal to pass a size to [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) that has at least one infinite dimension, to indicate that the panel can attempt to size itself to fit measurements of its content. Each child element being measured sets its [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) value using its natural size. Then, during the arrange pass, the panel typically arranges using that size. +It's legal to pass a size to [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) that has at least one infinite dimension, to indicate that the panel can attempt to size itself to fit measurements of its content. Each child element being measured sets its [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) value using its natural size. Then, during the arrange pass, the panel typically arranges using that size. -Text elements such as [**TextBlock**](/uwp/api/Windows.UI.Xaml.Controls.TextBlock) have a calculated [**ActualWidth**](/uwp/api/windows.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight) based on their text string and text properties even if no [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) or [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width) value is set, and these dimensions should be respected by your panel logic. Clipping text is a particularly bad UI experience. +Text elements such as [**TextBlock**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.textblock) have a calculated [**ActualWidth**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight) based on their text string and text properties even if no [**Height**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.height) or [**Width**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.width) value is set, and these dimensions should be respected by your panel logic. Clipping text is a particularly bad UI experience. -Even if your implementation doesn't use the desired size measurements, it's best to call the [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) method on each child element, because there are internal and native behaviors that are triggered by **Measure** being called. For an element to participate in layout, each child element must have **Measure** called on it during the measure pass and the [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) method called on it during the arrange pass. Calling these methods sets internal flags on the object and populates values (such as the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) property) that the system's layout logic needs when it builds the visual tree and renders the UI. +Even if your implementation doesn't use the desired size measurements, it's best to call the [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) method on each child element, because there are internal and native behaviors that are triggered by **Measure** being called. For an element to participate in layout, each child element must have **Measure** called on it during the measure pass and the [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) method called on it during the arrange pass. Calling these methods sets internal flags on the object and populates values (such as the [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) property) that the system's layout logic needs when it builds the visual tree and renders the UI. -The [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) return value is based on the panel's logic interpreting the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) or other size considerations for each of the child elements in [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children) when [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure) is called on them. What to do with **DesiredSize** values from children and how the **MeasureOverride** return value should use them is up to your own logic's interpretation. You don't typically add up the values without modification, because the input of **MeasureOverride** is often a fixed available size that's being suggested by the panel's parent. If you exceed that size, the panel itself might get clipped. You'd typically compare the total size of children to the panel's available size and make adjustments if necessary. +The [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) return value is based on the panel's logic interpreting the [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) or other size considerations for each of the child elements in [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children) when [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure) is called on them. What to do with **DesiredSize** values from children and how the **MeasureOverride** return value should use them is up to your own logic's interpretation. You don't typically add up the values without modification, because the input of **MeasureOverride** is often a fixed available size that's being suggested by the panel's parent. If you exceed that size, the panel itself might get clipped. You'd typically compare the total size of children to the panel's available size and make adjustments if necessary. ### Tips and guidance -- Ideally, a custom panel should be suitable for being the first true visual in a UI composition, perhaps at a level immediately under [**Page**](/uwp/api/Windows.UI.Xaml.Controls.Page), [**UserControl**](/uwp/api/Windows.UI.Xaml.Controls.UserControl) or another element that is the XAML page root. In [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) implementations, don't routinely return the input [**Size**](/uwp/api/Windows.Foundation.Size) without examining the values. If the return **Size** has an **Infinity** value in it, this can throw exceptions in runtime layout logic. An **Infinity** value can come from the main app window, which is scrollable and therefore doesn't have a maximum height. Other scrollable content might have the same behavior. -- Another common mistake in [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) implementations is to return a new default [**Size**](/uwp/api/Windows.Foundation.Size) (values for height and width are 0). You might start with that value, and it might even be the correct value if your panel determines that none of the children should be rendered. But, a default **Size** results in your panel not being sized correctly by its host. It requests no space in the UI, and therefore gets no space and doesn't render. All your panel code otherwise might be functioning fine, but you still won't see your panel or contents thereof if it's being composed with zero height, zero width. -- Within the overrides, avoid the temptation to cast child elements to [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement) and use properties that are calculated as a result of layout, particularly [**ActualWidth**](/uwp/api/windows.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight). For most common scenarios, you can base the logic on the child's [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) value and you won't need any of the [**Height**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Height) or [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width) related properties of a child element. For specialized cases, where you know the type of element and have additional information, for example the natural size of an image file, you can use your element's specialized information because it's not a value that is actively being altered by layout systems. Including layout-calculated properties as part of layout logic substantially increases the risk of defining an unintentional layout loop. These loops cause a condition where a valid layout can't be created and the system can throw a [**LayoutCycleException**](/dotnet/api/windows.ui.xaml.layoutcycleexception?view=dotnet-uwp-10.0&preserve-view=true) if the loop is not recoverable. -- Panels typically divide their available space between multiple child elements, although exactly how space is divided varies. For example, [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid) implements layout logic that uses its [**RowDefinition**](/uwp/api/Windows.UI.Xaml.Controls.RowDefinition) and [**ColumnDefinition**](/uwp/api/Windows.UI.Xaml.Controls.ColumnDefinition) values to divide the space into the **Grid** cells, supporting both star-sizing and pixel values. If they're pixel values, the size available for each child is already known, so that's what is passed as input size for a grid-style [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure). -- Panels themselves can introduce reserved space for padding between items. If you do this, make sure to expose the measurements as a property that's distinct from [**Margin**](/uwp/api/windows.ui.xaml.frameworkelement.margin) or any **Padding** property. -- Elements might have values for their [**ActualWidth**](/uwp/api/windows.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight) properties based on a previous layout pass. If values change, app UI code can put handlers for [**LayoutUpdated**](/uwp/api/windows.ui.xaml.frameworkelement.layoutupdated) on elements if there's special logic to run, but panel logic typically doesn't need to check for changes with event handling. The layout system is already making the determinations of when to re-run layout because a layout-relevant property changed value, and a panel's [**MeasureOverride**](/uwp/api/windows.ui.xaml.frameworkelement.measureoverride) or [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) are called automatically in the appropriate circumstances. +- Ideally, a custom panel should be suitable for being the first true visual in a UI composition, perhaps at a level immediately under [**Page**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.page), [**UserControl**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.usercontrol) or another element that is the XAML page root. In [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) implementations, don't routinely return the input [**Size**](/uwp/api/Windows.Foundation.Size) without examining the values. If the return **Size** has an **Infinity** value in it, this can throw exceptions in runtime layout logic. An **Infinity** value can come from the main app window, which is scrollable and therefore doesn't have a maximum height. Other scrollable content might have the same behavior. +- Another common mistake in [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) implementations is to return a new default [**Size**](/uwp/api/Windows.Foundation.Size) (values for height and width are 0). You might start with that value, and it might even be the correct value if your panel determines that none of the children should be rendered. But, a default **Size** results in your panel not being sized correctly by its host. It requests no space in the UI, and therefore gets no space and doesn't render. All your panel code otherwise might be functioning fine, but you still won't see your panel or contents thereof if it's being composed with zero height, zero width. +- Within the overrides, avoid the temptation to cast child elements to [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement) and use properties that are calculated as a result of layout, particularly [**ActualWidth**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight). For most common scenarios, you can base the logic on the child's [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) value and you won't need any of the [**Height**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.height) or [**Width**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.width) related properties of a child element. For specialized cases, where you know the type of element and have additional information, for example the natural size of an image file, you can use your element's specialized information because it's not a value that is actively being altered by layout systems. Including layout-calculated properties as part of layout logic substantially increases the risk of defining an unintentional layout loop. These loops cause a condition where a valid layout can't be created and the system can throw a [**LayoutCycleException**](/dotnet/api/windows.ui.xaml.layoutcycleexception?view=dotnet-uwp-10.0&preserve-view=true) if the loop is not recoverable. +- Panels typically divide their available space between multiple child elements, although exactly how space is divided varies. For example, [**Grid**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid) implements layout logic that uses its [**RowDefinition**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.rowdefinition) and [**ColumnDefinition**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.columndefinition) values to divide the space into the **Grid** cells, supporting both star-sizing and pixel values. If they're pixel values, the size available for each child is already known, so that's what is passed as input size for a grid-style [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure). +- Panels themselves can introduce reserved space for padding between items. If you do this, make sure to expose the measurements as a property that's distinct from [**Margin**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.margin) or any **Padding** property. +- Elements might have values for their [**ActualWidth**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualwidth) and [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight) properties based on a previous layout pass. If values change, app UI code can put handlers for [**LayoutUpdated**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.layoutupdated) on elements if there's special logic to run, but panel logic typically doesn't need to check for changes with event handling. The layout system is already making the determinations of when to re-run layout because a layout-relevant property changed value, and a panel's [**MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) or [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) are called automatically in the appropriate circumstances. ## **ArrangeOverride** -The [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) method has a [**Size**](/uwp/api/Windows.Foundation.Size) return value that's used by the layout system when rendering the panel itself, when the [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) method is called on the panel by its parent in layout. It's typical that the input *finalSize* and the **ArrangeOverride** returned **Size** are the same. If they aren't, that means the panel is attempting to make itself a different size than what the other participants in layout claim is available. The final size was based on having previously run the measure pass of layout through your panel code, so that's why returning a different size isn't typical: it means you are deliberately ignoring measure logic. +The [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) method has a [**Size**](/uwp/api/Windows.Foundation.Size) return value that's used by the layout system when rendering the panel itself, when the [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) method is called on the panel by its parent in layout. It's typical that the input *finalSize* and the **ArrangeOverride** returned **Size** are the same. If they aren't, that means the panel is attempting to make itself a different size than what the other participants in layout claim is available. The final size was based on having previously run the measure pass of layout through your panel code, so that's why returning a different size isn't typical: it means you are deliberately ignoring measure logic. Don't return a [**Size**](/uwp/api/Windows.Foundation.Size) with an **Infinity** component. Trying to use such a **Size** throws an exception from internal layout. -All [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) implementations should loop through [**Children**](/uwp/api/windows.ui.xaml.controls.panel.children), and call the [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) method on each child element. Like [**Measure**](/uwp/api/windows.ui.xaml.uielement.measure), **Arrange** doesn't have a return value. Unlike **Measure**, no calculated property gets set as a result (however, the element in question typically fires a [**LayoutUpdated**](/uwp/api/windows.ui.xaml.frameworkelement.layoutupdated) event). +All [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) implementations should loop through [**Children**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel.children), and call the [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) method on each child element. Like [**Measure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.measure), **Arrange** doesn't have a return value. Unlike **Measure**, no calculated property gets set as a result (however, the element in question typically fires a [**LayoutUpdated**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.layoutupdated) event). -Here's a very basic skeleton of an [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) method: +Here's a very basic skeleton of an [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) method: ```CSharp protected override Size ArrangeOverride(Size finalSize) @@ -157,18 +157,18 @@ protected override Size ArrangeOverride(Size finalSize) } ``` -The arrange pass of layout might happen without being preceded by a measure pass. However, this only happens when the layout system has determined no properties have changed that would have affected the previous measurements. For example, if an alignment changes, there's no need to re-measure that particular element because its [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) would not change when its alignment choice changes. On the other hand, if [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight) changes on any element in a layout, a new measure pass is needed. The layout system automatically detects true measure changes and invokes the measure pass again, and then runs another arrange pass. +The arrange pass of layout might happen without being preceded by a measure pass. However, this only happens when the layout system has determined no properties have changed that would have affected the previous measurements. For example, if an alignment changes, there's no need to re-measure that particular element because its [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) would not change when its alignment choice changes. On the other hand, if [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight) changes on any element in a layout, a new measure pass is needed. The layout system automatically detects true measure changes and invokes the measure pass again, and then runs another arrange pass. -The input for [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange) takes a [**Rect**](/uwp/api/Windows.Foundation.Rect) value. The most common way to construct this **Rect** is to use the constructor that has a [**Point**](/uwp/api/Windows.Foundation.Point) input and a [**Size**](/uwp/api/Windows.Foundation.Size) input. The **Point** is the point where the top left corner of the bounding box for the element should be placed. The **Size** is the dimensions used to render that particular element. You often use the [**DesiredSize**](/uwp/api/windows.ui.xaml.uielement.desiredsize) for that element as this **Size** value, because establishing the **DesiredSize** for all elements involved in layout was the purpose of the measure pass of layout. (The measure pass determines all-up sizing of the elements in an iterative way so that the layout system can optimize how elements are placed once it gets to the arrange pass.) +The input for [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange) takes a [**Rect**](/uwp/api/Windows.Foundation.Rect) value. The most common way to construct this **Rect** is to use the constructor that has a [**Point**](/uwp/api/Windows.Foundation.Point) input and a [**Size**](/uwp/api/Windows.Foundation.Size) input. The **Point** is the point where the top left corner of the bounding box for the element should be placed. The **Size** is the dimensions used to render that particular element. You often use the [**DesiredSize**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.desiredsize) for that element as this **Size** value, because establishing the **DesiredSize** for all elements involved in layout was the purpose of the measure pass of layout. (The measure pass determines all-up sizing of the elements in an iterative way so that the layout system can optimize how elements are placed once it gets to the arrange pass.) -What typically varies between [**ArrangeOverride**](/uwp/api/windows.ui.xaml.frameworkelement.arrangeoverride) implementations is the logic by which the panel determines the [**Point**](/uwp/api/Windows.Foundation.Point) component of how it arranges each child. An absolute positioning panel such as [**Canvas**](/uwp/api/Windows.UI.Xaml.Controls.Canvas) uses the explicit placement info that it gets from each element through [**Canvas.Left**](/uwp/api/windows.ui.xaml.controls.canvas.left) and [**Canvas.Top**](/uwp/api/windows.ui.xaml.controls.canvas.top) values. A space-dividing panel such as [**Grid**](/uwp/api/Windows.UI.Xaml.Controls.Grid) would have mathematical operations that divided the available space into cells and each cell would have an x-y value for where its content should be placed and arranged. An adaptive panel such as [**StackPanel**](/uwp/api/Windows.UI.Xaml.Controls.StackPanel) might be expanding itself to fit content in its orientation dimension. +What typically varies between [**ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) implementations is the logic by which the panel determines the [**Point**](/uwp/api/Windows.Foundation.Point) component of how it arranges each child. An absolute positioning panel such as [**Canvas**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.canvas) uses the explicit placement info that it gets from each element through [**Canvas.Left**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.canvas.left) and [**Canvas.Top**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.canvas.top) values. A space-dividing panel such as [**Grid**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.grid) would have mathematical operations that divided the available space into cells and each cell would have an x-y value for where its content should be placed and arranged. An adaptive panel such as [**StackPanel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.stackpanel) might be expanding itself to fit content in its orientation dimension. -There are still additional positioning influences on elements in layout, beyond what you directly control and pass to [**Arrange**](/uwp/api/windows.ui.xaml.uielement.arrange). These come from the internal native implementation of **Arrange** that's common to all [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement) derived types and augmented by some other types such as text elements. For example, elements can have margin and alignment, and some can have padding. These properties often interact. For more info, see [Alignment, margin, and padding](alignment-margin-padding.md). +There are still additional positioning influences on elements in layout, beyond what you directly control and pass to [**Arrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.arrange). These come from the internal native implementation of **Arrange** that's common to all [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement) derived types and augmented by some other types such as text elements. For example, elements can have margin and alignment, and some can have padding. These properties often interact. For more info, see [Alignment, margin, and padding](alignment-margin-padding.md). ## Panels and controls -Avoid putting functionality into a custom panel that should instead be built as a custom control. The role of a panel is to present any child element content that exists within it, as a function of layout that happens automatically. The panel might add decorations to content (similar to how a [**Border**](/uwp/api/Windows.UI.Xaml.Controls.Border) adds the border around the element it presents), or perform other layout-related adjustments like padding. But that's about as far as you should go when extending the visual tree output beyond reporting and using information from the children. +Avoid putting functionality into a custom panel that should instead be built as a custom control. The role of a panel is to present any child element content that exists within it, as a function of layout that happens automatically. The panel might add decorations to content (similar to how a [**Border**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.border) adds the border around the element it presents), or perform other layout-related adjustments like padding. But that's about as far as you should go when extending the visual tree output beyond reporting and using information from the children. If there's any interaction that's accessible to the user, you should write a custom control, not a panel. For example, a panel shouldn't add scrolling viewports to content it presents, even if the goal is to prevent clipping, because the scrollbars, thumbs and so on are interactive control parts. (Content might have scrollbars after all, but you should leave that up to the child's logic. Don't force it by adding scrolling as a layout operation.) You might create a control and also write a custom panel that plays an important role in that control's visual tree, when it comes to presenting content in that control. But the control and the panel should be distinct code objects. @@ -177,19 +177,19 @@ One reason the distinction between control and panel is important is because of ## Other layout API -There are some other APIs that are part of the layout system, but aren't declared by [**Panel**](/uwp/api/Windows.UI.Xaml.Controls.Panel). You might use these in a panel implementation or in a custom control that uses panels. +There are some other APIs that are part of the layout system, but aren't declared by [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.panel). You might use these in a panel implementation or in a custom control that uses panels. -- [**UpdateLayout**](/uwp/api/windows.ui.xaml.uielement.updatelayout), [**InvalidateMeasure**](/uwp/api/windows.ui.xaml.uielement.invalidatemeasure), and [**InvalidateArrange**](/uwp/api/windows.ui.xaml.uielement.invalidatearrange) are methods that initiate a layout pass. **InvalidateArrange** might not trigger a measure pass, but the other two do. Never call these methods from within a layout method override, because they're almost sure to cause a layout loop. Control code doesn't typically need to call them either. Most aspects of layout are triggered automatically by detecting changes to the framework-defined layout properties such as [**Width**](/uwp/api/Windows.UI.Xaml.FrameworkElement.Width) and so on. -- [**LayoutUpdated**](/uwp/api/windows.ui.xaml.frameworkelement.layoutupdated) is an event that fires when some aspect of layout of the element has changed. This isn't specific to panels; the event is defined by [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement). -- [**SizeChanged**](/uwp/api/windows.ui.xaml.frameworkelement.sizechanged) is an event that fires only after layout passes are finalized, and indicates that [**ActualHeight**](/uwp/api/windows.ui.xaml.frameworkelement.actualheight) or [**ActualWidth**](/uwp/api/windows.ui.xaml.frameworkelement.actualwidth) have changed as a result. This is another [**FrameworkElement**](/uwp/api/Windows.UI.Xaml.FrameworkElement) event. There are cases where [**LayoutUpdated**](/uwp/api/windows.ui.xaml.frameworkelement.layoutupdated) fires, but **SizeChanged** does not. For example the internal contents might be rearranged, but the element's size didn't change. +- [**UpdateLayout**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.updatelayout), [**InvalidateMeasure**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.invalidatemeasure), and [**InvalidateArrange**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.invalidatearrange) are methods that initiate a layout pass. **InvalidateArrange** might not trigger a measure pass, but the other two do. Never call these methods from within a layout method override, because they're almost sure to cause a layout loop. Control code doesn't typically need to call them either. Most aspects of layout are triggered automatically by detecting changes to the framework-defined layout properties such as [**Width**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.width) and so on. +- [**LayoutUpdated**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.layoutupdated) is an event that fires when some aspect of layout of the element has changed. This isn't specific to panels; the event is defined by [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement). +- [**SizeChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.sizechanged) is an event that fires only after layout passes are finalized, and indicates that [**ActualHeight**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualheight) or [**ActualWidth**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.actualwidth) have changed as a result. This is another [**FrameworkElement**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement) event. There are cases where [**LayoutUpdated**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.layoutupdated) fires, but **SizeChanged** does not. For example the internal contents might be rearranged, but the element's size didn't change. ## 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) +* [**FrameworkElement.ArrangeOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.arrangeoverride) +* [**FrameworkElement.MeasureOverride**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.frameworkelement.measureoverride) +* [**Panel**](/windows/windows-app-sdk/api/winrt/microsoft.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..55a8d6266b 100644 --- a/hub/apps/develop/camera/basic-photo-capture.md +++ b/hub/apps/develop/camera/basic-photo-capture.md @@ -81,7 +81,7 @@ You can also get a result frame when you stop the video by calling [**StopWithRe ### 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). +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). diff --git a/hub/apps/develop/camera/capture-device-controls-for-photo-and-video-capture.md b/hub/apps/develop/camera/capture-device-controls-for-photo-and-video-capture.md index ea5576ec6c..ae502d0c5b 100644 --- a/hub/apps/develop/camera/capture-device-controls-for-photo-and-video-capture.md +++ b/hub/apps/develop/camera/capture-device-controls-for-photo-and-video-capture.md @@ -20,7 +20,7 @@ The controls discussed in this article are all added to your app using the same The [**ExposureControl**](/uwp/api/Windows.Media.Devices.ExposureControl) allows you to set the shutter speed used during photo or video capture. -This example uses a [**Slider**](/uwp/api/Windows.UI.Xaml.Controls.Slider) control to adjust the current exposure value and a checkbox to toggle automatic exposure adjustment. +This example uses a [**Slider**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider) control to adjust the current exposure value and a checkbox to toggle automatic exposure adjustment. :::code language="xml" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml" id="SnippetExposureXAML"::: @@ -28,7 +28,7 @@ Check to see if the current capture device supports the **ExposureControl** by c The exposure value must be within the range supported by the device and must be an increment of the supported step size. Get the supported values for the current device by checking the [**Min**](/uwp/api/windows.media.devices.exposurecontrol.min), [**Max**](/uwp/api/windows.media.devices.exposurecontrol.max), and [**Step**](/uwp/api/windows.media.devices.exposurecontrol.step) properties, which are used to set the corresponding properties of the slider control. -Set the slider control's value to the current value of the **ExposureControl** after unregistering the [**ValueChanged**](/uwp/api/windows.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. +Set the slider control's value to the current value of the **ExposureControl** after unregistering the [**ValueChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetExposureControl"::: @@ -47,7 +47,7 @@ In the **CheckedChanged** event handler of the auto exposure checkbox, turn auto The [**ExposureCompensationControl**](/uwp/api/Windows.Media.Devices.ExposureCompensationControl) allows you to set the exposure compensation used during photo or video capture. -This example uses a [**Slider**](/uwp/api/Windows.UI.Xaml.Controls.Slider) control to adjust the current exposure compensation value. +This example uses a [**Slider**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider) control to adjust the current exposure compensation value. :::code language="xml" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml" id="SnippetEvXAML"::: @@ -55,7 +55,7 @@ Check to see if the current capture device supports the **ExposureCompensationCo The exposure compensation value must be within the range supported by the device and must be an increment of the supported step size. Get the supported values for the current device by checking the [**Min**](/uwp/api/windows.media.devices.exposurecompensationcontrol.min), [**Max**](/uwp/api/windows.media.devices.exposurecompensationcontrol.max), and [**Step**](/uwp/api/windows.media.devices.exposurecompensationcontrol.step) properties, which are used to set the corresponding properties of the slider control. -Set slider control's value to the current value of the **ExposureCompensationControl** after unregistering the [**ValueChanged**](/uwp/api/windows.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. +Set slider control's value to the current value of the **ExposureCompensationControl** after unregistering the [**ValueChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetEvControl"::: @@ -73,7 +73,7 @@ This example uses a set of radio buttons to allow the user to switch between on, Check to see if the current capture device supports the **FlashControl** by checking the [**Supported**](/uwp/api/windows.media.devices.focuscontrol.supported) property. If the control is supported, you can show and enable the UI for this feature. If the **FlashControl** is supported, automatic red eye reduction may or may not be supported, so check the [**RedEyeReductionSupported**](/uwp/api/windows.media.devices.flashcontrol.redeyereductionsupported) property before enabling the UI. Because the **TorchControl** is separate from the flash control, you must also check its [**Supported**](/uwp/api/windows.media.devices.torchcontrol.supported) property before using it. -In the [**Checked**](/uwp/api/windows.ui.xaml.controls.primitives.togglebutton.checked) event handler for each of the flash radio buttons, enable or disable the appropriate corresponding flash setting. Note that to set the flash to always be used, you must set the [**Enabled**](/uwp/api/windows.media.devices.flashcontrol.enabled) property to true and the [**Auto**](/uwp/api/windows.media.devices.flashcontrol.auto) property to false. +In the [**Checked**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.togglebutton.checked) event handler for each of the flash radio buttons, enable or disable the appropriate corresponding flash setting. Note that to set the flash to always be used, you must set the [**Enabled**](/uwp/api/windows.media.devices.flashcontrol.enabled) property to true and the [**Auto**](/uwp/api/windows.media.devices.flashcontrol.auto) property to false. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetFlashControl"::: @@ -104,7 +104,7 @@ Check to see if the current capture device supports the **FocusControl** by chec :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetCAF"::: -In the [**Checked**](/uwp/api/windows.ui.xaml.controls.primitives.togglebutton.checked) event handler for the continuous autofocus radio button, use the [**VideoDeviceController.FocusControl**](/uwp/api/windows.media.devices.videodevicecontroller.focuscontrol) property to get an instance of the control. Call [**UnlockAsync**](/uwp/api/windows.media.devices.focuscontrol.unlockasync) to unlock the control in case your app has previously called [**LockAsync**](/uwp/api/windows.media.devices.focuscontrol.lockasync) to enable one of the other focus modes. +In the [**Checked**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.togglebutton.checked) event handler for the continuous autofocus radio button, use the [**VideoDeviceController.FocusControl**](/uwp/api/windows.media.devices.videodevicecontroller.focuscontrol) property to get an instance of the control. Call [**UnlockAsync**](/uwp/api/windows.media.devices.focuscontrol.unlockasync) to unlock the control in case your app has previously called [**LockAsync**](/uwp/api/windows.media.devices.focuscontrol.lockasync) to enable one of the other focus modes. Create a new [**FocusSettings**](/uwp/api/Windows.Media.Devices.FocusSettings) object and set the [**Mode**](/uwp/api/windows.media.devices.focussettings.mode) property to **Continuous**. Set the [**AutoFocusRange**](/uwp/api/windows.media.devices.focussettings.autofocusrange) property to a value appropriate for your app scenario or selected by the user from your UI. Pass your **FocusSettings** object into the [**Configure**](/uwp/api/windows.media.devices.focuscontrol.configure) method, and then call [**FocusAsync**](/uwp/api/windows.media.devices.focuscontrol.focusasync) to initiate continuous autofocus. @@ -125,7 +125,7 @@ Check to see if the current capture device supports the **FocusControl** by chec :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetTapFocus"::: -In the [**Checked**](/uwp/api/windows.ui.xaml.controls.primitives.togglebutton.checked) event handler for the tap-to-focus radio button, use the [**VideoDeviceController.FocusControl**](/uwp/api/windows.media.devices.videodevicecontroller.focuscontrol) property to get an instance of the control. Call [**LockAsync**](/uwp/api/windows.media.devices.focuscontrol.lockasync) to lock the control in case your app has previously called [**UnlockAsync**](/uwp/api/windows.media.devices.focuscontrol.unlockasync) to enable continuous autofocus, and then wait for the user to tap the screen to change the focus. +In the [**Checked**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.togglebutton.checked) event handler for the tap-to-focus radio button, use the [**VideoDeviceController.FocusControl**](/uwp/api/windows.media.devices.videodevicecontroller.focuscontrol) property to get an instance of the control. Call [**LockAsync**](/uwp/api/windows.media.devices.focuscontrol.lockasync) to lock the control in case your app has previously called [**UnlockAsync**](/uwp/api/windows.media.devices.focuscontrol.unlockasync) to enable continuous autofocus, and then wait for the user to tap the screen to change the focus. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetTapFocusRadioButton"::: @@ -133,7 +133,7 @@ This example focuses on a region when the user taps the screen, and then removes :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetIsFocused"::: -The next step is to listen for the event when the user taps the screen by handling the [**Tapped**](/uwp/api/windows.ui.xaml.uielement.tapped) event of the [**CaptureElement**](/uwp/api/Windows.UI.Xaml.Controls.CaptureElement) that is currently displaying the capture preview stream. If the camera isn't currently previewing, or if tap-to-focus mode is disabled, return from the handler without doing anything. +The next step is to listen for the event when the user taps the screen by handling the [**Tapped**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.tapped) event of the [**CaptureElement**](/uwp/api/windows.ui.xaml.controls.captureelement) that is currently displaying the capture preview stream. If the camera isn't currently previewing, or if tap-to-focus mode is disabled, return from the handler without doing anything. If the tracking variable *\_isFocused* is toggled to false, and if the camera isn't currently in the process of focus (determined by the [**FocusState**](/uwp/api/windows.media.devices.focuscontrol.focusstate) property of the **FocusControl**), begin the tap-to-focus process. Get the position of the user's tap from the event args passed into the handler. This example also uses this opportunity to pick the size of the region that will be focused upon. In this case, the size is 1/4 of the smallest dimension of the capture element. Pass the tap position and the region size into the **TapToFocus** helper method that is defined in the next section. @@ -143,7 +143,7 @@ If the *\_isFocused* toggle is set to true, the user tap should clear the focus In the **TapToFocus** helper method, first set the *\_isFocused* toggle to true so that the next screen tap will release the focus from the tapped region. -The next task in this helper method is to determine the rectangle within the preview stream that will be assigned to the focus control. This requires two steps. The first step is to determine the rectangle that the preview stream takes up within the [**CaptureElement**](/uwp/api/Windows.UI.Xaml.Controls.CaptureElement) control. This depends on the dimensions of the preview stream and the orientation of the device. The helper method **GetPreviewStreamRectInControl**, shown at the end of this section, performs this task and returns the rectangle containing the preview stream. +The next task in this helper method is to determine the rectangle within the preview stream that will be assigned to the focus control. This requires two steps. The first step is to determine the rectangle that the preview stream takes up within the [**CaptureElement**](/uwp/api/windows.ui.xaml.controls.captureelement) control. This depends on the dimensions of the preview stream and the orientation of the device. The helper method **GetPreviewStreamRectInControl**, shown at the end of this section, performs this task and returns the rectangle containing the preview stream. The next task in **TapToFocus** is to convert the tap location and desired focus rectangle size, which were determined within the **CaptureElement.Tapped** event handler, into coordinates within capture stream. The **ConvertUiTapToPreviewRect** helper method, shown later in this section, performs this conversion and returns the rectangle, in capture stream coordinates, where the focus will be requested. @@ -188,7 +188,7 @@ Check to see if the current capture device supports the **FocusControl** by chec The focus value must be within the range supported by the device and must be an increment of the supported step size. Get the supported values for the current device by checking the [**Min**](/uwp/api/windows.media.devices.focuscontrol.min), [**Max**](/uwp/api/windows.media.devices.focuscontrol.max), and [**Step**](/uwp/api/windows.media.devices.focuscontrol.step) properties, which are used to set the corresponding properties of the slider control. -Set the slider control's value to the current value of the **FocusControl** after unregistering the [**ValueChanged**](/uwp/api/windows.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. +Set the slider control's value to the current value of the **FocusControl** after unregistering the [**ValueChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetFocus"::: @@ -218,7 +218,7 @@ In the **CheckedChanged** event handler, get the capture devices [**FlashControl The [**IsoSpeedControl**](/uwp/api/Windows.Media.Devices.IsoSpeedControl) allows you to set the ISO speed used during photo or video capture. -This example uses a [**Slider**](/uwp/api/Windows.UI.Xaml.Controls.Slider) control to adjust the current exposure compensation value and a checkbox to toggle automatic ISO speed adjustment. +This example uses a [**Slider**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider) control to adjust the current exposure compensation value and a checkbox to toggle automatic ISO speed adjustment. :::code language="xml" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml" id="SnippetIsoXAML"::: @@ -226,7 +226,7 @@ Check to see if the current capture device supports the **IsoSpeedControl** by c The ISO speed value must be within the range supported by the device and must be an increment of the supported step size. Get the supported values for the current device by checking the [**Min**](/uwp/api/windows.media.devices.isospeedcontrol.min), [**Max**](/uwp/api/windows.media.devices.isospeedcontrol.max), and [**Step**](/uwp/api/windows.media.devices.isospeedcontrol.step) properties, which are used to set the corresponding properties of the slider control. -Set the slider control's value to the current value of the **IsoSpeedControl** after unregistering the [**ValueChanged**](/uwp/api/windows.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. +Set the slider control's value to the current value of the **IsoSpeedControl** after unregistering the [**ValueChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetIsoControl"::: @@ -262,7 +262,7 @@ First, call the **VideoDeviceController** method [**TryGetPowerlineFrequency**]( The [**WhiteBalanceControl**](/uwp/api/windows.media.devices.videodevicecontroller.whitebalancecontrol) allows you to set the white balance used during photo or video capture. -This example uses a [**ComboBox**](/uwp/api/Windows.UI.Xaml.Controls.ComboBox) control to select from built-in color temperature presets and a [**Slider**](/uwp/api/Windows.UI.Xaml.Controls.Slider) control for manual white balance adjustment. +This example uses a [**ComboBox**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.combobox) control to select from built-in color temperature presets and a [**Slider**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider) control for manual white balance adjustment. :::code language="xml" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml" id="SnippetWhiteBalanceXAML"::: @@ -270,11 +270,11 @@ Check to see if the current capture device supports the **WhiteBalanceControl** For manual control, the white balance value must be within the range supported by the device and must be an increment of the supported step size. Get the supported values for the current device by checking the [**Min**](/uwp/api/windows.media.devices.whitebalancecontrol.min), [**Max**](/uwp/api/windows.media.devices.whitebalancecontrol.max), and [**Step**](/uwp/api/windows.media.devices.whitebalancecontrol.step) properties, which are used to set the corresponding properties of the slider control. Before enabling manual control, check to make sure that the range between the minimum and maximum supported values is greater than the step size. If it is not, manual control is not supported on the current device. -Set the slider control's value to the current value of the **WhiteBalanceControl** after unregistering the [**ValueChanged**](/uwp/api/windows.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. +Set the slider control's value to the current value of the **WhiteBalanceControl** after unregistering the [**ValueChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetWhiteBalance"::: -In the [**SelectionChanged**](/uwp/api/windows.ui.xaml.controls.primitives.selector.selectionchanged) event handler of the color temperature preset combo box, get the currently selected preset and set the value of the control by calling [**SetPresetAsync**](/uwp/api/windows.media.devices.whitebalancecontrol.setpresetasync). If the selected preset value is not **Manual**, disable the manual white balance slider. +In the [**SelectionChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.selector.selectionchanged) event handler of the color temperature preset combo box, get the currently selected preset and set the value of the control by calling [**SetPresetAsync**](/uwp/api/windows.media.devices.whitebalancecontrol.setpresetasync). If the selected preset value is not **Manual**, disable the manual white balance slider. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetWhiteBalanceComboBox"::: @@ -292,7 +292,7 @@ In the **ValueChanged** event handler, get the current value of the control and The [**ZoomControl**](/uwp/api/Windows.Media.Devices.ZoomControl) allows you to set the zoom level used during photo or video capture. -This example uses a [**Slider**](/uwp/api/Windows.UI.Xaml.Controls.Slider) control to adjust the current zoom level. The following section shows how to adjust zoom based on a pinch gesture on the screen. +This example uses a [**Slider**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.slider) control to adjust the current zoom level. The following section shows how to adjust zoom based on a pinch gesture on the screen. :::code language="xml" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.xaml" id="SnippetZoomXAML"::: @@ -300,7 +300,7 @@ Check to see if the current capture device supports the **ZoomControl** by check The zoom level value must be within the range supported by the device and must be an increment of the supported step size. Get the supported values for the current device by checking the [**Min**](/uwp/api/windows.media.devices.zoomcontrol.min), [**Max**](/uwp/api/windows.media.devices.zoomcontrol.max), and [**Step**](/uwp/api/windows.media.devices.zoomcontrol.step) properties, which are used to set the corresponding properties of the slider control. -Set the slider control's value to the current value of the **ZoomControl** after unregistering the [**ValueChanged**](/uwp/api/windows.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. +Set the slider control's value to the current value of the **ZoomControl** after unregistering the [**ValueChanged**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.primitives.rangebase.valuechanged) event handler so that the event is not triggered when the value is set. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetZoomControl"::: @@ -318,7 +318,7 @@ First, determine if the digital zoom control is supported on the current device :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetIsSmoothZoomSupported"::: -On a multi-touch enabled device, a typical scenario is to adjust the zoom factor based on a two-finger pinch gesture. Set the [**ManipulationMode**](/uwp/api/windows.ui.xaml.uielement.manipulationmode) property of the [**CaptureElement**](/uwp/api/Windows.UI.Xaml.Controls.CaptureElement) control to [**ManipulationModes.Scale**](/uwp/api/Windows.UI.Xaml.Input.ManipulationModes) to enable the pinch gesture. Then, register for the [**ManipulationDelta**](/uwp/api/windows.ui.xaml.uielement.manipulationdelta) event which is raised when the pinch gesture changes size. +On a multi-touch enabled device, a typical scenario is to adjust the zoom factor based on a two-finger pinch gesture. Set the [**ManipulationMode**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationmode) property of the [**CaptureElement**](/uwp/api/windows.ui.xaml.controls.captureelement) control to [**ManipulationModes.Scale**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.input.manipulationmodes) to enable the pinch gesture. Then, register for the [**ManipulationDelta**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.uielement.manipulationdelta) event which is raised when the pinch gesture changes size. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.ManualControls.xaml.cs" id="SnippetRegisterPinchGestureHandler"::: diff --git a/hub/apps/develop/camera/process-media-frames-with-mediaframereader.md b/hub/apps/develop/camera/process-media-frames-with-mediaframereader.md index 925be2b53d..91cdc24d2d 100644 --- a/hub/apps/develop/camera/process-media-frames-with-mediaframereader.md +++ b/hub/apps/develop/camera/process-media-frames-with-mediaframereader.md @@ -100,7 +100,7 @@ In your code behind page, declare a class member variable of type **SoftwareBitm :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.FrameReader.xaml.cs" id="SnippetDeclareBackBuffer"::: -Because the frames will arrive as **SoftwareBitmap** objects, you need to create a [**SoftwareBitmapSource**](/uwp/api/Windows.UI.Xaml.Media.Imaging.SoftwareBitmapSource) object which allows you to use a **SoftwareBitmap** as the source for a XAML **Control**. You should set the image source somewhere in your code before you start the frame reader. +Because the frames will arrive as **SoftwareBitmap** objects, you need to create a [**SoftwareBitmapSource**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.imaging.softwarebitmapsource) object which allows you to use a **SoftwareBitmap** as the source for a XAML **Control**. You should set the image source somewhere in your code before you start the frame reader. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.FrameReader.xaml.cs" id="SnippetImageElementSource"::: @@ -112,7 +112,7 @@ Next, the [**Interlocked.Exchange**](/dotnet/api/system.threading.interlocked.ex Next, the [**CoreDispatcher**](/uwp/api/Windows.UI.Core.CoreDispatcher) associated with the **Image** element is used to create a task that will run on the UI thread by calling [**RunAsync**](/uwp/api/windows.ui.core.coredispatcher.runasync). Because the asynchronous tasks will be performed within the task, the lambda expression passed to **RunAsync** is declared with the *async* keyword. -Within the task, the *_taskRunning* variable is checked to make sure that only one instance of the task is running at a time. If the task isn't already running, *_taskRunning* is set to true to prevent the task from running again. In a *while* loop, **Interlocked.Exchange** is called to copy from the backbuffer into a temporary **SoftwareBitmap** until the backbuffer image is null. For each time the temporary bitmap is populated, the **Source** property of the **Image** is cast to a **SoftwareBitmapSource**, and then [**SetBitmapAsync**](/uwp/api/windows.ui.xaml.media.imaging.softwarebitmapsource.setbitmapasync) is called to set the source of the image. +Within the task, the *_taskRunning* variable is checked to make sure that only one instance of the task is running at a time. If the task isn't already running, *_taskRunning* is set to true to prevent the task from running again. In a *while* loop, **Interlocked.Exchange** is called to copy from the backbuffer into a temporary **SoftwareBitmap** until the backbuffer image is null. For each time the temporary bitmap is populated, the **Source** property of the **Image** is cast to a **SoftwareBitmapSource**, and then [**SetBitmapAsync**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.media.imaging.softwarebitmapsource.setbitmapasync) is called to set the source of the image. Finally, the *_taskRunning* variable is set back to false so that the task can be run again the next time the handler is called. @@ -136,7 +136,7 @@ This section provides the full code listing for a provides a helper class that m The **FrameRenderer** helper class implements the following methods. -* **FrameRenderer** constructor - The constructor initializes the helper class to use the XAML [**Image**](/uwp/api/Windows.UI.Xaml.Controls.Image) element you pass in for displaying media frames. +* **FrameRenderer** constructor - The constructor initializes the helper class to use the XAML [**Image**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.image) element you pass in for displaying media frames. * **ProcessFrame** - This method displays a media frame, represented by a [**MediaFrameReference**](/uwp/api/Windows.Media.Capture.Frames.MediaFrameReference), in the **Image** element you passed into the constructor. You should typically call this method from your [**FrameArrived**](/uwp/api/windows.media.capture.frames.mediaframereader.framearrived) event handler, passing in the frame returned by [**TryAcquireLatestFrame**](/uwp/api/windows.media.capture.frames.mediaframereader.tryacquirelatestframe). * **ConvertToDisplayableImage** - This methods checks the format of the media frame and, if necessary, converts it to a displayable format. For color images, this means making sure that the color format is BGRA8 and that the bitmap alpha mode is premultiplied. For depth or infrared frames, each scanline is processed to convert the depth or infrared values to a psuedocolor gradient, using the **PsuedoColorHelper** class that is also included in the sample and listed below. @@ -201,7 +201,7 @@ In **Buffered** acquisition mode, the system will keep all frames in the buffer ## Use MediaSource to display frames in a MediaPlayerElement -Starting with Windows, version 1709, you can display frames acquired from a **MediaFrameReader** directly in a **[MediaPlayerElement](/uwp/api/windows.ui.xaml.controls.mediaplayerelement)** control in your XAML page. This is achieved by using the **[MediaSource.CreateFromMediaFrameSource](/uwp/api/windows.media.core.mediasource.createfrommediaframesource)** to create **[MediaSource](/uwp/api/windows.media.core.mediasource)** object that can be used directly by a **[MediaPlayer](/uwp/api/windows.media.playback.mediaplayer)** associated with a **MediaPlayerElement**. For detailed information on working with **MediaPlayer** and **MediaPlayerElement**, see [Play audio and video with MediaPlayer](/windows/uwp/audio-video-camera/play-audio-and-video-with-mediaplayer). +Starting with Windows, version 1709, you can display frames acquired from a **MediaFrameReader** directly in a **[MediaPlayerElement](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.mediaplayerelement)** control in your XAML page. This is achieved by using the **[MediaSource.CreateFromMediaFrameSource](/uwp/api/windows.media.core.mediasource.createfrommediaframesource)** to create **[MediaSource](/uwp/api/windows.media.core.mediasource)** object that can be used directly by a **[MediaPlayer](/uwp/api/windows.media.playback.mediaplayer)** associated with a **MediaPlayerElement**. For detailed information on working with **MediaPlayer** and **MediaPlayerElement**, see [Play audio and video with MediaPlayer](/windows/uwp/audio-video-camera/play-audio-and-video-with-mediaplayer). The following code examples show you a simple implementation that displays the frames from a front-facing and back-facing camera simultaneously in a XAML page. @@ -219,7 +219,7 @@ Initialize the **MediaCapture** object to use the selected **MediaFrameSourceGro :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.FrameReader.xaml.cs" id="SnippetMediaSourceInitMediaCapture"::: -Finally, call **[MediaSource.CreateFromMediaFrameSource](/uwp/api/windows.media.core.mediasource.createfrommediaframesource)** to create a **MediaSource** for each frame source by using the **[Id](/uwp/api/windows.media.capture.frames.mediaframesourceinfo.Id)** property of the associated **MediaFrameSourceInfo** object to select one of the frame sources in the **MediaCapture** object's **[FrameSources](/uwp/api/windows.media.capture.mediacapture.FrameSources)** collection. Initialize a new **MediaPlayer** object and assign it to a **MediaPlayerElement** by calling **[SetMediaPlayer](/uwp/api/windows.ui.xaml.controls.mediaplayerelement.MediaPlayer)**. Then set the **[Source](/uwp/api/windows.media.playback.mediaplayer.Source)** property to the newly created **MediaSource** object. +Finally, call **[MediaSource.CreateFromMediaFrameSource](/uwp/api/windows.media.core.mediasource.createfrommediaframesource)** to create a **MediaSource** for each frame source by using the **[Id](/uwp/api/windows.media.capture.frames.mediaframesourceinfo.Id)** property of the associated **MediaFrameSourceInfo** object to select one of the frame sources in the **MediaCapture** object's **[FrameSources](/uwp/api/windows.media.capture.mediacapture.FrameSources)** collection. Initialize a new **MediaPlayer** object and assign it to a **MediaPlayerElement** by calling **[SetMediaPlayer](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.mediaplayerelement.mediaplayer)**. Then set the **[Source](/uwp/api/windows.media.playback.mediaplayer.Source)** property to the newly created **MediaSource** object. :::code language="csharp" source="~/../snippets-windows/winappsdk/audio-video-camera/camera-winui/CS/CameraWinUI/MainWindow.FrameReader.xaml.cs" id="SnippetMediaSourceMediaPlayer"::: diff --git a/hub/apps/develop/launch/handle-uri-activation.md b/hub/apps/develop/launch/handle-uri-activation.md index da286a5a5a..50d3ae06d2 100644 --- a/hub/apps/develop/launch/handle-uri-activation.md +++ b/hub/apps/develop/launch/handle-uri-activation.md @@ -136,7 +136,7 @@ The following code programmatically launches the app via its URI: For more details about how to launch an app via a URI, see [Launch the default app for a URI](launch-default-app.md). -It is recommended that apps create a new XAML [Frame](/uwp/api/Windows.UI.Xaml.Controls.Frame) for each activation event that opens a new page. This way, the navigation backstack for the new XAML **Frame** will not contain any previous content that the app might have on the current window when suspended. Apps that decide to use a single XAML **Frame** for Launch and File Contracts should clear the pages on the **Frame** navigation journal before navigating to a new page. +It is recommended that apps create a new XAML [Frame](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) for each activation event that opens a new page. This way, the navigation backstack for the new XAML **Frame** will not contain any previous content that the app might have on the current window when suspended. Apps that decide to use a single XAML **Frame** for Launch and File Contracts should clear the pages on the **Frame** navigation journal before navigating to a new page. When launched via Protocol activation, apps should consider including UI that allows the user to go back to the top page of the app. @@ -150,9 +150,9 @@ Any app or website can use your URI scheme name, including malicious ones. So an > [!NOTE] > When a UWP app is launched via Protocol Contract, make sure that Back button takes the user back to the screen that launched the app and not to the app's previous content. -We recommend that apps create a new XAML [**Frame**](/uwp/api/Windows.UI.Xaml.Controls.Frame) for each activation event that opens a new Uri target. This way, the navigation backstack for the new XAML **Frame** will not contain any previous content that the app might have on the current window when suspended. +We recommend that apps create a new XAML [**Frame**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) for each activation event that opens a new Uri target. This way, the navigation backstack for the new XAML **Frame** will not contain any previous content that the app might have on the current window when suspended. -If you decide that you want your apps to use a single XAML [**Frame**](/uwp/api/Windows.UI.Xaml.Controls.Frame) for Launch and Protocol Contracts, clear the pages on the **Frame** navigation journal before navigating to a new page. When launched via Protocol Contract, consider including UI into your apps that allows the user to go back to the top of the app. +If you decide that you want your apps to use a single XAML [**Frame**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.frame) for Launch and Protocol Contracts, clear the pages on the **Frame** navigation journal before navigating to a new page. When launched via Protocol Contract, consider including UI into your apps that allows the user to go back to the top of the app. ## Related content 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..56f1bbbf12 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/collection-commanding.md b/hub/apps/develop/ui/controls/collection-commanding.md index b13aefa98e..95f3cab16d 100644 --- a/hub/apps/develop/ui/controls/collection-commanding.md +++ b/hub/apps/develop/ui/controls/collection-commanding.md @@ -209,7 +209,7 @@ After you have generated some PodcastObjects, you can create a list of podcasts -