Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions specs/Setter_ValueProperty_Spec.md
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:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be we should say, boxing would be required to set values to Setter without XamlBindingHelper


```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")]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISetterStatics ?

{
static Microsoft.UI.Xaml.DependencyProperty ValueProperty{ get; };
}
};
}
```
264 changes: 264 additions & 0 deletions specs/XamlBindingHelper_Spec.md
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(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it should be SetPropertyFromThickness right?

Also I dont see a section for SetPropertyFromCornerRadius

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);
}
};
}
```
Loading