Skip to content

chore: BindableType preserves properties and more - #22017

Merged
jonpryor merged 1 commit into
masterfrom
dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers
Dec 4, 2025
Merged

chore: BindableType preserves properties and more#22017
jonpryor merged 1 commit into
masterfrom
dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers

Conversation

@jonpryor

@jonpryor jonpryor commented Dec 2, 2025

Copy link
Copy Markdown
Contributor

chore: BindableType preserves properties and more

Context: unoplatform/uno.chefs#1712
Context: #21920
Context: unoplatform/uno.extensions#2966
Context: unoplatform/uno.extensions#2969
Context: https://discord.com/channels/732297728826277939/732297837953679412/1444909702512119899

While running the uno.chefs app on macOS under NativeAOT:

dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop -bl \
  Chefs/Chefs.csproj \
  -p:SelfContained=true -p:PublishAot=true -p:IsAotCompatible=true -p:UseSkiaRendering=true \
  -p:IlcGenerateMapFile=true -p:IlcGenerateMstatFile=true -p:IlcGenerateDgmlFile=true \
  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
Chefs/bin/Release/net10.0-desktop/osx-x64/publish/Chefs

Console output would contain the following errors:

fail: Uno.UI.Dispatching.NativeDispatcher[0]
      The [TabNavigation] property getter does not exist on type [Microsoft.UI.Xaml.Controls.FlipView]
fail: Uno.UI.Dispatching.NativeDispatcher[0]
      The [Y] property getter does not exist on type [Windows.Foundation.Point]
fail: Uno.UI.Dispatching.NativeDispatcher[0]
      The [X] property getter does not exist on type [Windows.Foundation.Point]

At this point, a description of the relation between NativeAOT and
Reflection would be useful.

Parts of System.Reflection can be used. Which parts can be used,
and how to use them, is oddly not well specified in the
Native AOT deployment documentation.

What doesn't work is outlined in the limitations section:

  • No dynamic loading, for example, Assembly.LoadFile.
  • No run-time code generation, for example, System.Reflection.Emit.

What always appears to work is:

  • Type.GetType() returns a Type instance.

What can work is:

  • Type.GetType(string), so long as an assembly-qualified name
    is used as a string constant

    // bad
    string name = GetSomeTypeName();
    Type type = Type.GetType(name);
    
    // good
    Type type = Type.GetType("My.Example.TypeName, ExampleAssembly");
    
  • Type.GetMethod(string), but see fine print below.

  • Type.GetProperty(string), but see fine print below.

  • MethodInfo.Invoke()

The Fine Print: in order for many Reflection-based APIs such as
Type.GetMethod(string) to work, the program must contain
"reflection metadata."

We can now describe, briefly, what NativeAOT does:

  1. Accept IL/assemblies as input

  2. Internally trim the IL, optimizes them, etc.

  3. Generates a native binary containing two separate bits of data:

    • Native machine code for execution
    • "reflection metadata"

