Avalonia
Avalonia copied to clipboard
Several FocusAdornerTemplate issues
We are theming controls and are trying to build focus adorners that appear right outside the bounds of the control. This is possible in WPF, but not in Avalonia at the moment due to a couple bugs. Also, for proper accessibility, there is a need for controls in the FocusAdornerTemplate
to be able to bind to properties like CornerRadius
, etc. on the adorned control, but that currently is not possible.
WPF Capabilities
✅ Showing Focus Adorners Outside the Bounds of the Control
WPF allows you to make a FocusVisualStyle
that has the focus adorner outside of the control's bounds without any trouble. That works like this:
<Button HorizontalAlignment="Left" Margin="20" Content="Focus Test Button" FontSize="16" Padding="10,6">
<Button.FocusVisualStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border Margin="-3" BorderThickness="2" BorderBrush="Red" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.FocusVisualStyle>
</Button>
And that renders this:
❌ Cannot Bind to Properties on the Adorned Control
The problem that has always existed in WPF is that it has no way to bind to any properties on the focused control, which makes it near impossible to have the focus adorner match the shape of the control. For instance, if we have a custom Button
control with a CornerRadius
on it, we may want the focus adorner to have the corner radius as well. Otherwise we are always stuck with rectangles unless we hardcode a corner radius into the FocusVisualStyle
. But since we are control developers, we can't do that because our developer customers can change properties on Button
like CornerRadius
at any time.
Avalonia Problems
❌ Problem 1 - Focus Adorner is Clipped to Control
The first Avalonia issue is that any elements in the FocusAdornerTemplate
that render outside the bounds of the control are clipped. In the code below. we see no focus adorner at all since it's completely clipped.
<Button HorizontalAlignment="Left" Content="Problem #1: Focus Adorner Clipped" FontSize="16" Padding="10,6" CornerRadius="5">
<Button.FocusAdorner>
<FocusAdornerTemplate>
<Border Margin="-3" BorderThickness="2" BorderBrush="Red" />
</FocusAdornerTemplate>
</Button.FocusAdorner>
</Button>
Here's the focused button:
It should be showing a red border around it, but it's totally clipped by the control, which is wrong.
Turning off ClipToBounds
gets part of the focus adorner to show, but we'll see in the next problem that there is an issue with negative margins rendering correctly. Also, setting ClipToBounds="False"
should NOT be necessary to get a focus adorner to render outside the bounds of the control.
❌ Problem 2 - Negative Margin Rendering Issue
The second issue is with negative margins rendering correctly in a FocusAdornerTemplate
. Here's the same code as before but with ClipToBounds="False"
:
<Button HorizontalAlignment="Left" Content="Problem #2: Negative Margin Issue" FontSize="16" Padding="10,6" CornerRadius="5" ClipToBounds="False">
<Button.FocusAdorner>
<FocusAdornerTemplate>
<Border Margin="-3" BorderThickness="2" BorderBrush="Red" />
</FocusAdornerTemplate>
</Button.FocusAdorner>
</Button>
Here's the focused button now:
You can see that only the top/left sides render. It seems that maybe the control's clip is being retained in the focus adorner but it's offset by the negative margin?
❌ Problem 3 - No Way to Bind to Control
The final issue is not being able to bind to the adorned control from within the FocusAdornerTemplate
. Reasons why we need this are explained in the WPF section above, as it never had support for that either and has always been a major accessibility drawback.
The focus adorner should always be able to match the shape of the adorned control and should not have to be hardcoded. But since we are control developers and our customers can change properties on the controls being themed, we need bindings to work so our focus adorner can alter its appearance as necessary.
We tried code like this to bind CornerRadius
to the adorned control but RelativeSource TemplatedParent
doesn't work:
<Button HorizontalAlignment="Left" Margin="10,0,10,10" Content="Problem #3: No Way to Bind to Control" FontSize="16" Padding="10,6" CornerRadius="5" ClipToBounds="False">
<Button.FocusAdorner>
<FocusAdornerTemplate>
<Border Margin="-3" BorderThickness="2" BorderBrush="Red"
CornerRadius="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=CornerRadius}" />
</FocusAdornerTemplate>
</Button.FocusAdorner>
</Button>
💡Proposed Solution for Binding Issue
My proposal to resolve this issue and finally solve this longstanding problem with WPF is to add a new RelativeSource
option named AdornedElement
. It could be used in adorner scenarios like this where it would effectively grant you access to the element being adorned, in our case above, a Button
.
The syntax for the binding would be:
CornerRadius="{Binding RelativeSource={RelativeSource AdornedElement}, Path=CornerRadius}"
That would hopefully be a quick, easy add to the API and would solve this problem.
⭐ Summary
If these three problems were fixed, we should be able to have this code:
<Button HorizontalAlignment="Left" Margin="10,0,10,10" Content="Ideal Scenario" FontSize="16" Padding="10,6" CornerRadius="5" ClipToBounds="False">
<Button.FocusAdorner>
<FocusAdornerTemplate>
<Border Margin="-3" BorderThickness="2" BorderBrush="Red"
CornerRadius="{Binding RelativeSource={RelativeSource AdornedElement}, Path=CornerRadius}" />
</FocusAdornerTemplate>
</Button.FocusAdorner>
</Button>
And have it render a focused button like this:
I hope this explains everything in enough detail. Please contact me if you have any questions.
Should be related to https://github.com/AvaloniaUI/Avalonia/issues/10700 and https://github.com/AvaloniaUI/Avalonia/issues/10701
I should also have mentioned, this was all tested in 11.0.0-preview7
.
Problem 1 - Focus Adorner is Clipped to Control Problem 2 - Negative Margin Rendering Issue
Seems to be the same problem introduced with new renderer, yes, https://github.com/AvaloniaUI/Avalonia/issues/10701