8000 BrowserHtmlElement not displayed when set as ContentControl.Content (WASM Skia) · Issue #22461 · unoplatform/uno · GitHub
[go: up one dir, main page]

Skip to content

BrowserHtmlElement not displayed when set as ContentControl.Content (WASM Skia) #22461

@KKirchhoff

Description

@KKirchhoff

Current behavior

When using BrowserHtmlElement as Content of a ContentControl (or derived class) on WASM with Skia renderer, the native HTML element is not displayed. The element remains in the hidden uno-native-element-store div and is never moved to the visible uno-native-element-host.

Expected behavior

The BrowserHtmlElement should be automatically attached to the native element host and displayed correctly, similar to how it works described in the documentation.

How to reproduce?

  1. Create a ContentControl (or derived class like custom control)
  2. Create a BrowserHtmlElement and set it as Content
  3. The element is created but not visible
public partial class MyControl : ContentControl
{
    public void SetupNativeElement()
    {
        var htmlElement = BrowserHtmlElement.CreateHtmlElement("div");
        this.Content = htmlElement;
        
        // Element is now in uno-native-element-store (hidden)
        // but never moved to uno-native-element-host (visible)
    }
}

Root Cause Analysis

After investigating the Uno source code, I found the following issues:

1. ContentPresenter.skia.cs - TryRegisterNativeElement

In ContentPresenter.skia.cs, the TryRegisterNativeElement method checks IsInLiveTree before calling AttachNativeElement():

if (IsInLiveTree)
{
    //If in visual tree, attach immediately. If not, don't attach since Enter will attach later.
    AttachNativeElement();
}

The comment says "Enter will attach later", but this doesn't happen reliably when using ContentControl.

2. Missing AttachNativeElement call

The AttachNativeElement() is supposed to be called either:

  • Immediately if IsInLiveTree is true when content is set
  • Later in EnterImpl when IsNativeHost is true

However, when setting Content on a ContentControl, the content flows to the internal ContentPresenter via template binding. The timing seems to cause IsNativeHost to not be set correctly by the time EnterImpl runs.

3. DOM State

Looking at the browser DOM:

  • Element is created in uno-native-element-store (has display: none)
  • uno-native-element-host is never created (created lazily on first attach)
  • The JavaScript attachNativeElement() function that moves elements from store to host is never called

Workaround

The following workaround manually calls the JavaScript functions:

private void AttachNativeElementManually()
{
    var position = this.TransformToVisual(null).TransformPoint(new Point(0, 0));
    var x = position.X.ToString(CultureInfo.InvariantCulture);
    var y = position.Y.ToString(CultureInfo.InvariantCulture);
    var width = ActualWidth.ToString(CultureInfo.InvariantCulture);
    var height = ActualHeight.ToString(CultureInfo.InvariantCulture);

    var javascript = $@"
        var elementId = element.id;
        var api = globalThis.Uno.UI.NativeElementHosting.BrowserHtmlElement;
        
        // 1. Attach element to host
        api.attachNativeElement(elementId);
        
        // 2. Position the element
        api.arrangeNativeElement(elementId, {x}, {y}, {width}, {height});
        
        // 3. Set clip-path for this area
        var path = 'M {x} {y} L ' + ({x}+{width}) + ' {y} L ' + ({x}+{width}) + ' ' + ({y}+{height}) + ' L {x} ' + ({y}+{height}) + ' Z';
        api.setSvgClipPathForNativeElementHost(path, 'nonzero');
    ";
    _htmlElement.ExecuteJavascript(javascript);
}

Environment

  • Uno.Sdk: 5.5 / 5.6 (tested with both)
  • .NET: 9.0 / 10.0
  • Platform: WebAssembly with Skia renderer
  • Browser: Chrome, Safari (all browsers affected)

Additional Context

This issue specifically affects WASM with Skia renderer. The ContentPresenter.wasm.cs (for native WASM renderer) has different, simpler logic that might work correctly, but ContentPresenter.skia.cs (used for Skia-based WASM) has the timing issue.

The native element hosting extension (BrowserNativeElementHostingExtension) and JavaScript interop (Uno.Runtime.Wasm.js) work correctly when called directly - the issue is that ContentPresenter doesn't call them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0