Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

Several FocusAdornerTemplate issues

Open billhenn opened this issue 1 year ago • 3 comments

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: image

❌ 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: image

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: image

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: image

I hope this explains everything in enough detail. Please contact me if you have any questions.

billhenn avatar May 04 '23 12:05 billhenn

Should be related to https://github.com/AvaloniaUI/Avalonia/issues/10700 and https://github.com/AvaloniaUI/Avalonia/issues/10701

rabbitism avatar May 04 '23 12:05 rabbitism

I should also have mentioned, this was all tested in 11.0.0-preview7.

billhenn avatar May 04 '23 14:05 billhenn

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

maxkatz6 avatar May 04 '23 21:05 maxkatz6