You can get an inkling of what methods survived trimming and become
native code by using dotnet publish -p:IlcGenerateMapFile=true …,
which will produce a .mstat file, a PE file which references every
type and member which is in the native binary, after inlining.
(Meaning if a member is inlined, it won't be present!)
Use e.g. monodis --memberref App.mstat to list post-trimmed members.

You can get an inkling of the "reflection metadata" that is present
by using dotnet publish -p:IlcGenerateMetadataLog=true …, which
produces a .metadata.csv file. It's not particularly scrutible,
but can be used to verify observed behavior. Consider one of the above
failure messages:

The [TabNavigation] property getter does not exist on type [Microsoft.UI.Xaml.Controls.FlipView]

An obvious question to ask: is the TabNavigation property in the
reflection metadata? Search for "TabNavigation" (with quotes!),
and it's not in there. Compare to when this commit is in use, and:

66087019, Property, "TabNavigation", "3410be9a 6810bea8 5410beae 5410beb2"
3410be9a, ConstantStringValue, "TabNavigation", ""

The 3rd column is the property name TabNavigation, while the 2nd
column is the type; for properties, we want Property. The 4th
column is "Children", one of which is:

5410beae, MethodSemantics, "Getter : [HasThis]  Microsoft.UI.Xaml.Input.KeyboardNavigationMode get_TabNavigation()", "50086c65"

which at least verifies that TabNavigation is in play.

Programs can control what is contained within reflection metadata
by using string constants with Reflection APIs, for example:

typeof(SomeKnownType).GetMethod("ConstantName")

will ensure that reflection metadata contains
SomeKnownType.ConstantName(), and ConstantName() will be returned
from typeof(SomeKnownType).GetMethods() and can be invoked with
MethodInfo.Invoke().

If you don't use typeof(SomeKnownType) or string constants with
Type.GetType(string) or type.GetMethod("constant"), then you need
to "suggest" that some pieces of information be added to
reflection metadata.

The two predominant ways to do this are via the custom attributes:

From the Uno perspective, enter BindingPropertyHelper: everything
is based on Reflection!

Fortunately NativeAOT "supports" Reflection! (See above.)

Unfortunately, we now need to convince NativeAOT to store the
reflection metadata Uno requires in order to work!

Various other PRs have dealt with some of this, such as #21920.

Returning to the original failure messages, e.g.

fail: Uno.UI.Dispatching.NativeDispatcher[0]
      The [TabNavigation] property getter does not exist on type [Microsoft.UI.Xaml.Controls.FlipView]

During the app build, src/SourceGenerators/Uno.UI.SourceGenerators
generates a BindableMetadata.g.cs file which will mention
[Bindable] types, e.g. for Microsoft.UI.Xaml.Controls.FlipView:

/// <summary>
/// Builder for Microsoft.UI.Xaml.Controls.FlipView
/// </summary>
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
static class MetadataBuilder_239
{
  internal static global::Uno.UI.DataBinding.IBindableType Build(global::Uno.UI.DataBinding.BindableType parent)
  {
    var bindableType = parent ?? new global::Uno.UI.DataBinding.BindableType(151, typeof(global::Microsoft.UI.Xaml.Controls.FlipView));
    // …
  }
  private static object CreateInstance() => new global::Microsoft.UI.Xaml.Controls.FlipView();
}

BindableMetadata.g.cs was needed in the ye olde Xamarin world order
to tell its linker to e.g. "preserve the FlipView default ctor!"

Now, we can build upon this infrastructure and update BindableType
to request that Reflection information regarding properties, fields,
and constructors be retained. We can do this by updating the
BindableType constructor:

partial class BindableType {
  internal const DynamicallyAccessedMemberTypes TypeRequirements =
    DynamicallyAccessedMemberTypes.PublicProperties | …;
  public BindableType(int estimatedPropertySize, [DynamicallyAccessedMembers(TypeRequirements)] Type sourceType) => …
}

Because we have BindableMetadata.g.cs and because it provides
typeof(FlipView), this directs NativeAOT to make property and other
reflection metadata available to the app, fixing the error messages.

Expand this addition of [DynamicallyAccessedMembers] to also include
BindableProperty and related types.

Note: the IL2111 warning "Method 'System.Type.TypeInitializer.get' …"
is caused by typeof(Type) (?!), which is particularly odd given
that we don't use Type.TypeInitializer!
Thanks to Alexander Köplinger for looking into this.

@jonpryor
jonpryor requested a review from jeromelaban December 2, 2025 21:02
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22017/docs/index.html

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-22017/wasm-skia-net9/index.html

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 186025 found UI Test snapshots differences: android-28-net9: 16, android-28-net9-Snap: 32, ios: 5, ios-Snap: 46, skia-linux-screenshots: 71, skia-windows-screenshots: 115, wasm: 137, wasm-automated-net10.0-WinUI-Benchmarks-automated: 0, wasm-automated-net10.0-WinUI-Default-automated: 12, wasm-automated-net10.0-WinUI-RuntimeTests-0: 0, wasm-automated-net10.0-WinUI-RuntimeTests-1: 0, wasm-automated-net10.0-WinUI-RuntimeTests-2: 0

Details
  • android-28-net9: 16 changed over 825

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Detereminate_ProgressRing_Validation50_[#FF0000_#008000_#008000_#FF0000]_Progress-Ring-Value-50
    • NativeCommandBar_Size_Uno_UI_Samples_Content_UITests_CommandBar_CommandBar_Dynamic
    • WebView_NavigateToAnchor_Uno_UI_Samples_Content_UITests_WebView_WebView_AnchorNavigation
    • When_SingleSelectionWithItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_SingleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • ProgressRing_IsEnabled_Running_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • When_Parent_PointerMoved_After_drag_on_non-scrolling_ScrollViewer
    • ListView_ListViewWithHeader_InitializesTest_SamplesApp_Windows_UI_Xaml_Controls_ListView_HorizontalListViewGrouped
    • ProgressRing_Visibility_Collapsed_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • UpDownEnabledTest_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • When_Parent_PointerMoved_After_drag_on_ScrollViewer_-_touch
    • When_NoSelection_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_MultipleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • WebView_NavigateToAnchor_Initial
    • Detereminate_ProgressRing_Validation75_[#FF0000_#008000_#008000_#008000]_Progress-Ring-Value-75
    • Detereminate_ProgressRing_Validation25_[#FF0000_#008000_#FF0000_#FF0000]_Progress-Ring-Value-25
  • android-28-net9-Snap: 32 changed over 1077

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • CommandBarFlyout_MUXControlsTestApp_CommandBarFlyoutPage_MUXControlsTestApp_CommandBarFlyoutPage
    • Gesture_Recognizer_Pointer_Events_test_bench_UITests_Shared_Windows_UI_Input_GestureRecognizer_PointersEvents
    • MUX_NumberBox_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • ListView_ListViewSelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • ListView_ListView_With_ListViews_Count_Measure_UITests_Shared_Windows_UI_Xaml_Controls_ListView_ListView_With_ListViews_Count_Measure
    • NavigationView_MUXControlsTestApp_NavigationViewTopNavOnlyPage_MUXControlsTestApp_NavigationViewTopNavOnlyPage
    • NavigationView_MUXControlsTestApp_NavigationViewTopNavPage_MUXControlsTestApp_NavigationViewTopNavPage
    • Scrolling_MUXControlsTestApp_ScrollViewDynamicPage_MUXControlsTestApp_ScrollViewDynamicPage
    • Image_UITests_Windows_UI_Xaml_Controls_ImageTests_SvgImageSource_Basic_UITests_Windows_UI_Xaml_Controls_ImageTests_SvgImageSource_Basic
    • TextBlock_UITests_Shared_Windows_UI_Xaml_Controls_TextBlockControl_TextBlock_Layout_UITests_Shared_Windows_UI_Xaml_Controls_TextBlockControl_TextBlock_Layout
    • MediaPlayerElement_Mini_player_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Minimal
    • MUX_UITests_Shared_Microsoft_UI_Xaml_Controls_TreeViewTests_TreeViewPage_UITests_Shared_Microsoft_UI_Xaml_Controls_TreeViewTests_TreeViewPage
    • TeachingTip_UITests_Microsoft_UI_Xaml_Controls_TeachingTipTests_TeachingTipPage_UITests_Microsoft_UI_Xaml_Controls_TeachingTipTests_TeachingTipPage
    • Transform_Basics_UITests_Shared_Windows_UI_Xaml_Media_Transform_Basics
    • WebView_WebView_JavascriptInvoke_Uno_UI_Samples_Content_UITests_WebView_WebView_JavascriptInvoke
    • RatingControl_UITests_Microsoft_UI_Xaml_Controls_RatingControlTests_RatingControlPage_UITests_Microsoft_UI_Xaml_Controls_RatingControlTests_RatingControlPage
    • MediaPlayerElement_Using_3gp_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_3gp_Extension
    • MediaPlayerElement_Using_mp3_Audio_only_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Mp3_Extension
    • MediaPlayerElement_Using_ogg_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Ogg_Extension
    • WebView_WebView_NavigateToUri_Uno_UI_Samples_Content_UITests_WebView_WebView_NavigateToUri
  • ios: 5 changed over 255

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • ProgressRing_Visibility_Collapsed_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • Check_ListView_Swallows_Measure_UITests_Shared_Windows_UI_Xaml_Controls_ListView_ListView_With_ListViews_Count_Measure
    • ListView_SelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • ProgressRing_IsEnabled_Running_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • SequentialAnimations_SamplesApp_Windows_UI_Xaml_Media_Animation_SequentialAnimationsPage
  • ios-Snap: 46 changed over 994

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Brushes_Uno_UI_Samples_UITests_ImageBrushTestControl_DoubleImageBrushInList_Uno_UI_Samples_UITests_ImageBrushTestControl_DoubleImageBrushInList
    • TabView_MUXControlsTestApp_TabViewPage_MUXControlsTestApp_TabViewPage
    • Brushes_PathImageBrushfill_Uno_UI_Samples_UITests_ImageBrushTestControl_PathImageBrushfill
    • Brushes_Uno_UI_Samples_Samples_Shared_Content_UITests_ImageBrushInList_Uno_UI_Samples_Samples_Shared_Content_UITests_ImageBrushInList
    • ColorPicker_WinUIColorPickerPage_UITests_Shared_Microsoft_UI_Xaml_Controls_ColorPickerTests_WinUIColorPickerPage
    • Icons_UITests_Shared_Windows_UI_Xaml_Controls_BitmapIconTests_BitmapIcon_Foreground_UITests_Shared_Windows_UI_Xaml_Controls_BitmapIconTests_BitmapIcon_Foreground
    • Microsoft_UI_Xaml_Media_UITests_Windows_UI_Xaml_Media_ThemeShadowTests_ThemeShadow_Overlap_UITests_Windows_UI_Xaml_Media_ThemeShadowTests_ThemeShadow_Overlap
    • ContentControl_ContentControl_Nested_TemplatedParent_Uno_UI_Samples_Content_UITests_ContentControlTestsControl_ContentControl_Nested_TemplatedParent
    • Grid_CenteredGridinGridwiththreefixedsizechildren_Uno_UI_Samples_Content_UITests_GridTestsControl_CenteredGridinGridwiththreefixedsizechildren
    • Brushes_ImageBrushStretch2_Uno_UI_Samples_UITests_ImageBrushTestControl_ImageBrushStretch2
    • Image_Image_Stretch_None_Uno_UI_Samples_UITests_ImageTestsControl_Image_Stretch_None
    • Image_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Wider_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Wider
    • TextBlock_TextBlock_FixedWidth_With_DataBound_Run_Uno_UI_Samples_Content_UITests_TextBlockControl_TextBlock_FixedWidth_With_DataBound_Run
    • Brushes_BorderImageBrush_Uno_UI_Samples_UITests_ImageBrushTestControl_BorderImageBrush
    • Flyouts_UITests_Windows_UI_Xaml_Controls_Flyout_Flyout_TemplatedParent_UITests_Windows_UI_Xaml_Controls_Flyout_Flyout_TemplatedParent
    • Image_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Horizontal_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Horizontal
    • Image_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Vertical_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Vertical
    • Image_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Alignment_SizeOnControl_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Alignment_SizeOnControl
    • Pickers_TimePicker_TimePickerFlyoutStyle_UITests_Windows_UI_Xaml_Controls_TimePicker_TimePicker_TimePickerFlyoutStyle
    • UIElement_TransformToVisual_Simple_UITests_Shared_Windows_UI_Xaml_UIElementTests_TransformToVisual_Simple
  • skia-linux-screenshots: 71 changed over 2306

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • CalendarView_Theming.png-dark
    • CalendarView_Theming.png
    • ImageBrushAlignmentXY2.png-dark
    • ImageBrushAlignmentXY2.png
    • ClipboardTests.png-dark
    • Focus_FocusVisual_Properties.png-dark
    • ButtonClippingTestsControl.png-dark
    • ColorPickerSample.png-dark
    • ColorPickerSample.png
    • ImagesInlineInFlipView.png-dark
    • ImagesInlineInFlipView.png
    • ImageSourceUrlMsAppDataScheme.png-dark
    • ImageSourceUrlMsAppDataScheme.png
    • ButtonClippingTestsControl.png
    • Buttons.png-dark
    • DoubleImageBrushInList.png-dark
    • DoubleImageBrushInList.png
    • ImageIconPage.png-dark
    • ImageIconPage.png
    • ClipboardTests.png
  • skia-windows-screenshots: 115 changed over 2306

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • DisplayInformation.png-dark
    • DropDownButtonPage.png-dark
    • ClipboardTests.png-dark
    • Basics_Automated.png-dark
    • BitmapIcon_Monochromatic.png
    • CalendarView_Theming.png
    • Examples.png-dark
    • Examples.png
    • ImageWithLateSource.png-dark
    • ImageWithLateSource.png
    • ImageWithNoSpecificSize.png-dark
    • ImageWithNoSpecificSize.png
    • Image_Fixed_Size_Alignment.png-dark
    • Image_Fixed_Size_Alignment.png
    • Border_With_Off_Centre_RotateTransform.png
    • ButtonClippingTestsControl.png-dark
    • ButtonClippingTestsControl.png
    • Basics.png
    • Border_With_Off_Centre_ScaleTransform.png-dark
    • Border_With_Off_Centre_ScaleTransform.png
  • wasm: 137 changed over 1058

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • MUXControlsTestApp.NavigationViewMenuItemStretchPage
    • MUXControlsTestApp.NavigationViewStretchPage
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ListView.ListView_IsSelected
    • UITests.Microsoft_UI_Xaml_Controls.TreeView.TreeViewBasics
    • UITests.Microsoft_UI_Xaml_Controls.TreeViewTests.TreeView_ItemInvoked
    • UITests.Shared.Windows_Graphics_Display.DisplayInformationTests
    • UITests.Shared.Windows_UI_ViewManagement.TitleBarColorTests
    • UITests.Shared.Windows_UI_Xaml_Controls.Popup.Popup_LightDismiss
    • UITests.Shared.Windows_UI_Xaml_Controls.ScrollViewerTests.Hosted_ScrollViewer
    • UITests.Windows_UI_Input.PointersTests.HitTest_LightDismiss
    • UITests.Windows_UI_Input.PointersTests.HitTest_Shapes
    • UITests.Windows_UI_Xaml_Media_Animation.ColorAnimation_Background
    • UITests.Windows_UI_Xaml_Media_Animation.ColorAnimation_Fill
    • UITests.Windows_UI_Xaml_Media_Animation.DoubleAnimation_FinalState_Opacity
    • GenericApp.Views.Samples.Shared.Content.UITests.GridViewMultipleSelectionMode
    • MUXControlsTestApp.ScrollViewPage
    • MUXControlsTestApp.SwipeControlPage
    • UITests.Microsoft_UI_Xaml_Controls.RadioButtonsTests.RadioButtonsBasicPage
    • UITests.Shared.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_NavigateToString2
    • UITests.Shared.Microsoft_UI_Xaml_Controls.ExpanderTests.Expander_ScrollView
  • wasm-automated-net10.0-WinUI-Benchmarks-automated: 0 changed over 1

  • wasm-automated-net10.0-WinUI-Default-automated: 12 changed over 877

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Default_StrokeThickness_MyLine
    • Default_StrokeThickness_MyPolygon
    • Default_StrokeThickness_MyRect
    • TestProgressRing_InitialState_UITests_Microsoft_UI_Xaml_Controls_ProgressRing_WinUIProgressRing_Features
    • ListView_SelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • SequentialAnimations_SamplesApp_Windows_UI_Xaml_Media_Animation_SequentialAnimationsPage
    • Default_StrokeThickness_MyEllipse
    • Default_StrokeThickness_MyPolyline
    • When_StretchAndAlignmentNone_ImageBrush-50-50-None-XLeft-YBottom
    • When_NoSelection_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_Theme_Changed_No_Crash_UITests_Windows_UI_Xaml_Controls_CalendarView_CalendarView_Theming
    • Default_StrokeThickness_MyPath
  • wasm-automated-net10.0-WinUI-RuntimeTests-0: 0 changed over 1

  • wasm-automated-net10.0-WinUI-RuntimeTests-1: 0 changed over 1

  • wasm-automated-net10.0-WinUI-RuntimeTests-2: 0 changed over 1

@unodevops

Copy link
Copy Markdown
Contributor

⚠️⚠️ The build 186025 has failed on Uno.UI - CI.

@jonpryor
jonpryor force-pushed the dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers branch 2 times, most recently from 47c9883 to 5845044 Compare December 3, 2025 15:37
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22017/docs/index.html

1 similar comment
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22017/docs/index.html

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-22017/wasm-skia-net9/index.html

@unodevops

Copy link
Copy Markdown
Contributor

⚠️⚠️ The build 186160 has failed on Uno.UI - CI.

@jonpryor
jonpryor force-pushed the dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers branch from 5845044 to 3890a29 Compare December 3, 2025 20:16
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22017/docs/index.html

@jonpryor
jonpryor force-pushed the dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers branch from 3890a29 to 31b1df5 Compare December 3, 2025 21:24
jonpryor added a commit to unoplatform/uno.toolkit.ui that referenced this pull request Dec 3, 2025
Context: unoplatform/uno#22017

While running the uno.chefs app on macOS under NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop -bl \
	  Chefs/Chefs.csproj -p:SelfContained=true -p:PublishAot=true -p:IsAotCompatible=true -p:UseSkiaRendering=true \
	  -p:IlcGenerateMapFile=true -p:IlcGenerateMstatFile=true -p:IlcGenerateDgmlFile=true -p:IlcGenerateMetadataLog=true \
	  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
	Chefs/bin/Release/net10.0-desktop/osx-x64/publish/Chefs

Console output would contain the following errors:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Uno.Toolkit.UI:ProgressExtensions.IsActive] property getter does not exist on type [Microsoft.UI.Xaml.Controls.ContentControl]

The `Uno.Toolkit.UI:ProgressExtensions.IsActive` property is an
*attached* property, from `ProgressExtensions.IsActive`:

	static partial class ProgressExtensions {
	  public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
	      "IsActive",
	      typeof(bool),
	      typeof(ProgressExtensions),
	      new PropertyMetadata(false, IsActiveChanged));
	  public static bool GetIsActive(FrameworkElement element) => …;
	  public static void SetIsActive(FrameworkElement element, bool value) => …;
	}

Attached properties work by using Reflection to look for methods with
`Get` and `Set` prefixes before the property name, in this case
`GetIsActive()` and `SetIsActive()`.

NativeAOT cannot statically determine that `GetIsActive()` and
`SetIsActive()` are used, and thus doesn't emit any reflection metadata
for these members.  This can be verified by consulting the generated
`Chefs.metadata.csv` file, which only contains these entries for
`GetIsActive` and `SetIsActive`:

	3424256a, ConstantStringValue, "GetIsActive", ""

The [`[DynamicDependency]`][0] custom attribute can be used to inform
NativeAOT of this dependency, by listing the names of members which
should be preserved:

	static partial class ProgressExtensions {
	  [DynamicDependency(nameof(GetIsActive))]
	  [DynamicDependency(nameof(SetIsActive))]
	  public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
	      "IsActive",
	      typeof(bool),
	      typeof(ProgressExtensions),
	      new PropertyMetadata(false, IsActiveChanged));
	}

With this change in place, the originating failure message is no
longer emitted, and `Chefs.metadata.csv` contains:

	500b1f0b, Method, "System.Boolean GetIsActive(Microsoft.UI.Xaml.FrameworkElement)", "34141647 56141653 620c0acd"
	500b1f1a, Method, "System.Void SetIsActive(Microsoft.UI.Xaml.FrameworkElement, System.Boolean)", "3414165f 5614166b 620c0acd 6206708f"
	34141647, ConstantStringValue, "GetIsActive", ""
	3414165f, ConstantStringValue, "SetIsActive", ""
	4214168b, CustomAttribute, "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.[HasThis]  System.Void .ctor(System.String)(\"GetIsActive\")(ctor: Internal.Metadata.NativeFormat.Handle", "6c1c41df 34141647"
	42141695, CustomAttribute, "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.[HasThis]  System.Void .ctor(System.String)(\"SetIsActive\")(ctor: Internal.Metadata.NativeFormat.Handle", "6c1c41df 3414165f"

Review all usage of `DependencyProperty.RegisterAttached()` and add
`[DynamicDependency]` attributes as appropriate.

[0]: https://learn.microsoft.comdotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-10.0
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22017/docs/index.html

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-22017/wasm-skia-net9/index.html

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 186212 found UI Test snapshots differences: android-28-net9: 16, android-28-net9-Snap: 28, ios: 7, ios-Snap: 59, skia-linux-screenshots: 63, skia-windows-screenshots: 109, wasm: 136, wasm-automated-net10.0-WinUI-Benchmarks-automated: 0, wasm-automated-net10.0-WinUI-Default-automated: 13, wasm-automated-net10.0-WinUI-RuntimeTests-0: 0, wasm-automated-net10.0-WinUI-RuntimeTests-1: 0, wasm-automated-net10.0-WinUI-RuntimeTests-2: 0

Details
  • android-28-net9: 16 changed over 825

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Detereminate_ProgressRing_Validation50_[#FF0000_#008000_#008000_#FF0000]_Progress-Ring-Value-50
    • ListView_ListViewWithHeader_InitializesTest_SamplesApp_Windows_UI_Xaml_Controls_ListView_HorizontalListViewGrouped
    • Detereminate_ProgressRing_Validation75_[#FF0000_#008000_#008000_#008000]_Progress-Ring-Value-75
    • When_NoSelection_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • UpDownEnabledTest_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • When_SingleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • FlyoutTest_When_NoOverlayInputPassThroughElement_Then_DontPassThrough_woOff_UITests_Shared_Windows_UI_Xaml_Controls_Flyout_Flyout_OverlayInputPassThroughElement
    • NativeCommandBar_Size_Uno_UI_Samples_Content_UITests_CommandBar_CommandBar_Dynamic
    • ProgressRing_IsEnabled_Running_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • WebView_NavigateToAnchor_Initial
    • When_Parent_PointerMoved_After_drag_on_ScrollViewer_-_touch
    • DecimalFormatterTest_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • When_NoSelectionWithItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • Detereminate_ProgressRing_Validation25_[#FF0000_#008000_#FF0000_#FF0000]_Progress-Ring-Value-25
    • ProgressRing_Visibility_Collapsed_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • When_SingleSelectionWithItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
  • android-28-net9-Snap: 28 changed over 1077

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • NavigationView_MUXControlsTestApp_NavigationViewRS4Page_MUXControlsTestApp_NavigationViewRS4Page
    • MUX_NumberBox_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • TeachingTip_UITests_Microsoft_UI_Xaml_Controls_TeachingTipTests_TeachingTipPage_UITests_Microsoft_UI_Xaml_Controls_TeachingTipTests_TeachingTipPage
    • Image_UITests_Windows_UI_Xaml_Controls_ImageTests_SvgImageSource_Icons_UITests_Windows_UI_Xaml_Controls_ImageTests_SvgImageSource_Icons
    • ListView_ListView_With_ListViews_Count_Measure_UITests_Shared_Windows_UI_Xaml_Controls_ListView_ListView_With_ListViews_Count_Measure
    • MUX_UITests_Shared_Microsoft_UI_Xaml_Controls_TreeViewTests_TreeViewPage_UITests_Shared_Microsoft_UI_Xaml_Controls_TreeViewTests_TreeViewPage
    • RatingControl_UITests_Microsoft_UI_Xaml_Controls_RatingControlTests_RatingControlPage_UITests_Microsoft_UI_Xaml_Controls_RatingControlTests_RatingControlPage
    • TextBlock_UITests_Shared_Windows_UI_Xaml_Controls_TextBlockControl_TextBlock_Layout_UITests_Shared_Windows_UI_Xaml_Controls_TextBlockControl_TextBlock_Layout
    • Gesture_Recognizer_Pointer_Events_test_bench_UITests_Shared_Windows_UI_Input_GestureRecognizer_PointersEvents
    • MediaPlayerElement_Mini_player_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Minimal
    • NavigationView_MUXControlsTestApp_NavigationViewCustomThemeResourcesPage_MUXControlsTestApp_NavigationViewCustomThemeResourcesPage
    • CommandBar_Examples_Uno_UI_Samples_Content_UITests_CommandBar_CommandBar_Examples
    • CommandBarFlyout_MUXControlsTestApp_CommandBarFlyoutPage_MUXControlsTestApp_CommandBarFlyoutPage
    • ListView_ListViewSelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • MediaPlayerElement_Using_3gp_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_3gp_Extension
    • MediaPlayerElement_Using_mp3_Audio_only_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Mp3_Extension
    • MediaPlayerElement_Using_ogg_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Ogg_Extension
    • Transform_Basics_UITests_Shared_Windows_UI_Xaml_Media_Transform_Basics
    • NavigationView_MUXControlsTestApp_NavigationViewTopNavOnlyPage_MUXControlsTestApp_NavigationViewTopNavOnlyPage
    • NavigationView_MUXControlsTestApp_NavigationViewTopNavPage_MUXControlsTestApp_NavigationViewTopNavPage
  • ios: 7 changed over 255

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • ProgressRing_IsEnabled_Running_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • Validate_Offscreen_Shapes_UITests_Windows_UI_Xaml_Shapes_Offscreen_Shapes
    • ListView_SelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • ProgressRing_Visibility_Collapsed_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • TextBox_UpdatedBinding_On_OneWay_Mode_UITests_Windows_UI_Xaml_Controls_TextBox_TextBox_Bindings
    • Check_ListView_Swallows_Measure_UITests_Shared_Windows_UI_Xaml_Controls_ListView_ListView_With_ListViews_Count_Measure
    • ImageStretch_None_Uno_UI_Samples_UITests_ImageTestsControl_Image_Stretch_None
  • ios-Snap: 59 changed over 994

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Default_UITests_Windows_UI_Xaml_Controls_Canvas_Grid_ZIndex_UITests_Windows_UI_Xaml_Controls_Canvas_Grid_ZIndex
    • Performance_UITests_Windows_UI_Xaml_Performance_Performance_1000ButtonsContinuousRendering_UITests_Windows_UI_Xaml_Performance_Performance_1000ButtonsContinuousRendering
    • TextBlock_Attributed_text_Simple_Uno_UI_Samples_Content_UITests_TextBlockControl_Attributed_text_Simple
    • Brushes_UITests_Shared_Windows_UI_Xaml_Media_ImageBrushTests_ImageBrush_SameWithDelay_UITests_Shared_Windows_UI_Xaml_Media_ImageBrushTests_ImageBrush_SameWithDelay
    • Brushes_RectangleStretchFill_Uno_UI_Samples_UITests_ImageBrushTestControl_RectangleStretchFill
    • Brushes_PanelImageBrush_Uno_UI_Samples_UITests_ImageBrushTestControl_PanelImageBrush
    • Brushes_UITests_Windows_UI_Xaml_Media_BrushesTests_RevealBrush_Fallback_UITests_Windows_UI_Xaml_Media_BrushesTests_RevealBrush_Fallback
    • ContentControl_ContentControl_SelectorInheritance_Uno_UI_Samples_Content_UITests_ContentControlTestsControl_ContentControl_SelectorInheritance
    • Icons_UITests_Shared_Windows_UI_Xaml_Controls_BitmapIconTests_BitmapIcon_Foreground_UITests_Shared_Windows_UI_Xaml_Controls_BitmapIconTests_BitmapIcon_Foreground
    • Image_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Vertical_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Vertical
    • Image_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Alignment_SizeOnControl_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Alignment_SizeOnControl
    • ItemsControl_UITests_Windows_UI_Xaml_Controls_ItemsControl_ItemsControl_ReplaceItem_UITests_Windows_UI_Xaml_Controls_ItemsControl_ItemsControl_ReplaceItem
    • MediaPlayerElement_Using_ogg_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Ogg_Extension
    • Microsoft_UI_Composition_UITests_Windows_UI_Composition_MixTransformCliPropertyAndClippedByParentWithBorders_Then_RenderingIsValid_UITests_Windows_UI_Composition_MixTransformCliPropertyAndClippedByParentWithBorders_Then_RenderingIsValid
    • Microsoft_UI_Composition_UITests_Windows_UI_Composition_TransformElementClippedByParentWithBorder_Then_ClippingAppliedPostRendering_UITests_Windows_UI_Composition_TransformElementClippedByParentWithBorder_Then_ClippingAppliedPostRendering
    • Microsoft_UI_Composition_UITests_Shared_Windows_UI_Composition_SKCanvasElement_Simple_UITests_Shared_Windows_UI_Composition_SKCanvasElement_Simple
    • Microsoft_UI_Composition_UITests_Windows_UI_Composition_TransformElementClippedByParent_Then_ClippingAppliedPostRendering_UITests_Windows_UI_Composition_TransformElementClippedByParent_Then_ClippingAppliedPostRendering
    • Microsoft_UI_Composition_UITests_Windows_UI_Composition_InteractionTrackerAndExpressionAnimationSample_UITests_Windows_UI_Composition_InteractionTrackerAndExpressionAnimationSample
    • Microsoft_UI_Composition_UITests_Windows_UI_Composition_VisualRotationSample_UITests_Windows_UI_Composition_VisualRotationSample
    • Microsoft_UI_Xaml_Media_CompositionTarget_Rendering_UITests_Shared_Windows_UI_Xaml_Media_CompositionTargetTests_CompositionTarget_Rendering
  • skia-linux-screenshots: 63 changed over 2306

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • EllipsemaskingEllipseGrid.png-dark
    • EllipsemaskingEllipseGrid.png
    • CalendarView_Theming.png-dark
    • Buttons.png-dark
    • DisplayInformation.png-dark
    • BitmapIcon_Monochromatic.png
    • ButtonClippingTestsControl.png
    • ImageBrushInList.png-dark
    • ImageBrushInList.png
    • Gamepad_Enumeration.png-dark
    • Gamepad_Enumeration.png
    • ImageIconPage.png-dark
    • ImageIconPage.png
    • CalendarView_Theming.png
    • ClipboardTests.png-dark
    • CompositionEffectBrush.png-dark
    • CompositionEffectBrush.png
    • Gamepad_CurrentReading.png-dark
    • Gamepad_CurrentReading.png
    • Examples.png-dark
  • skia-windows-screenshots: 109 changed over 2306

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • DisplayInformation.png-dark
    • DisplayInformation.png
    • Gamepad_CurrentReading.png-dark
    • Gamepad_CurrentReading.png
    • Gamepad_Enumeration.png-dark
    • Gamepad_Enumeration.png
    • ButtonClippingTestsControl.png-dark
    • ButtonClippingTestsControl.png
    • ContentPresenter_NativeEmbedding_Android_FillType.png-dark
    • ContentPresenter_NativeEmbedding_Android_FillType.png
    • ContentPresenter_NativeEmbedding_ZIndex.png-dark
    • ContentPresenter_NativeEmbedding_ZIndex.png
    • DoubleImageBrushInList.png-dark
    • DoubleImageBrushInList.png
    • FileOpenPickerTests.png-dark
    • FileOpenPickerTests.png
    • FileOpenPicker_Bitmap.png-dark
    • FileOpenPicker_Bitmap.png
    • ImageSourceWriteableBitmapInvalidate.png-dark
    • ImageSourceWriteableBitmapInvalidate.png
  • wasm: 136 changed over 1058

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • GenericApp.Views.Samples.Shared.Content.UITests.GridViewMultipleSelectionMode
    • UITests.Microsoft_UI_Xaml_Controls.TreeViewTests.TreeView_ItemInvoked
    • UITests.Shared.Windows_ApplicationModel.Email.EmailManagerTests
    • UITests.Shared.Windows_UI_Xaml.ViusalStateTests.VisualState_AdaptiveTrigger_Storyboard
    • UITests.Shared.Windows_UI_Xaml_Controls.WebView.WebView_NavigateToString2
    • UITests.Uno_Web.Http.CookieManagerTests
    • UITests.Windows_ApplicationModel.DataTransfer.DataTransferManagerTests
    • UITests.Windows_UI_Xaml_Controls.TextBox.TextBox_ClipboardMethods
    • UITests.Windows_UI_Xaml_Controls.TextBox.TextBox_Focus_Programmatic
    • Uno.UI.Samples.Content.UITests.Animations.DoubleAnimation_BeginTime
    • Uno.UI.Samples.Content.UITests.Animations.DoubleAnimation_Cumulative
    • Uno.UI.Samples.Content.UITests.Animations.DoubleAnimation_VisualStates
    • initial_state
    • MUXControlsTestApp.CommandBarFlyoutMainPage
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ComboBox.ComboBox_CornerRadius
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ComboBox.ComboBox_Corners
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ListView.ListView_IsSelected
    • UITests.Shared.Windows_UI_Xaml_Controls.Button.Button_Events
    • UITests.Shared.Windows_UI_Xaml_Controls.TextBoxControl.TextBox_Binding_Null
    • UITests.Windows_UI_Xaml_Controls.PasswordBoxTests.PasswordBox_AutoFill
  • wasm-automated-net10.0-WinUI-Benchmarks-automated: 0 changed over 1

  • wasm-automated-net10.0-WinUI-Default-automated: 13 changed over 877

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Default_StrokeThickness_MyLine
    • When_MultipleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • Default_StrokeThickness_MyEllipse
    • ListView_SelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • Default_StrokeThickness_MyRect
    • TestProgressRing_InitialState_UITests_Microsoft_UI_Xaml_Controls_ProgressRing_WinUIProgressRing_Features
    • Default_StrokeThickness_MyPath
    • When_StretchAndAlignmentNone_ImageBrush-50-50-None-XLeft-YBottom
    • Default_StrokeThickness_MyPolyline
    • Check_CornerRadius_Border_CornerRadius=5
    • Default_StrokeThickness_MyPolygon
    • SequentialAnimations_SamplesApp_Windows_UI_Xaml_Media_Animation_SequentialAnimationsPage
    • When_TransformToVisual_ScrollViewer_UITests_Shared_Windows_UI_Xaml_UIElementTests_TransformToVisual_ScrollViewer
  • wasm-automated-net10.0-WinUI-RuntimeTests-0: 0 changed over 1

  • wasm-automated-net10.0-WinUI-RuntimeTests-1: 0 changed over 1

  • wasm-automated-net10.0-WinUI-RuntimeTests-2: 0 changed over 1

@unodevops

Copy link
Copy Markdown
Contributor

⚠️⚠️ The build 186212 has failed on Uno.UI - CI.

Context: unoplatform/uno.chefs#1712
Context: #21920
Context: unoplatform/uno.extensions#2966
Context: unoplatform/uno.extensions#2969
Context: https://discord.com/channels/732297728826277939/732297837953679412/1444909702512119899

While running the uno.chefs app on macOS under NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop -bl \
	  Chefs/Chefs.csproj \
	  -p:SelfContained=true -p:PublishAot=true -p:IsAotCompatible=true -p:UseSkiaRendering=true \
	  -p:IlcGenerateMapFile=true -p:IlcGenerateMstatFile=true -p:IlcGenerateDgmlFile=true \
	  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
	Chefs/bin/Release/net10.0-desktop/osx-x64/publish/Chefs

Console output would contain the following errors:

	fail: Uno.UI.Dispatching.NativeDispatcher[0]
	      The [TabNavigation] property getter does not exist on type [Microsoft.UI.Xaml.Controls.FlipView]
	fail: Uno.UI.Dispatching.NativeDispatcher[0]
	      The [Y] property getter does not exist on type [Windows.Foundation.Point]
	fail: Uno.UI.Dispatching.NativeDispatcher[0]
	      The [X] property getter does not exist on type [Windows.Foundation.Point]

At this point, a description of the relation between NativeAOT and
Reflection would be useful.

*Parts* of System.Reflection can be used.  Which parts *can* be used,
and how to use them, is oddly *not* well specified in the
[Native AOT deployment][0] documentation.

What doesn't work is outlined in the [limitations][1] section:

> * No dynamic loading, for example, `Assembly.LoadFile`.
> * No run-time code generation, for example, `System.Reflection.Emit`.

What *always* appears to work is:

  * `Type.GetType()` returns a `Type` instance.

What ***can*** work is:

  * `Type.GetType(string)`, *so long as* an assembly-qualified name
    is used as a *string constant*

        // bad
        string name = GetSomeTypeName();
        Type type = Type.GetType(name);

        // good
        Type type = Type.GetType("My.Example.TypeName, ExampleAssembly");

  * `Type.GetMethod(string)`, but see fine print below.
  * `Type.GetProperty(string)`, but see fine print below.
  * `MethodInfo.Invoke()`
  * …

**The Fine Print**: in order for many Reflection-based APIs such as
`Type.GetMethod(string)` to work, the program must contain
"reflection metadata."

We can now describe, briefly, what NativeAOT does:

 1. Accept IL/assemblies as input
 2. Internally trim the IL, optimizes them, etc.
 3. Generates a native binary containing two separate bits of data:

    * Native machine code for execution
    * "reflection metadata"

You can get an inkling of what methods survived trimming and become
native code by using `dotnet publish -p:IlcGenerateMstatFile=true …`,
which will produce a `.mstat` file, a PE file which references every
type and member which is in the native binary, ***after*** inlining.
(Meaning if a member is inlined, it *won't* be present!)
Use e.g. `monodis --memberref App.mstat` to list post-trimmed members.

You can get an inkling of the "reflection metadata" that is present
by using `dotnet publish -p:IlcGenerateMetadataLog=true …`, which
produces a `.metadata.csv` file.  It's not particularly scrutible,
but can be used to verify observed behavior.  Consider one of the above
failure messages:

	The [TabNavigation] property getter does not exist on type [Microsoft.UI.Xaml.Controls.FlipView]

An obvious question to ask: is the `TabNavigation` property in the
reflection metadata?  Search for `"TabNavigation"` (with quotes!),
and it's *not* in there.  Compare to when this commit is in use, and:

	66087019, Property, "TabNavigation", "3410be9a 6810bea8 5410beae 5410beb2"
	3410be9a, ConstantStringValue, "TabNavigation", ""

The 3rd column is the property name `TabNavigation`, while the 2nd
column is the type; for properties, we want `Property`.  The 4th
column is "Children", one of which is:

	5410beae, MethodSemantics, "Getter : [HasThis]  Microsoft.UI.Xaml.Input.KeyboardNavigationMode get_TabNavigation()", "50086c65"

which at least verifies that `TabNavigation` is in play.

Programs can control what is contained within reflection metadata
by using string constants with Reflection APIs, for example:

	typeof(SomeKnownType).GetMethod("ConstantName")

will ensure that reflection metadata contains
`SomeKnownType.ConstantName()`, and `ConstantName()` will be returned
from `typeof(SomeKnownType).GetMethods()` and can be invoked with
`MethodInfo.Invoke()`.

If you *don't* use `typeof(SomeKnownType)` or string constants with
`Type.GetType(string)` or `type.GetMethod("constant")`, then you need
to "suggest" that some pieces of information be added to
reflection metadata.

The two predominant ways to do this are via the custom attributes:

  * [`DynamicallyAccessedMembersAttribute`][2]
  * [`DynamicDependencyAttribute`][3]

From the Uno perspective, enter `BindingPropertyHelper`: *everything*
is based on Reflection!

Fortunately NativeAOT "supports" Reflection!  (See above.)

*Unfortunately*, we now need to convince NativeAOT to store the
reflection metadata Uno requires in order to work!

Various other PRs have dealt with some of this, such as #21920.

Returning to the original failure messages, e.g.

	fail: Uno.UI.Dispatching.NativeDispatcher[0]
	      The [TabNavigation] property getter does not exist on type [Microsoft.UI.Xaml.Controls.FlipView]

During the app build, `src/SourceGenerators/Uno.UI.SourceGenerators`
generates a `BindableMetadata.g.cs` file which will mention
`[Bindable]` types, e.g. for `Microsoft.UI.Xaml.Controls.FlipView`:

	/// <summary>
	/// Builder for Microsoft.UI.Xaml.Controls.FlipView
	/// </summary>
	[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
	static class MetadataBuilder_239
	{
	  internal static global::Uno.UI.DataBinding.IBindableType Build(global::Uno.UI.DataBinding.BindableType parent)
	  {
	    var bindableType = parent ?? new global::Uno.UI.DataBinding.BindableType(151, typeof(global::Microsoft.UI.Xaml.Controls.FlipView));
	    // …
	  }
	  private static object CreateInstance() => new global::Microsoft.UI.Xaml.Controls.FlipView();
	}

`BindableMetadata.g.cs` was needed in the ye olde Xamarin world order
to tell *its* linker to e.g. "preserve the `FlipView` default ctor!"

*Now*, we can build upon this infrastructure and update `BindableType`
to request that Reflection information regarding properties, fields,
and constructors be retained.  We can do this by updating the
`BindableType` constructor:

	partial class BindableType {
	  internal const DynamicallyAccessedMemberTypes TypeRequirements =
	    DynamicallyAccessedMemberTypes.PublicProperties | …;
	  public BindableType(int estimatedPropertySize, [DynamicallyAccessedMembers(TypeRequirements)] Type sourceType) => …
	}

*Because* we have `BindableMetadata.g.cs` *and* because it provides
`typeof(FlipView)`, this directs NativeAOT to make property and other
reflection metadata available to the app, *fixing* the error messages.

Expand this addition of `[DynamicallyAccessedMembers]` to also include
`BindableProperty` and related types.

Note: the IL2111 warning "Method 'System.Type.TypeInitializer.get' …"
is *caused by* `typeof(Type)` (?!), which is particularly odd given
that we don't use `Type.TypeInitializer`!
Thanks to Alexander Köplinger for [looking into this][4].

[0]: https://learn.microsoft.comdotnet/core/deploying/native-aot
[1]: https://learn.microsoft.comdotnet/core/deploying/native-aot/#limitations-of-native-aot-deployment
[2]: https://learn.microsoft.comdotnet/api/system.diagnostics.codeanalysis.dynamicallyaccessedmembersattribute?view=net-10.0
[3]: https://learn.microsoft.comdotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-10.0
[4]: https://discord.com/channels/732297728826277939/732297837953679412/1445773677152174150
@jonpryor
jonpryor force-pushed the dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers branch from 31b1df5 to 559b1f7 Compare December 4, 2025 12:13
@github-actions github-actions Bot added the area/code-generation Categorizes an issue or PR as relevant to code generation label Dec 4, 2025
@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-22017/wasm-skia-net9/index.html

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-22017/docs/index.html

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 186269 found UI Test snapshots differences: android-28-net9: 20, android-28-net9-Snap: 30, ios: 5, ios-Snap: 52, skia-linux-screenshots: 62, skia-windows-screenshots: 113, wasm: 142, wasm-automated-net10.0-WinUI-Benchmarks-automated: 0, wasm-automated-net10.0-WinUI-Default-automated: 14, wasm-automated-net10.0-WinUI-RuntimeTests-0: 0, wasm-automated-net10.0-WinUI-RuntimeTests-1: 0, wasm-automated-net10.0-WinUI-RuntimeTests-2: 0

Details
  • android-28-net9: 20 changed over 825

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • DecimalFormatterTest_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • Detereminate_ProgressRing_Validation75_[#FF0000_#008000_#008000_#008000]_Progress-Ring-Value-75
    • FocusManager_GetFocusedElement_Border_Validation_FocusManager_-_GetFocusedElement_-_Border_-_2_-_After_Selection
    • FlyoutTest_When_NoOverlayInputPassThroughElement_Then_DontPassThrough_woOff_UITests_Shared_Windows_UI_Xaml_Controls_Flyout_Flyout_OverlayInputPassThroughElement
    • FocusManager_GetFocusedElement_Border_Validation_Uno_UI_Samples_Content_UITests_FocusTests_FocusManager_GetFocus_Automated
    • ListView_ListViewWithHeader_InitializesTest_SamplesApp_Windows_UI_Xaml_Controls_ListView_HorizontalListViewGrouped
    • ProgressRing_IsEnabled_Running_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • NativeCommandBar_Size_Uno_UI_Samples_Content_UITests_CommandBar_CommandBar_Dynamic
    • ProgressRing_Visibility_Collapsed_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • SequentialAnimations_SamplesApp_Windows_UI_Xaml_Media_Animation_SequentialAnimationsPage
    • WebView_NavigateToAnchor_Initial
    • When_Parent_PointerMoved_After_drag_on_non-scrolling_ScrollViewer
    • When_NoSelection_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • UpDownEnabledTest_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • When_SingleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_SingleSelectionWithItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_MultipleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • FocusManager_GetFocusedElement_Border_Validation_FocusManager_-_GetFocusedElement_-_Border_-_1_-_Initial_State
    • Detereminate_ProgressRing_Validation50_[#FF0000_#008000_#008000_#FF0000]_Progress-Ring-Value-50
    • When_Parent_PointerMoved_After_drag_on_ScrollViewer_-_touch
  • android-28-net9-Snap: 30 changed over 1077

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • NavigationView_MUXControlsTestApp_NavigationViewTopNavOnlyPage_MUXControlsTestApp_NavigationViewTopNavOnlyPage
    • MUX_UITests_Shared_Microsoft_UI_Xaml_Controls_TreeViewTests_TreeViewPage_UITests_Shared_Microsoft_UI_Xaml_Controls_TreeViewTests_TreeViewPage
    • MediaPlayerElement_Mini_player_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Minimal
    • MUX_NumberBox_UITests_Shared_Microsoft_UI_Xaml_Controls_NumberBoxTests_NumberBoxPage
    • Transform_Basics_UITests_Shared_Windows_UI_Xaml_Media_Transform_Basics
    • NavigationView_MUXControlsTestApp_NavigationViewTopNavPage_MUXControlsTestApp_NavigationViewTopNavPage
    • Windows_Media_MediaPlayer_UITests_Windows_Media_MediaPlayerTests
    • NavigationView_MUXControlsTestApp_NavigationViewCustomThemeResourcesPage_MUXControlsTestApp_NavigationViewCustomThemeResourcesPage
    • SwipeControl_MUXControlsTestApp_SwipeControlPage2_MUXControlsTestApp_SwipeControlPage2
    • Pickers_UITests_Windows_UI_Xaml_Controls_CalendarView_CalendarView_Theming_UITests_Windows_UI_Xaml_Controls_CalendarView_CalendarView_Theming
    • Scrolling_MUXControlsTestApp_ScrollViewWithScrollControllersPage_MUXControlsTestApp_ScrollViewWithScrollControllersPage
    • MediaPlayerElement_Using_mp3_Audio_only_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Mp3_Extension
    • MediaPlayerElement_Using_ogg_UITests_Shared_Windows_UI_Xaml_Controls_MediaPlayerElement_MediaPlayerElement_Ogg_Extension
    • WebView_WebView_NavigateToUri_Uno_UI_Samples_Content_UITests_WebView_WebView_NavigateToUri
    • Icons_UITests_Shared_Windows_UI_Xaml_Controls_BitmapIconTests_BitmapIcon_Foreground_UITests_Shared_Windows_UI_Xaml_Controls_BitmapIconTests_BitmapIcon_Foreground
    • Image_UITests_Windows_UI_Xaml_Controls_ImageTests_SvgImageSource_Icons_UITests_Windows_UI_Xaml_Controls_ImageTests_SvgImageSource_Icons
    • RatingControl_UITests_Microsoft_UI_Xaml_Controls_RatingControlTests_RatingControlPage_UITests_Microsoft_UI_Xaml_Controls_RatingControlTests_RatingControlPage
    • Gesture_Recognizer_Pointer_Events_test_bench_UITests_Shared_Windows_UI_Input_GestureRecognizer_PointersEvents
    • CommandBarFlyout_MUXControlsTestApp_CommandBarFlyoutPage_MUXControlsTestApp_CommandBarFlyoutPage
    • Image_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Bigger_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Bigger
  • ios: 5 changed over 255

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • ProgressRing_Visibility_Collapsed_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • ImageStretch_None_Uno_UI_Samples_UITests_ImageTestsControl_Image_Stretch_None
    • ProgressRing_IsEnabled_Running_UITests_Windows_UI_Xaml_Controls_ProgressRing_WindowsProgressRing_GH1220
    • ListView_SelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • Validate_Offscreen_Shapes_UITests_Windows_UI_Xaml_Shapes_Offscreen_Shapes
  • ios-Snap: 52 changed over 994

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Brushes_ImageBrushStretch2_Uno_UI_Samples_UITests_ImageBrushTestControl_ImageBrushStretch2
    • ContentControl_ContentControl_SelectorInheritance_Uno_UI_Samples_Content_UITests_ContentControlTestsControl_ContentControl_SelectorInheritance
    • Default_UITests_Windows_UI_Xaml_Controls_Canvas_Grid_ZIndex_UITests_Windows_UI_Xaml_Controls_Canvas_Grid_ZIndex
    • Image_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Smaller_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Smaller
    • Image_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Taller_Uno_UI_Samples_UITests_Image_Image_Stretch_Alignment_Taller
    • Performance_UITests_Windows_UI_Xaml_Performance_Performance_1000ButtonsContinuousRendering_UITests_Windows_UI_Xaml_Performance_Performance_1000ButtonsContinuousRendering
    • WebView_UITests_Microsoft_UI_Xaml_Controls_WebView2Tests_WebView2_ExecuteScriptAsync_UITests_Microsoft_UI_Xaml_Controls_WebView2Tests_WebView2_ExecuteScriptAsync
    • WebView_UITests_Microsoft_UI_Xaml_Controls_WebViewTests_WebView_InvokeScriptAsync_UITests_Microsoft_UI_Xaml_Controls_WebViewTests_WebView_InvokeScriptAsync
    • SwipeControl_MUXControlsTestApp_SwipeControlPage2_MUXControlsTestApp_SwipeControlPage2
    • WebView_WebView2_JavascriptInvoke_SamplesApp_Microsoft_UI_Xaml_Controls_WebView2Tests_WebView2_JavascriptInvoke
    • TextBlock_Attributed_text_Simple_Uno_UI_Samples_Content_UITests_TextBlockControl_Attributed_text_Simple
    • WebView_WebView_ChromeClient_Uno_UI_Samples_Content_UITests_WebView_WebView_ChromeClient
    • WebView_WebView_JavascriptInvoke_Uno_UI_Samples_Content_UITests_WebView_WebView_JavascriptInvoke
    • Microsoft_UI_Xaml_Media_CompositionTarget_Rendering_UITests_Shared_Windows_UI_Xaml_Media_CompositionTargetTests_CompositionTarget_Rendering
    • NavigationView_MUXControlsTestApp_NavigationViewMenuItemStretchPage_MUXControlsTestApp_NavigationViewMenuItemStretchPage
    • Brushes_Uno_UI_Samples_UITests_ImageBrushTestControl_DoubleImageBrushInList_Uno_UI_Samples_UITests_ImageBrushTestControl_DoubleImageBrushInList
    • UIElement_TransformToVisual_Simple_UITests_Shared_Windows_UI_Xaml_UIElementTests_TransformToVisual_Simple
    • Brushes_RectangleStretchFill_Uno_UI_Samples_UITests_ImageBrushTestControl_RectangleStretchFill
    • Image_EmptyImageFixedWidth_Uno_UI_Samples_UITests_ImageTestsControl_EmptyImageFixedWidth
    • Image_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Vertical_UITests_Shared_Windows_UI_Xaml_Controls_ImageTests_Image_Stretch_Algmnt_Inf_Vertical
  • skia-linux-screenshots: 62 changed over 2306

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • ColorPickerSample.png-dark
    • ColorPickerSample.png
    • ListViewHeaderUpdate.png-dark
    • CompositionEffectBrush.png-dark
    • CompositionEffectBrush.png
    • Gamepad_Enumeration.png-dark
    • Gamepad_Enumeration.png
    • Focus_FocusVisual_Properties.png-dark
    • Focus_FocusVisual_Properties.png
    • ImageIconPage.png-dark
    • DisplayInformation.png-dark
    • Buttons.png-dark
    • DropDownButtonPage.png-dark
    • ImageBrushInList.png-dark
    • ImageBrushInList.png
    • ButtonClippingTestsControl.png-dark
    • ButtonClippingTestsControl.png
    • CalendarView_Theming.png-dark
    • CalendarView_Theming.png
    • Popup_Simple.png-dark
  • skia-windows-screenshots: 113 changed over 2306

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • BitmapIcon_Sizing.png
    • FileOpenPickerTests.png-dark
    • FileOpenPickerTests.png
    • FileOpenPicker_Bitmap.png-dark
    • FileOpenPicker_Bitmap.png
    • Buttons.png-dark
    • Buttons.png
    • DoubleImageBrushInList.png-dark
    • DoubleImageBrushInList.png
    • CompositionEffectBrush.png-dark
    • CompositionEffectBrush.png
    • Examples.png
    • Image_Stretch_None_ScrollViewer.png-dark
    • Image_Stretch_None_ScrollViewer.png
    • DropDownButtonPage.png-dark
    • ClipboardTests.png-dark
    • ClipboardTests.png
    • CalendarView_Theming.png-dark
    • CalendarView_Theming.png
    • Gamepad_CurrentReading.png-dark
  • wasm: 142 changed over 1058

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • UITests.Windows_UI_Xaml_Controls.ImageTests.SvgImageSource_FromMsAppData
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ComboBox.ComboBox_PlaceholderText
    • UITests.Shared.Windows_UI_Xaml_Controls.TextBoxControl.TextBox_Binding_Null
    • Uno.UI.Samples.Content.UITests.TextBlockControl.TextBlock_Nested_Measure_With_Outer_Alignments
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ListView.ListView_IsSelected
    • Uno.UI.Samples.Samples.Shared.Content.UITests.ImageBrushInList
    • SamplesApp.Windows_UI_Xaml_Controls.ToggleSwitchControl.Native_ToggleSwitch_IsOn
    • UITests.Microsoft_UI_Xaml_Controls.TeachingTipTests.TeachingTipBasicPage
    • Uno.UI.Samples.Content.UITests.TextBlockControl.SimpleText_MaxLines_Two_With_Wrap
    • UITests.Shared.Windows_UI_Xaml_Controls.Button.Button_Events
    • UITests.Shared.Windows_UI_Xaml_Controls.Button.RadioButton_Combined_Style
    • UITests.Shared.Windows_UI_Xaml_Controls.TextBoxTests.TextBox_BeforeTextChanging
    • UITests.Toolkit.ElevatedView_Tester
    • Uno.UI.Samples.Content.UITests.TextBlockControl.TextBlock_Run_Inheritance
    • SamplesApp.Windows_UI_Xaml_Controls.ListView.ListView_TextBox
    • Uno.UI.Samples.Content.UITests.CommandBar.CommandBar_With_Long_Sentences
    • Uno.UI.Samples.Content.UITests.GridTestsControl.Grid_Two_bottom_row_Auto__middle_col_auto
    • UITests.Windows_UI_Xaml_Controls.TextBox.WASM_Multiline
    • Uno.UI.Samples.Content.UITests.XBind.XBind_Simple
    • Uno.UI.Samples.Controls.SimpleText_MaxWidth_Wrap
  • wasm-automated-net10.0-WinUI-Benchmarks-automated: 0 changed over 1

  • wasm-automated-net10.0-WinUI-Default-automated: 14 changed over 877

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Default_StrokeThickness_MyLine
    • Default_StrokeThickness_MyPolygon
    • When_NoSelectionWithItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_MultipleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • When_SingleSelectionWithoutItemClick_Then_PointersEvents_UITests_Windows_UI_Xaml_Controls_ListView_ListView_Selection_Pointers
    • Default_StrokeThickness_MyPath
    • SequentialAnimations_SamplesApp_Windows_UI_Xaml_Media_Animation_SequentialAnimationsPage
    • Default_StrokeThickness_MyPolyline
    • ListView_SelectedItems_SamplesApp_Windows_UI_Xaml_Controls_ListView_ListViewSelectedItems
    • Default_StrokeThickness_MyRect
    • When_Theme_Changed_No_Crash_UITests_Windows_UI_Xaml_Controls_CalendarView_CalendarView_Theming
    • Default_StrokeThickness_MyEllipse
    • TestProgressRing_InitialState_UITests_Microsoft_UI_Xaml_Controls_ProgressRing_WinUIProgressRing_Features
    • When_TransformToVisual_ScrollViewer_UITests_Shared_Windows_UI_Xaml_UIElementTests_TransformToVisual_ScrollViewer
  • wasm-automated-net10.0-WinUI-RuntimeTests-0: 0 changed over 1

  • wasm-automated-net10.0-WinUI-RuntimeTests-1: 0 changed over 1

  • wasm-automated-net10.0-WinUI-RuntimeTests-2: 0 changed over 1

@jonpryor
jonpryor merged commit 15564e7 into master Dec 4, 2025
106 checks passed
@jonpryor
jonpryor deleted the dev/jonpryor/jonp-BindableType-DynamicallyAccessedMembers branch December 4, 2025 18:11
jonpryor added a commit to unoplatform/uno.toolkit.ui that referenced this pull request Dec 4, 2025
Context: unoplatform/uno#22017
Context: 1f09dd1

While running the uno.chefs app on macOS under NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop -bl \
	  Chefs/Chefs.csproj -p:SelfContained=true -p:PublishAot=true -p:IsAotCompatible=true -p:UseSkiaRendering=true \
	  -p:IlcGenerateMapFile=true -p:IlcGenerateMstatFile=true -p:IlcGenerateDgmlFile=true -p:IlcGenerateMetadataLog=true \
	  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
	Chefs/bin/Release/net10.0-desktop/osx-x64/publish/Chefs

Console output would contain the following errors:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Uno.Toolkit.UI:ProgressExtensions.IsActive] property getter does not exist on type [Microsoft.UI.Xaml.Controls.ContentControl]

The `Uno.Toolkit.UI:ProgressExtensions.IsActive` property is an
*attached* property, from `ProgressExtensions.IsActive`:

	static partial class ProgressExtensions {
	  public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
	      "IsActive",
	      typeof(bool),
	      typeof(ProgressExtensions),
	      new PropertyMetadata(false, IsActiveChanged));
	  public static bool GetIsActive(FrameworkElement element) => …;
	  public static void SetIsActive(FrameworkElement element, bool value) => …;
	}

Attached properties work by using Reflection to look for methods with
`Get` and `Set` prefixes before the property name, in this case
`GetIsActive()` and `SetIsActive()`.

NativeAOT cannot statically determine that `GetIsActive()` and
`SetIsActive()` are used, and thus doesn't emit any reflection metadata
for these members.  This can be verified by consulting the generated
`Chefs.metadata.csv` file, which only contains these entries for
`GetIsActive` and `SetIsActive`:

	3424256a, ConstantStringValue, "GetIsActive", ""

The [`[DynamicDependency]`][0] custom attribute can be used to inform
NativeAOT of this dependency, by listing the names of members which
should be preserved:

	static partial class ProgressExtensions {
	  [DynamicDependency(nameof(GetIsActive))]
	  [DynamicDependency(nameof(SetIsActive))]
	  public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
	      "IsActive",
	      typeof(bool),
	      typeof(ProgressExtensions),
	      new PropertyMetadata(false, IsActiveChanged));
	}

With this change in place, the originating failure message is no
longer emitted, and `Chefs.metadata.csv` contains:

	500b1f0b, Method, "System.Boolean GetIsActive(Microsoft.UI.Xaml.FrameworkElement)", "34141647 56141653 620c0acd"
	500b1f1a, Method, "System.Void SetIsActive(Microsoft.UI.Xaml.FrameworkElement, System.Boolean)", "3414165f 5614166b 620c0acd 6206708f"
	34141647, ConstantStringValue, "GetIsActive", ""
	3414165f, ConstantStringValue, "SetIsActive", ""
	4214168b, CustomAttribute, "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.[HasThis]  System.Void .ctor(System.String)(\"GetIsActive\")(ctor: Internal.Metadata.NativeFormat.Handle", "6c1c41df 34141647"
	42141695, CustomAttribute, "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.[HasThis]  System.Void .ctor(System.String)(\"SetIsActive\")(ctor: Internal.Metadata.NativeFormat.Handle", "6c1c41df 3414165f"

Review all usage of `DependencyProperty.RegisterAttached()` and add
`[DynamicDependency]` attributes as appropriate.

Of note:

  * Commit 1f09dd1 *commented out* many of the `[DynamicDependency]`
    annotations within `AutoLayout.Properties.cs`.  Some of these
    have already been undone, e.g. f16d514, and this commit uncomments
    the remaining `[DynamicDependency]` annotations.

  * There are now two separate patterns for providing
    `[DynamicDependency]`:

     1. Provide a `[DynamicDependency]` on the attached property for
        the `Get` method, and then `[DynamicDependency]` on the
        `Get` method (to the `Set` method), and a `[DynamicDependency]`
        on the `Set` method (to the `Get` method):

            partial class DeclType {
              [DynamicDependency(nameof(GetAttached))]
              public static readonly DependencyProperty AttachedProperty = DependencyProperty.RegisterAttached(
                "Attached"
                typeof(T),
                typeof(DeclType),
                new PropertyMetadata(…));

              [DynamicDependency(nameof(SetAttached))]
              public static T    GetAttached(DependencyObject element) => …
              [DynamicDependency(nameof(SetAttached))]
              public static void SetAttached(DependencyObject element, T value) => …
            }

     2. Provide `[DynamicDependency]` for *both* the `Get` and `Set`
        methods on the attached property:

            partial class DeclType {
              [DynamicDependency(nameof(GetAttached))]
              [DynamicDependency(nameof(SetAttached))]
              public static readonly DependencyProperty AttachedProperty = DependencyProperty.RegisterAttached(
                "Attached"
                typeof(T),
                typeof(DeclType),
                new PropertyMetadata(…));

              public static T    GetAttached(DependencyObject element) => …
              public static void SetAttached(DependencyObject element, T value) => …
            }

Both of these are fine, but @jonpryor personally finds the latter
easier to review.  At least one "typo" was found in the current review.

[0]: https://learn.microsoft.comdotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-10.0
jonpryor added a commit to unoplatform/uno.toolkit.ui that referenced this pull request Dec 5, 2025
Context: unoplatform/uno#22017
Context: 1f09dd1

While running the uno.chefs app on macOS under NativeAOT:

	dotnet publish -c Release -r osx-x64 -f net10.0-desktop -p:TargetFrameworkOverride=net10.0-desktop -bl \
	  Chefs/Chefs.csproj -p:SelfContained=true -p:PublishAot=true -p:IsAotCompatible=true -p:UseSkiaRendering=true \
	  -p:IlcGenerateMapFile=true -p:IlcGenerateMstatFile=true -p:IlcGenerateDgmlFile=true -p:IlcGenerateMetadataLog=true \
	  -p:EmitCompilerGeneratedFiles=true -p:CompilerGeneratedFilesOutputPath=`pwd`/_gen
	Chefs/bin/Release/net10.0-desktop/osx-x64/publish/Chefs

Console output would contain the following errors:

	fail: Uno.UI.DataBinding.BindingPropertyHelper[0]
	      The [Uno.Toolkit.UI:ProgressExtensions.IsActive] property getter does not exist on type [Microsoft.UI.Xaml.Controls.ContentControl]

The `Uno.Toolkit.UI:ProgressExtensions.IsActive` property is an
*attached* property, from `ProgressExtensions.IsActive`:

	static partial class ProgressExtensions {
	  public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
	      "IsActive",
	      typeof(bool),
	      typeof(ProgressExtensions),
	      new PropertyMetadata(false, IsActiveChanged));
	  public static bool GetIsActive(FrameworkElement element) => …;
	  public static void SetIsActive(FrameworkElement element, bool value) => …;
	}

Attached properties work by using Reflection to look for methods with
`Get` and `Set` prefixes before the property name, in this case
`GetIsActive()` and `SetIsActive()`.

NativeAOT cannot statically determine that `GetIsActive()` and
`SetIsActive()` are used, and thus doesn't emit any reflection metadata
for these members.  This can be verified by consulting the generated
`Chefs.metadata.csv` file, which only contains these entries for
`GetIsActive` and `SetIsActive`:

	3424256a, ConstantStringValue, "GetIsActive", ""

The [`[DynamicDependency]`][0] custom attribute can be used to inform
NativeAOT of this dependency, by listing the names of members which
should be preserved:

	static partial class ProgressExtensions {
	  [DynamicDependency(nameof(GetIsActive))]
	  [DynamicDependency(nameof(SetIsActive))]
	  public static readonly DependencyProperty IsActiveProperty = DependencyProperty.RegisterAttached(
	      "IsActive",
	      typeof(bool),
	      typeof(ProgressExtensions),
	      new PropertyMetadata(false, IsActiveChanged));
	}

With this change in place, the originating failure message is no
longer emitted, and `Chefs.metadata.csv` contains:

	500b1f0b, Method, "System.Boolean GetIsActive(Microsoft.UI.Xaml.FrameworkElement)", "34141647 56141653 620c0acd"
	500b1f1a, Method, "System.Void SetIsActive(Microsoft.UI.Xaml.FrameworkElement, System.Boolean)", "3414165f 5614166b 620c0acd 6206708f"
	34141647, ConstantStringValue, "GetIsActive", ""
	3414165f, ConstantStringValue, "SetIsActive", ""
	4214168b, CustomAttribute, "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.[HasThis]  System.Void .ctor(System.String)(\"GetIsActive\")(ctor: Internal.Metadata.NativeFormat.Handle", "6c1c41df 34141647"
	42141695, CustomAttribute, "System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.[HasThis]  System.Void .ctor(System.String)(\"SetIsActive\")(ctor: Internal.Metadata.NativeFormat.Handle", "6c1c41df 3414165f"

Review all usage of `DependencyProperty.RegisterAttached()` and add
`[DynamicDependency]` attributes as appropriate.

Of note:

  * Commit 1f09dd1 *commented out* many of the `[DynamicDependency]`
    annotations within `AutoLayout.Properties.cs`.  Some of these
    have already been undone, e.g. f16d514, and this commit uncomments
    the remaining `[DynamicDependency]` annotations.

  * There are now two separate patterns for providing
    `[DynamicDependency]`:

     1. Provide a `[DynamicDependency]` on the attached property for
        the `Get` method, and then `[DynamicDependency]` on the
        `Get` method (to the `Set` method), and a `[DynamicDependency]`
        on the `Set` method (to the `Get` method):

            partial class DeclType {
              [DynamicDependency(nameof(GetAttached))]
              public static readonly DependencyProperty AttachedProperty = DependencyProperty.RegisterAttached(
                "Attached"
                typeof(T),
                typeof(DeclType),
                new PropertyMetadata(…));

              [DynamicDependency(nameof(SetAttached))]
              public static T    GetAttached(DependencyObject element) => …
              [DynamicDependency(nameof(SetAttached))]
              public static void SetAttached(DependencyObject element, T value) => …
            }

     2. Provide `[DynamicDependency]` for *both* the `Get` and `Set`
        methods on the attached property:

            partial class DeclType {
              [DynamicDependency(nameof(GetAttached))]
              [DynamicDependency(nameof(SetAttached))]
              public static readonly DependencyProperty AttachedProperty = DependencyProperty.RegisterAttached(
                "Attached"
                typeof(T),
                typeof(DeclType),
                new PropertyMetadata(…));

              public static T    GetAttached(DependencyObject element) => …
              public static void SetAttached(DependencyObject element, T value) => …
            }

Both of these are fine, but @jonpryor personally finds the latter
easier to review.  At least one "typo" was found in the current review.

[0]: https://learn.microsoft.comdotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute?view=net-10.0
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators May 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area/code-generation Categorizes an issue or PR as relevant to code generation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants