using System.Windows; using System.Windows.Controls; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Shapes; using HandyControl.Data; namespace HandyControl.Controls; [TemplatePart(Name = ElementRoot, Type = typeof(Border))] [ContentProperty(nameof(Content))] public class Watermark : Control { private const string ElementRoot = "PART_Root"; private Border _borderRoot; private DrawingBrush _brush; public static readonly DependencyProperty AngleProperty = DependencyProperty.Register( nameof(Angle), typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender)); public double Angle { get => (double) GetValue(AngleProperty); set => SetValue(AngleProperty, value); } public static readonly DependencyProperty ContentProperty = DependencyProperty.Register( nameof(Content), typeof(object), typeof(Watermark), new PropertyMetadata(default)); public object Content { get => GetValue(ContentProperty); set => SetValue(ContentProperty, value); } public static readonly DependencyProperty MarkProperty = DependencyProperty.Register( nameof(Mark), typeof(object), typeof(Watermark), new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender)); public object Mark { get => GetValue(MarkProperty); set => SetValue(MarkProperty, value); } public static readonly DependencyProperty MarkWidthProperty = DependencyProperty.Register( nameof(MarkWidth), typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender)); public double MarkWidth { get => (double) GetValue(MarkWidthProperty); set => SetValue(MarkWidthProperty, value); } public static readonly DependencyProperty MarkHeightProperty = DependencyProperty.Register( nameof(MarkHeight), typeof(double), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.Double0Box, FrameworkPropertyMetadataOptions.AffectsRender)); public double MarkHeight { get => (double) GetValue(MarkHeightProperty); set => SetValue(MarkHeightProperty, value); } public static readonly DependencyProperty MarkBrushProperty = DependencyProperty.Register( nameof(MarkBrush), typeof(Brush), typeof(Watermark), new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender)); public Brush MarkBrush { get => (Brush) GetValue(MarkBrushProperty); set => SetValue(MarkBrushProperty, value); } public static readonly DependencyProperty AutoSizeEnabledProperty = DependencyProperty.Register( nameof(AutoSizeEnabled), typeof(bool), typeof(Watermark), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.AffectsRender)); public bool AutoSizeEnabled { get => (bool) GetValue(AutoSizeEnabledProperty); set => SetValue(AutoSizeEnabledProperty, ValueBoxes.BooleanBox(value)); } public static readonly DependencyProperty MarkMarginProperty = DependencyProperty.Register( nameof(MarkMargin), typeof(Thickness), typeof(Watermark), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.AffectsRender)); public Thickness MarkMargin { get => (Thickness) GetValue(MarkMarginProperty); set => SetValue(MarkMarginProperty, value); } public override void OnApplyTemplate() => _borderRoot = GetTemplateChild(ElementRoot) as Border; private void EnsureBrush() { var presenter = new ContentPresenter(); if (Mark is Geometry geometry) { presenter.Content = new Path { Width = MarkWidth, Height = MarkHeight, Fill = MarkBrush, Stretch = Stretch.Uniform, Data = geometry }; } else if (Mark is string str) { presenter.Content = new TextBlock { Text = str, FontSize = FontSize, Foreground = MarkBrush }; } else { presenter.Content = Mark; } Size markSize; if (AutoSizeEnabled) { presenter.Measure(new Size(double.MaxValue, double.MaxValue)); markSize = presenter.DesiredSize; } else { markSize = new Size(MarkWidth, MarkHeight); } _brush = new DrawingBrush { ViewportUnits = BrushMappingMode.Absolute, Stretch = Stretch.Uniform, TileMode = TileMode.Tile, Transform = new RotateTransform(Angle), Drawing = new GeometryDrawing { Brush = new VisualBrush(new Border { Background = Brushes.Transparent, Padding = MarkMargin, Child = presenter }), Geometry = new RectangleGeometry(new Rect(markSize)) }, Viewport = new Rect(markSize) }; RenderOptions.SetCacheInvalidationThresholdMinimum(_brush, 0.5); RenderOptions.SetCacheInvalidationThresholdMaximum(_brush, 2); RenderOptions.SetCachingHint(_brush, CachingHint.Cache); if (_borderRoot != null) { _borderRoot.Background = _brush; } } protected override void OnRender(DrawingContext drawingContext) => EnsureBrush(); }