-
Couldn't load subscription status.
- Fork 772
Description
Proposal: UIElement/FrameworkElement should expose protected method to add/initialize VisualTree
Follow-up from discussion on docs repo here: MicrosoftDocs/winrt-api#646
Summary
Currently, especially in C#, it's not possible to inherit directly from FrameworkElement for a low-level component. Even in WinUI 2 with C++ here, while they look like they're inheriting from FrameworkElement, they're really using Panel (see DeriveFromPanelHelper_base) as an intermediary even if only a single child is expected.
The ability to initialize a Child or Children property into the Visual Tree that's being created on a subclass of FrameworkElement is not exposed even as a protected member within the framework. This means that while you can write code that inherits directly from FrameworkElement, there's no way to get it to render as it can't be added to the VisualTree itself.
Rationale
In the Windows Community Toolkit, we wanted to add a low-level component akin to Viewbox for constraining to a specific aspect ratio. It made sense to make it a single-child control from FrameworkElement, but we can't do that directly as we can't add the Child property we create to the Visual Tree. See CommunityToolkit/WindowsCommunityToolkit#4104.
Instead we need to inherit from Panel if we want something simple, but then that allows for multiple children to be added (which is odd for this scenario) OR we need to inherit from ContentPresenter which does more than we need it to do with templating support.
- Would allow library developers to also develop lower-level components without the overhead of the high-level abstractions.
Scope
| Capability | Priority |
|---|---|
| This proposal will allow developers to accomplish initialize and render a low-level UI component | Must |
| This proposal will allow end users to accomplish react to remove and replace content when a developer changes the content of the sub-classed control | Must |
| This proposal will allow developers to create an element which accepts multiple children | Could |
API Proposal
Example of what a proposed API could look like with a protected AddChild and RemoveChild method for UIElement:
public MyClass : FrameworkElement
{
propdp UIElement Child; // Shorthand
private static void ChildPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is FrameworkElement element && e.OldValue != e.NewValue)
{
element.RemoveChild(e.OldValue); // new protected method
if (e.NewValue != null)
{
element.AddChild(e.NewValue); // new protected method
}
}
}
}Open Questions
- I think it makes sense by default that a
FrameworkElementwould have a single child as a root for folks to subclass from. Otherwise if they accept multiple-children, it feels like they'd be aPanelbased implementation at that point? I don't know the implementation details ofPanelso not sure where it makes sense to optimize for the single vs. multi-children support in the stack. - I noticed some controls like
ParallaxViewexposeChildas a Dependency Property, but others likeBorderdo not. Is there a reason? Is it required to be a DP to support removing/adding dynamically to the content of the control? - There's also the
ChildTransitionsproperty on manyFrameworkElementsubclasses, there'd probably at least need to be documentation on how to add that into this scenario as well. - WPF had the
Decoratorsubclass as a mirror toPanelbut that took a single child. Does it make sense to provide that as a new base forBorder/Viewboxlike it was in WPF and keep more of the abstraction, but provide a lighter-weight model to build off-of. - Should
ViewboxbeViewBox??? 😋