-
Notifications
You must be signed in to change notification settings - Fork 818
specs/XamlBindingHelper_Spec.md #11022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
a605d6c
903f207
54524f3
d3288da
87e09b9
8697534
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| Setter.ValueProperty | ||
| === | ||
|
|
||
| # Background | ||
|
|
||
| [`Setter`](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.setter) | ||
| is a WinUI 3 class that associates a dependency property with a value inside a `Style`. The | ||
| `Setter.Value` property holds the value that will be applied, but until now there has been no | ||
| public `DependencyProperty` identifier exposed for it. | ||
|
|
||
| All `XamlBindingHelper.SetPropertyFrom*` methods require a `DependencyProperty` as their second | ||
| argument (`propertyToSet`). Without a public `DependencyProperty` handle for `Setter.Value`, | ||
| callers cannot use `XamlBindingHelper` to set `Setter.Value` directly — they are forced to box the | ||
| value to `Object` first: | ||
|
|
||
| ```cpp | ||
| // WinUI 3 — current approach (boxing required) | ||
| auto widthSetter = Setter(); | ||
| widthSetter.Value(box_value(300)); | ||
| ``` | ||
|
|
||
| This spec adds a new static property, `Setter.ValueProperty`, that returns the | ||
| `DependencyProperty` identifier for `Setter.Value`. This unlocks `XamlBindingHelper` usage for | ||
| `Setter.Value`, allowing developers to set values without boxing: | ||
|
|
||
| ```cpp | ||
| // WinUI 3 — new approach (no boxing) | ||
| XamlBindingHelper::SetPropertyFromInt32( | ||
| widthSetter, | ||
| Setter::ValueProperty(), | ||
| 300); | ||
| ``` | ||
|
|
||
| ## Goals | ||
|
|
||
| * Expose `Setter.ValueProperty` so callers have a `DependencyProperty` handle to pass as | ||
| `propertyToSet` in `XamlBindingHelper.SetPropertyFrom*` methods. | ||
| * Follow the established pattern of other WinUI 3 classes that expose `DependencyProperty` | ||
| identifiers for their properties. | ||
|
|
||
| ## Non-goals | ||
|
|
||
| * Changing the behavior or storage of `Setter.Value` itself. | ||
| * Adding new overloads to `XamlBindingHelper` (covered in a separate spec). | ||
|
|
||
| # Conceptual pages (How To) | ||
|
|
||
| ## Using Setter.ValueProperty with XamlBindingHelper | ||
|
|
||
| Previously there was no public way to obtain a `DependencyProperty` token for `Setter.Value`. With | ||
| `Setter.ValueProperty`, you can now pass it to any existing `XamlBindingHelper.SetPropertyFrom*` | ||
| overload: | ||
|
|
||
| ```cpp | ||
| auto setter = Setter(); | ||
| // Set an Int32 value without boxing | ||
| XamlBindingHelper::SetPropertyFromInt32(setter, Setter::ValueProperty(), 300); | ||
| ``` | ||
|
|
||
| # API Pages | ||
|
|
||
| ## Setter.ValueProperty property | ||
|
|
||
| Gets the `DependencyProperty` identifier for the | ||
| [`Setter.Value`](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.setter.value) | ||
| property. | ||
|
|
||
| ```idl | ||
| static Microsoft.UI.Xaml.DependencyProperty ValueProperty{ get; }; | ||
| ``` | ||
|
|
||
| ### Remarks | ||
|
|
||
| * `ValueProperty` is a read-only static property that returns a singleton `DependencyProperty` | ||
| instance. | ||
| * Its primary purpose is to serve as the `propertyToSet` argument when calling | ||
| `XamlBindingHelper.SetPropertyFrom*` methods targeting `Setter.Value`. | ||
|
|
||
| ### Examples | ||
|
|
||
| * C#: | ||
| ```csharp | ||
| var setter = new Setter(); | ||
| // Use any existing SetPropertyFrom* overload with Setter.ValueProperty | ||
| XamlBindingHelper.SetPropertyFromDouble(setter, Setter.ValueProperty, 16.0); | ||
| ``` | ||
|
|
||
| * C++: | ||
| ```cpp | ||
| auto setter = Setter(); | ||
| // Use any existing SetPropertyFrom* overload with Setter::ValueProperty() | ||
| XamlBindingHelper::SetPropertyFromDouble(setter, Setter::ValueProperty(), 16.0); | ||
| ``` | ||
|
|
||
| # API Details | ||
|
|
||
| ```idl | ||
| namespace Microsoft.UI.Xaml | ||
| { | ||
| [contract(Microsoft.UI.Xaml.WinUIContract, 1)] | ||
| [webhosthidden] | ||
| runtimeclass Setter : Microsoft.UI.Xaml.SetterBase | ||
| { | ||
| // Existing members omitted for brevity | ||
|
|
||
| [contract(Microsoft.UI.Xaml.WinUIContract, 10)] | ||
| [static_name("Microsoft.UI.Xaml.ISetterStatics2")] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ISetterStatics ?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ISetterStatics is already taken, MIDL3 auto-generates it for the existing static members in the Setter class. Since that name is used, the new statics block for ValueProperty uses the next available name, ISetterStatics2 |
||
| { | ||
| static Microsoft.UI.Xaml.DependencyProperty ValueProperty{ get; }; | ||
| } | ||
| }; | ||
| } | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,264 @@ | ||
| XamlBindingHelper | ||
| === | ||
|
|
||
| # Background | ||
|
|
||
| [`XamlBindingHelper`](https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.markup.xamlbindinghelper) | ||
| is a utility class in WinUI 3 that provides static helper methods for setting dependency property | ||
| values without boxing them to `IInspectable`. It already has overloads for primitive types such as | ||
| `Int32`, `Double`, `Boolean`, `String`, and several `Windows.Foundation` structs (`Point`, `Rect`, | ||
| `Size`, `TimeSpan`). | ||
|
|
||
| In WinUI 2, developers could use the | ||
| [`XamlDirect`](https://learn.microsoft.com/uwp/api/windows.ui.xaml.core.direct.xamldirect) API to | ||
| set struct-typed property values directly without boxing. For example `SetThicknessProperty`, | ||
| `SetCornerRadiusProperty`, and `SetColorProperty`. `XamlDirect` was intentionally not carried | ||
| forward to WinUI 3 because it is a narrow, low-level API with a limited number of consumers and | ||
| significant maintenance costs. | ||
|
|
||
| However, there is a real performance gap: developers who need to configure `Setter.Value` with | ||
| struct types - `Thickness`, `CornerRadius`, and `Windows.UI.Color` � currently have no option | ||
| other than boxing the value to `Object` first: | ||
|
|
||
| ```cpp | ||
| // WinUI 3 � current approach (boxing required) | ||
| auto widthSetter = Setter(); | ||
| widthSetter.Value(box_value(300)); | ||
| ``` | ||
|
|
||
| This spec extends `XamlBindingHelper` with three new struct-typed overloads to close that gap: | ||
|
|
||
| - `SetPropertyFromThickness` | ||
| - `SetPropertyFromCornerRadius` | ||
| - `SetPropertyFromColor` | ||
|
|
||
| With these additions, developers can set struct-typed values on a `Setter` without any boxing: | ||
|
|
||
| ```cpp | ||
| // WinUI 3 � new approach (no boxing) | ||
| XamlBindingHelper::SetPropertyFromThickness( | ||
| widthSetter, | ||
| Setter::ValueProperty(), | ||
| thickness); | ||
| ``` | ||
|
|
||
| ## Goals | ||
|
|
||
| * Provide boxing-free helpers for the three most commonly needed struct types when configuring `Setter.Value`. | ||
| * Follow the established `SetPropertyFrom*` naming pattern already present on `XamlBindingHelper`. | ||
|
|
||
| ## Non-goals | ||
|
|
||
| * Re-introducing `XamlDirect` or any part of its API surface into WinUI 3. | ||
| * Adding `SetPropertyFrom*` overloads for every possible WinUI or Windows struct type. | ||
|
|
||
| # Conceptual pages (How To) | ||
|
|
||
| ## Setting Setter.Value without boxing | ||
|
|
||
| Before these APIs, setting a struct-typed value on `Setter.Value` required boxing the value to | ||
| `Object` first. For example, setting a `Thickness` on a `Setter` looked like this: | ||
|
|
||
| ```cpp | ||
| auto setter = Setter(); | ||
| setter.Value(box_value(Thickness{ 2, 4, 2, 4 })); | ||
| ``` | ||
|
|
||
| With the new APIs, the struct can be passed directly and no boxing is needed in application code: | ||
|
|
||
| ```cpp | ||
| auto setter = Setter(); | ||
| Thickness thickness{ 2, 4, 2, 4 }; | ||
| XamlBindingHelper::SetPropertyFromThickness(setter, Setter::ValueProperty(), thickness); | ||
| ``` | ||
|
|
||
| # API Pages | ||
|
|
||
| _(Each level-two section below maps to a docs.microsoft.com API page.)_ | ||
|
|
||
| ## XamlBindingHelper.SetPropertyFromThickness method | ||
|
|
||
| Sets a `Microsoft.UI.Xaml.Thickness` value on the specified dependency property of an object, | ||
| without requiring the caller to box the struct to `IInspectable`. | ||
|
|
||
| ```idl | ||
| static void SetPropertyFromThickness( | ||
| Object dependencyObject, | ||
| Microsoft.UI.Xaml.DependencyProperty propertyToSet, | ||
| Microsoft.UI.Xaml.Thickness value); | ||
| ``` | ||
|
|
||
| ### Parameters | ||
|
|
||
| | Parameter | Type | Description | | ||
| |---|---|---| | ||
| | `dependencyObject` | `object` | The target object that owns `propertyToSet`. | | ||
| | `propertyToSet` | `DependencyProperty` | The dependency property to assign the value to. | | ||
| | `value` | `Microsoft.UI.Xaml.Thickness` | The `Thickness` value to set. | | ||
|
|
||
| ### Examples | ||
|
|
||
| * C#: | ||
| ```csharp | ||
| var thicknessSetter = new Setter(); | ||
| var thickness = new Thickness(); | ||
| thickness.Left = 2; | ||
| thickness.Top = 4; | ||
| thickness.Right = 2; | ||
| thickness.Bottom = 4; | ||
| XamlBindingHelper.SetPropertyFromThickness(thicknessSetter, Setter.ValueProperty, thickness); | ||
| DemoBorder.SetValue(Border.BorderThicknessProperty, thicknessSetter.Value); | ||
| ``` | ||
|
|
||
| * C++: | ||
| ```cpp | ||
| auto thicknessSetter = Setter(); | ||
| Thickness thickness{}; | ||
| thickness.Left = 2; | ||
| thickness.Top = 4; | ||
| thickness.Right = 2; | ||
| thickness.Bottom = 4; | ||
| XamlBindingHelper::SetPropertyFromThickness(thicknessSetter, Setter::ValueProperty(), thickness); | ||
| DemoBorder().SetValue(Border::BorderThicknessProperty(), thicknessSetter.Value()); | ||
| ``` | ||
|
|
||
| ### Remarks | ||
|
|
||
| * If `dependencyObject` or `propertyToSet` is `null`, an exception is thrown by the WinRT layer from the underlying `E_POINTER` failure. | ||
|
|
||
| Sets a `Microsoft.UI.Xaml.CornerRadius` value on the specified dependency property of an object, | ||
| without requiring the caller to box the struct to `IInspectable`. | ||
|
|
||
| ```idl | ||
| static void SetPropertyFromCornerRadius( | ||
|
rashmi-thakurr marked this conversation as resolved.
|
||
| Object dependencyObject, | ||
| Microsoft.UI.Xaml.DependencyProperty propertyToSet, | ||
| Microsoft.UI.Xaml.CornerRadius value); | ||
| ``` | ||
|
|
||
| ### Parameters | ||
|
|
||
| | Parameter | Type | Description | | ||
| |---|---|---| | ||
| | `dependencyObject` | `object` | The target object that owns `propertyToSet`. | | ||
| | `propertyToSet` | `DependencyProperty` | The dependency property to assign the value to. | | ||
| | `value` | `Microsoft.UI.Xaml.CornerRadius` | The `CornerRadius` value to set. | | ||
|
|
||
| ### Examples | ||
|
|
||
| * C#: | ||
| ```csharp | ||
| var cornerRadiusSetter = new Setter(); | ||
| var cornerRadius = new CornerRadius(); | ||
| cornerRadius.TopLeft = 5; | ||
| cornerRadius.TopRight = 10; | ||
| cornerRadius.BottomRight = 15; | ||
| cornerRadius.BottomLeft = 20; | ||
| XamlBindingHelper.SetPropertyFromCornerRadius(cornerRadiusSetter, Setter.ValueProperty, cornerRadius); | ||
| DemoBorder.SetValue(Border.CornerRadiusProperty, cornerRadiusSetter.Value); | ||
| ``` | ||
|
|
||
| * C++: | ||
| ```cpp | ||
| auto cornerRadiusSetter = Setter(); | ||
| CornerRadius cornerRadius{}; | ||
| cornerRadius.TopLeft = 5; | ||
| cornerRadius.TopRight = 10; | ||
| cornerRadius.BottomRight = 15; | ||
| cornerRadius.BottomLeft = 20; | ||
| XamlBindingHelper::SetPropertyFromCornerRadius(cornerRadiusSetter, Setter::ValueProperty(), cornerRadius); | ||
| DemoBorder().SetValue(Border::CornerRadiusProperty(), cornerRadiusSetter.Value()); | ||
| ``` | ||
|
|
||
| ### Remarks | ||
|
|
||
| * If `dependencyObject` or `propertyToSet` is `null`, an exception is thrown by the WinRT layer from the underlying `E_POINTER` failure. | ||
|
|
||
| ## XamlBindingHelper.SetPropertyFromColor method | ||
|
|
||
| Sets a `Windows.UI.Color` value on the specified dependency property of an object, without | ||
| requiring the caller to box the struct to `IInspectable`. | ||
|
|
||
| ```idl | ||
| static void SetPropertyFromColor( | ||
| Object dependencyObject, | ||
| Microsoft.UI.Xaml.DependencyProperty propertyToSet, | ||
| Windows.UI.Color value); | ||
| ``` | ||
|
|
||
| ### Parameters | ||
|
|
||
| | Parameter | Type | Description | | ||
| |---|---|---| | ||
| | `dependencyObject` | `object` | The target object that owns `propertyToSet`. | | ||
| | `propertyToSet` | `DependencyProperty` | The dependency property to assign the value to. | | ||
| | `value` | `Windows.UI.Color` | The `Color` value to set. | | ||
|
|
||
| ### Examples | ||
|
|
||
| Setting `Setter.Value` to a color: | ||
|
|
||
| * C#: | ||
| ```csharp | ||
| var colorSetter = new Setter(); | ||
| XamlBindingHelper.SetPropertyFromColor(colorSetter, Setter.ValueProperty, Colors.BlueViolet); | ||
| DemoBorder.SetValue( | ||
| Border.BorderBrushProperty, | ||
| new SolidColorBrush((Windows.UI.Color)colorSetter.Value)); | ||
| ``` | ||
|
|
||
| Setting `SolidColorBrush.ColorProperty` directly on a brush: | ||
|
|
||
| * C#: | ||
| ```csharp | ||
| var brush = new SolidColorBrush(); | ||
| XamlBindingHelper.SetPropertyFromColor(brush, SolidColorBrush.ColorProperty, Colors.BlueViolet); | ||
| DemoBorder.SetValue(Border.BorderBrushProperty, brush); | ||
| ``` | ||
|
|
||
| * C++: | ||
| ```cpp | ||
| auto brush = SolidColorBrush(); | ||
| XamlBindingHelper::SetPropertyFromColor( | ||
| brush, | ||
| SolidColorBrush::ColorProperty(), | ||
| Colors::BlueViolet()); | ||
| DemoBorder().SetValue(Border::BorderBrushProperty(), brush); | ||
| ``` | ||
|
|
||
| ### Remarks | ||
|
|
||
| * If `dependencyObject` or `propertyToSet` is `null`, an exception is thrown by the WinRT layer from the underlying `E_POINTER` failure. | ||
|
|
||
| # API Details | ||
|
|
||
| ```idl | ||
| namespace Microsoft.UI.Xaml.Markup | ||
| { | ||
| [contract(Microsoft.UI.Xaml.WinUIContract, 1)] | ||
| [webhosthidden] | ||
| [default_interface] | ||
| runtimeclass XamlBindingHelper | ||
| { | ||
| // Existing members omitted for brevity | ||
|
|
||
| [contract(Microsoft.UI.Xaml.WinUIContract, 10)] | ||
| { | ||
| static void SetPropertyFromThickness( | ||
| Object dependencyObject, | ||
| Microsoft.UI.Xaml.DependencyProperty propertyToSet, | ||
| Microsoft.UI.Xaml.Thickness value); | ||
|
|
||
| static void SetPropertyFromCornerRadius( | ||
| Object dependencyObject, | ||
| Microsoft.UI.Xaml.DependencyProperty propertyToSet, | ||
| Microsoft.UI.Xaml.CornerRadius value); | ||
|
|
||
| static void SetPropertyFromColor( | ||
| Object dependencyObject, | ||
| Microsoft.UI.Xaml.DependencyProperty propertyToSet, | ||
| Windows.UI.Color value); | ||
| } | ||
| }; | ||
| } | ||
| ``` | ||
Uh oh!
There was an error while loading. Please reload this page.