SkillAgentSearch skills...

uno

Beautiful themed components for Uno Platform in C#

Install / Use

npx skills add tobitege/Flowery.Uno

Installs into whichever agent you are using.

About this skill
📐

Cursor Rules

Cursor IDE rules (v2)

Quality Score

64/100

Supported Platforms

Cursor

alwaysApply: true

Flowery.Uno MANDATORY Development Notes

This file captures learnings and patterns discovered during Flowery.Uno development for future reference.

🚨 READ THIS FIRST (top crash-prevention rules)

If you only read the first ~50 lines of this file, read this section. These rules prevent the most common Uno “mystery” runtime crashes:

  • ContentControls that rebuild Content: ALWAYS detach before re-parenting.
    • Pattern: _userContent = Content; Content = null; BuildVisualTree(); _presenter.Content = _userContent;
    • See “UIElement can only have one parent” (search for ### 19).
  • Never bind a ContentPresenter back to this.Content in a control that later sets Content = _rootGrid (creates self-parenting / re-parenting issues).
    • See the anti-pattern example under ### 19.
  • Don’t use PathIcon dynamically in code-behind (Uno can throw ArgumentException: Value does not fall within the expected range.).
    • Use Microsoft.UI.Xaml.Shapes.Path or Flowery.Helpers.FloweryPathHelpers instead (search for ### 18).
  • Use DaisyControlExtensions.Icon for button icons - This is the GOLD STANDARD (see section below).
  • Ambiguous type names: Path, Color, etc. often need aliasing/qualification.
    • Example: using Path = Microsoft.UI.Xaml.Shapes.Path; (search for ### 12).
  • Do NOT merge ms-appx:///uno.toolkit.*/Styles/Generic.xaml.
    • Uno.Toolkit.* packages do not ship Styles/Generic.xaml. Adding that dictionary will fail to load resources and can crash at startup. ShadowContainer only needs the package reference.

Neumorphic Takeaways

For the distilled, field-tested fixes and integration notes from recent stability work, see llms-static/neumorphic.mdField-Tested Integration Notes (Session Takeaways).

ThemeShadow + Elevation Learnings

  • ThemeShadow requires explicit receivers: add the receiver to ThemeShadow.Receivers (see Uno tests in !uno/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Media/ThemeShadowTests).
  • Translation.Z defines shadow depth: the casting element must have a Translation Z (e.g., 0,0,6).
  • CornerRadius is respected when ThemeShadow is applied directly to Border or Rectangle with radius properties (no custom masking required).
  • WASM/Skia elevation: for rounded shadows, apply SetElevation to the template’s Border (e.g., ButtonBorder), not the Button control itself.

Pitfalls (Session)

These are compile-time issues that should be avoided up front:

  • Do not use ?? with different operand types (e.g., Border ?? DaisyCard). Cast to a shared base like FrameworkElement first.
  • Do not assign UIElement to FrameworkElement without an explicit cast and a null/type check.
  • Do not reference non-existent WinUI/Uno members like FrameworkElement.IsVisibleChanged; use supported events or RegisterPropertyChangedCallback.
  • Do not access internal or private helpers (e.g., PlatformCompatibility) from outside their assembly.
  • Do not set null into non-nullable reference types; update the type or use a nullable value.
  • Do not use x:Bind paths that are not real properties on the page (e.g., Localization); ensure the property exists and follow the required localization binding pattern.

WASM/Browser (Skia) Heads-Up (Session)

These are the practical fixes and gotchas encountered when getting the Browser head running with Skia:

  • Use Microsoft.NET.Sdk.WebAssembly for the Browser head when using Uno.WinUI.Runtime.Skia.WebAssembly.Browser. Do NOT reference Uno.WinUI.Runtime.WebAssembly (triggers UNOB0017).
  • Target net9.0 with RuntimeIdentifier=browser-wasm and run via dotnet run on the project (not the output folder) to avoid hostpolicy.dll self-contained errors.
  • Use HostBuilder.UseWebAssembly() directly; avoid reflection-based host builder hacks (inaccessible method errors).
  • Fix culture crashes by disabling invariant globalization and including ICU data:
    • <InvariantGlobalization>false</InvariantGlobalization>
    • <WasmIncludeFullIcuData>true</WasmIncludeFullIcuData>
  • Keep SkiaSharp versions aligned across managed + native:
    • SkiaSharp and SkiaSharp.NativeAssets.WebAssembly MUST match (e.g., 3.119.1) or you will hit undefined symbol errors.
  • Static web assets duplicates (library layout + root assets) cause:
    • Two assets found targeting the same path with incompatible asset kinds
    • Fix by disabling root asset copies for net9.0 library projects and using ms-appx:///Flowery.Uno.Gallery/Assets/... paths.
    • Add a Browser-head build target that RemoveDuplicates on @(UnoAllCopyToOutputItems) before _UnoAssetsGetCopyToPublishDirectoryItems.
  • CSP warnings (workers, unsafe-eval) and WEBGL_invalid_enum messages are expected in debug and are not fatal.
  • Keep Browser script ports aligned (5236) to avoid mismatched logs vs URL.
  • ms-appx:/// is the correct scheme for Content assets in Uno (including WASM); it is supported by Image/BitmapImage.
  • Referencing assets in code can use ms-appx:///Assets/... or ms-appx:///AssemblyName/Assets/... and can be bound as a string.
  • Uno 4.7+ requires exact-case assembly names in ms-appx:///AssemblyName/... (case-sensitive).
  • Library assets require <GenerateLibraryLayout>true</GenerateLibraryLayout> in the library .csproj.
  • Library assets are referenced via ms-appx:///[LibraryName]/[AssetPath] and via StorageFile.GetFileFromApplicationUriAsync.
  • For non-WinAppSDK targets, library asset names should be lowercased in the ms-appx URI.
  • StorageFileHelper.ExistsInPackage("Assets/...") can be used to confirm asset presence at runtime.

Testing (Runtime Tests)

Problems, causes, and effective fixes

  • Windows runner COMExceptions / missing WinUI theme resources

    • Symptom: Cannot locate resource from 'ms-appx:///Microsoft.UI.Xaml/Themes/themeresources.xaml' and control construction COMExceptions.
    • Cause: Build command disabled PRI/resource generation and copy (AppxGeneratePriEnabled=false, IncludeCopyLocalFilesOutputGroup=false).
    • Fix: Keep EnableCoreMrtTooling=false, but remove those two properties in the Windows runner build args so WinUI resources load.
  • Flowery theme resources missing in runtime tests

    • Symptom: ms-appx:///Flowery.Uno/Themes/Generic.xaml not found; Daisy brushes missing.
    • Cause: Runtime test output only had Themes/ at app root, not Flowery.Uno/Themes/ (library layout path).
    • Fix: In Flowery.Uno.Gallery.Windows/App.xaml.cs, when isRuntimeTests:
      • Copy ThemesFlowery.Uno/Themes under AppContext.BaseDirectory.
      • Load ms-appx:///Flowery.Uno/Themes/Generic.xaml.
      • Still add XamlControlsResources (log if it fails).
      • Call EnsureGalleryResources(isRuntimeTests) before the runtime-test early return so resources exist during tests.
  • Runtime tests not picking up --runtime-tests args

    • Symptom: Test app runs but no results produced / hangs.
    • Cause: Args not reliably passed when running the Windows app via test host.
    • Fix: Add env var fallback: FLOWERY_RUNTIME_TESTS_PATH.
      • RuntimeTestArguments checks env var first.
      • Both Windows/Skia runners set FLOWERY_RUNTIME_TESTS_PATH.
  • Windows runner launching the wrong host

    • Symptom: Running dotnet <dll> bypassed Windows app packaging behavior.
    • Fix: Prefer the .exe (Path.ChangeExtension(TargetPath, ".exe")) when it exists.

Correct setup snapshot

  • Flowery.Uno.RuntimeTests targets: net9.0;net9.0-windows10.0.19041.
  • Windows runner build args: -p:EnableCoreMrtTooling=false (do not disable PRI or copy-local outputs).
  • Windows runner execution: run the app .exe when available; always set FLOWERY_RUNTIME_TESTS_PATH.
  • App.xaml.cs for Windows: load runtime-test resources before the early return; copy Themes into Flowery.Uno/Themes for ms-appx resolution.

✅ CI / GitHub Actions (Uno + gh CLI)

Uno templates (CI generation)

Uno project templates can generate CI pipelines:

dotnet new unoapp -ci github
dotnet new unoapp -ci azure
dotnet new unoapp -ci none

GitHub CLI (workflow operations)

# List workflows
gh workflow list

# Trigger a workflow (requires on: workflow_dispatch)
gh workflow run .github/workflows/ci.yml

# Watch a run
gh run watch <run-id>

# View run details / logs
gh run view <run-id> --log-failed

⭐ GOLD STANDARD: Button Icons via Attached Property

This is the official Uno.Themes pattern for adding icons to buttons. It avoids all UIElement parentage issues.

Why This Pattern?

  • UIElements can only have ONE parent. Passing PathIcon as Content often causes silent failures.
  • Attached properties allow the button to build its own icon presenter, avoiding parentage issues.
  • Supports icon + text on the same button (not mutually exclusive).
  • Foreground inheritance is handled correctly for different button variants/states.

Using DaisyControlExtensions.Icon (Recommended)

<!-- Icon-only button -->
<daisy:DaisyButton Shape="Circle" Variant="Primary">
    <daisy:DaisyControlExtensions.Icon>
        <PathIcon Width="16" Height="16" Data="M12 4.5v15m7.5-7.5h-15" />
    </daisy:DaisyControlExtensions.Icon>
</daisy:DaisyButton>

<!-- Icon + text button -->
<daisy:DaisyButton Content="Save" Variant="Primary">
    <daisy:DaisyControlExtensions.Icon>
        <PathIcon Width="16" Height="16" Data="M..." />
    </daisy:DaisyControlExtensions.Icon>
</daisy:DaisyButton>

<!-- Icon on the right side -->
<daisy:DaisyButton Content="Next">
    <daisy:DaisyControlExtensions.Icon>
        <PathIcon Data="M..." />
    </daisy:DaisyControlExtensions.Icon>
    <daisy:DaisyControlExtensions.IconPlacement>Right</daisy:DaisyControlExtensions.IconPlacement>
</daisy:DaisyButton>

Using TriggerIconData for DaisyFab (Best Practice)

For the FAB trigger button, use TriggerIconData (a string containing the path data). This is the safest approach because we create the PathIcon internally, completely avoiding UIElement parentage issues.

<daisy:DaisyFab TriggerVariant="Secondary" Size="Medium"
                TriggerIconData="M12 4.5v15m7.5-7.5h-15"
                TriggerIconSize="16">
    <StackPanel>
        <daisy:DaisyButton Shape="Circle">
            <PathIcon Width="16" Height="16" Data="M3 9.5l9-7 9 7V20..." />
        </daisy:DaisyButton>
    </StackPanel>
</daisy:DaisyFab>

Available Attached Properties

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | DaisyControlExtensions.Icon | IconElement | null | The icon to display | | DaisyControlExtensions.IconWidth | double | NaN | Explicit icon width (auto if NaN) | | DaisyControlExtensions.IconHeight | double | NaN | Explicit icon height (auto if NaN) | | DaisyControlExtensions.IconPlacement | IconPlacement | Left | Position: Left, Right, Top, Bottom | | DaisyControlExtensions.IconSpacing | double | 8.0 | Spacing between icon and content | | DaisyControlExtensions.AlternateContent | object | null | For toggle controls: content when checked |

Note: These properties use [Bindable] and [DynamicDependency] attributes for proper XAML binding and AOT compilation safety, following the Uno.Themes pattern.

❌ DON'T: Set PathIcon as Direct Content

<!-- ❌ FAILS SILENTLY: PathIcon becomes child of DaisyButton,
     then can't be re-parented to internal presenter -->
<daisy:DaisyButton Shape="Circle" Variant="Primary">
    <PathIcon Data="M..." />
</daisy:DaisyButton>

✅ DO: Use the Attached Property Pattern

<!-- ✅ WORKS: Icon is picked up by button and placed in its own presenter -->
<daisy:DaisyButton Shape="Circle" Variant="Primary">
    <daisy:DaisyControlExtensions.Icon>
        <PathIcon Data="M..." />
 

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars0
CategoryEducation
Updated2mo ago
Forks0

Security Score

80/100

Audited on Jul 9, 2026

1 medium1 low