Skip to content

ElementName bindings don't resolve for programmatically-added named elements #22987

@MartinZikmund

Description

@MartinZikmund

Current behavior

When a {Binding ElementName=X} is defined in a XAML template and the element named X is created programmatically and added to the visual tree after the template is applied, the binding silently fails. The SourceElement (or whatever target property) remains null.

This is because ApplyElementNameBindings() runs at element load time via BindingHelper.ApplyBindingsOnLoad. At that point, NameScope.FindInNamescopes walks the ancestor chain looking for the name, but the named element doesn't exist yet.

WinUI handles this through deferred name resolution in its binding infrastructure — bindings to not-yet-available element names are resolved when the named element later enters the name scope.

Steps to reproduce

  1. Create a control template containing {Binding ElementName=MyElement} targeting some property
  2. In the control's OnApplyTemplate, programmatically create a FrameworkElement, set its Name = "MyElement", and add it to the template's visual tree
  3. The binding never resolves

Expected behavior

The binding should resolve once the named element is added to the visual tree and registered in the name scope, matching WinUI behavior.

Affected scenarios

  • DatePickerFlyoutPresenter: creates DayLoopingSelector, MonthLoopingSelector, YearLoopingSelector programmatically in OnApplyTemplate. The MonochromaticOverlayPresenter elements in the Fluent v2 theme bind to these via ElementName, but the bindings fail. A workaround manually registers names in the NameScope and re-applies bindings.

Root cause

In Uno, setting FrameworkElement.Name does not register the element in any NameScope. The OnNameChanged callback only sets AutomationProperties.AutomationId. There is no mechanism to:

  1. Register a programmatically-set name in the nearest ancestor NameScope
  2. Re-evaluate pending ElementName bindings when new names are registered

Workaround

Manually find the NameScope, register the name, and call ApplyElementNameBindings() on the consuming elements:

// Find the NameScope
INameScope nameScope = null;
DependencyObject current = someTemplateChild;
while (current is not null)
{
    nameScope = NameScope.GetNameScope(current);
    if (nameScope is not null) break;
    current = (current as FrameworkElement)?.Parent as DependencyObject;
}

// Register the dynamically-created element
nameScope?.RegisterName("MyElement", myElement);

// Re-apply bindings on consumers
if (consumer is IDependencyObjectStoreProvider provider)
{
    provider.Store.ApplyElementNameBindings();
}

Environment

  • Uno Platform (all targets)
  • Affects any {Binding ElementName=...} where the named element is added programmatically after template application

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions