--- name: implementing-wpf-adorners description: Implements WPF Adorner decoration layers with AdornerLayer, AdornerDecorator, and custom Adorner patterns. Use when building drag handles, validation indicators, watermarks, selection visuals, or resize grips. --- # WPF Adorner Patterns Adorner is a mechanism for overlaying decorative visual elements on top of UIElements. ## 1. Adorner Concept ### 1.1 Characteristics - **AdornerLayer**: Separate rendering layer that holds Adorners - **Z-Order**: Always renders above the adorned element - **Layout Independent**: No effect on target element's layout - **Event Support**: Can receive mouse/keyboard events ### 1.2 Usage Scenarios | Scenario | Description | |----------|-------------| | **Validation Display** | Input field error display | | **Drag Handles** | Element move/resize handles | | **Watermark** | Hint text for empty TextBox | | **Selection Display** | Highlight selected elements | | **Tooltip/Badge** | Additional info display on elements | | **Drag and Drop** | Preview during drag | --- ## 2. Basic Adorner Implementation ### 2.1 Simple Adorner ```csharp namespace MyApp.Adorners; using System.Windows; using System.Windows.Documents; using System.Windows.Media; /// /// Adorner that draws border around element /// public sealed class BorderAdorner : Adorner { private readonly Pen _borderPen; public BorderAdorner(UIElement adornedElement) : base(adornedElement) { _borderPen = new Pen(Brushes.Red, 2) { DashStyle = DashStyles.Dash }; _borderPen.Freeze(); // Disable mouse events (decoration only) IsHitTestVisible = false; } protected override void OnRender(DrawingContext drawingContext) { var rect = new Rect(AdornedElement.RenderSize); // Draw border drawingContext.DrawRectangle(null, _borderPen, rect); } } ``` ### 2.2 Applying Adorner ```csharp // Get AdornerLayer var adornerLayer = AdornerLayer.GetAdornerLayer(targetElement); if (adornerLayer is not null) { // Add Adorner var adorner = new BorderAdorner(targetElement); adornerLayer.Add(adorner); } ``` ### 2.3 Removing Adorner ```csharp // Remove all Adorners from specific element var adornerLayer = AdornerLayer.GetAdornerLayer(targetElement); var adorners = adornerLayer?.GetAdorners(targetElement); if (adorners is not null) { foreach (var adorner in adorners) { adornerLayer!.Remove(adorner); } } ``` --- ## 3. AdornerDecorator ### 3.1 Default Location ```xml ``` ### 3.2 Explicit AdornerDecorator ```xml