I have an adorner which should be placed beside it's adorned element. Depening on the value of the custom Position
dependency property the adorner appears at the left or right side of the element.
I want to use a style to set the value of the Position
property. But I can only do this if I add the style to the resources of the top-level control. If I place the style inside the resources of any child element it shows no effect.
Is there a way that I can set the adorner style on a per-element basis like in the following example?
<Window x:Class="StyledAdorner.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StyledAdorner">
<Window.Resources>
<Style TargetType="local:MyAdorner">
<Setter Property="Position" Value="Right" />
</Style>
<Style TargetType="Button">
<Setter Property="Content" Value="Adorn me!" />
<Setter Property="Margin" Value="15" />
<EventSetter Event="Click" Handler="AddAdorner" />
</Style>
</Window.Resources>
<StackPanel>
<Button />
<Button>
<Button.Resources>
<Style TargetType="local:MyAdorner">
<!-- This setter has no effect! -->
<Setter Property="Position" Value="Left" />
</Style>
</Button.Resources>
</Button>
</StackPanel>
</Window>
The only solution I can image is to scan the adorned element's resources for an adorner style. If there is one then check if there is a setter for the Position
property and use this value. But that looks like a really dirty hack...
- Code for
AddAdorner
handler that creates the adorner:
private void AddAdorner(object sender, RoutedEventArgs e)
{
new MyAdorner((UIElement)sender);
}
- Constructor for
MyAdorner
private Path _indicator = new Path { /* details omitted */ };
public MyAdorner(UIElement adornedElement) : base(adornedElement)
{
AdornerLayer.GetAdornerLayer(AdornedElement).Add(this);
AddVisualChild(_indicator);
InvalidateMeasure();
InvalidateArrange();
}
CodePudding user response:
I could solve my problem by turning the Position
property into an attached property:
public static readonly DependencyProperty PositionProperty = DependencyProperty.RegisterAttached(
"Position",
typeof(AdornerPosition),
typeof(MyAdorner),
new FrameworkPropertyMetadata(AdornerPosition.Right, UpdateAdornerLayerLayout));
Now, I just have to set the desired value on the adorned element:
<Button local:MyAdorner.Position="Left">
The property is evaluated in adorner`s ArrangeOverride
method when the position for the adorner is calculated.
Note that the UpdateAdornerLayerLayout
property changed callback is neccessary to force a layout update for the adorner layer when the property changes:
private static void UpdateAdornerLayerLayout(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UIElement element)
{
var layer = AdornerLayer.GetAdornerLayer(element);
layer?.Update();
}
}